diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..92eae39 --- /dev/null +++ b/.clang-format @@ -0,0 +1,22 @@ +--- +Language: Cpp +BasedOnStyle: Google +IndentWidth: 4 +ColumnLimit: 120 +AlignAfterOpenBracket: AlwaysBreak +AllowShortBlocksOnASingleLine: Never +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AllowShortLambdasOnASingleLine: None +BinPackArguments: false +BinPackParameters: false + +IncludeCategories: + - Regex: '^<.*>$' + Priority: 1 + - Regex: '^"gtest/.*"$' + Priority: 2 + - Regex: '^".*"$' + Priority: 3 +... diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..13ce862 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,177 @@ +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: ci +on: + push: + branches: + - main + tags: + - v* + pull_request: + branches: + - main +jobs: + build_dist: + runs-on: ${{ matrix.os_dist.os }} + strategy: + fail-fast: false + matrix: + os_dist: [ + {os: ubuntu-latest, dist: cp310-manylinux_x86_64}, + {os: ubuntu-latest, dist: cp311-manylinux_x86_64}, + {os: ubuntu-latest, dist: cp312-manylinux_x86_64}, + + {os: macos-latest, dist: cp310-macosx_x86_64, macosarch: x86_64}, + {os: macos-latest, dist: cp311-macosx_x86_64, macosarch: x86_64}, + {os: macos-latest, dist: cp312-macosx_x86_64, macosarch: x86_64}, + + {os: macos-latest, dist: cp310-macosx_arm64, macosarch: arm64}, + {os: macos-latest, dist: cp311-macosx_arm64, macosarch: arm64}, + {os: macos-latest, dist: cp312-macosx_arm64, macosarch: arm64}, + + # Currently disabled because in CI it gives "DLL load failed" errors I don't understand when testing the wheel. + # {os: windows-latest, dist: cp310-win_amd64}, + # {os: windows-latest, dist: cp311-win_amd64}, + # {os: windows-latest, dist: cp312-win_amd64}, + ] + env: + MACOSX_DEPLOYMENT_TARGET: "10.15" + CIBW_BUILD: "${{ matrix.os_dist.dist }}" + CIBW_ARCHS_MACOS: "${{ matrix.os_dist.macosarch }}" + CIBW_TEST_REQUIRES: pytest stim sinter pygltflib + CIBW_TEST_COMMAND: pytest {project}/src + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - run: python tools/overwrite_dev_versions_with_date.py + - run: mkdir -p output/stim + - run: mkdir -p output/stimcirq + - run: mkdir -p output/sinter + - run: python -m pip install pybind11~=2.11.1 cibuildwheel~=2.16.2 setuptools + - run: python -m cibuildwheel --print-build-identifiers + - run: python -m cibuildwheel --output-dir output/chromobius + - run: python setup.py sdist + - run: mv dist/* output/chromobius + - uses: actions/upload-artifact@v3 + with: + name: dist + path: | + ./output/chromobius/* + check_sdist_installs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - run: python -m pip install pybind11~=2.11.1 cibuildwheel~=2.16.2 setuptools + - run: python setup.py sdist + - run: pip install dist/*.tar.gz + run_main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: cmake . + - run: make chromobius -j 2 + - run: out/chromobius --help + build_bazel: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: bazelbuild/setup-bazelisk@v1 + - run: bazel build :all + - run: bazel test :chromobius_test + build_clang: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v1 + - run: | + cd .. + git clone https://github.com/google/googletest.git -b release-1.12.1 + mkdir googletest/build && cd googletest/build + cmake .. -DBUILD_GMOCK=OFF + make + sudo make install + - uses: egor-tensin/setup-clang@v1 + with: + version: latest + platform: x64 + - run: cmake . -DCMAKE_C_COMPILER=cc -DCMAKE_CXX_COMPILER=c++ + - run: cmake --build . --target chromobius chromobius_test chromobius_perf + - run: out/chromobius --help + perf: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: cmake . + - run: make chromobius_perf -j 2 + - run: out/chromobius_perf + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: | + cd .. + git clone https://github.com/google/googletest.git -b release-1.12.1 + mkdir googletest/build && cd googletest/build + cmake .. -DBUILD_GMOCK=OFF + make + sudo make install + - run: cmake . + - run: make chromobius_test -j 2 + - run: out/chromobius_test + test_o3: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: | + cd .. + git clone https://github.com/google/googletest.git -b release-1.12.1 + mkdir googletest/build && cd googletest/build + cmake .. -DBUILD_GMOCK=OFF + make + sudo make install + - run: cmake . -DSIMD_WIDTH=256 + - run: make chromobius_test_o3 -j 2 + - run: out/chromobius_test_o3 + test_generated_docs_are_fresh: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - uses: bazelbuild/setup-bazelisk@v1 + - run: bazel build :chromobius_dev_wheel + - run: pip install bazel-bin/chromobius-0.0.dev0-py3-none-any.whl + - run: diff <(python tools/gen_chromobius_api_reference.py -dev) doc/chromobius_api_reference.md + - run: diff <(python tools/gen_chromobius_stub_file.py -dev) doc/chromobius.pyi + - run: python doc/chromobius.pyi + test_generated_file_lists_are_fresh: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: tools/regen_file_lists.sh /tmp + - run: diff /tmp/perf_files file_lists/perf_files + - run: diff /tmp/pybind_files file_lists/pybind_files + - run: diff /tmp/source_files_no_main file_lists/source_files_no_main + - run: diff /tmp/test_files file_lists/test_files + test_pybind: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - uses: bazelbuild/setup-bazelisk@v1 + - run: bazel build :chromobius_dev_wheel + - run: pip install bazel-bin/chromobius-0.0.dev0-py3-none-any.whl + - run: pip install pytest stim sinter pygltflib + - run: pytest src + - run: tools/doctest_proper.py --module chromobius diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e4cbbc --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +.idea +.pytest_cache +out +__pycache__ +cmake-build-debug +.cmake +CMakeFiles +CMakeCache.txt +.ninja_deps +.ninja_log +Testing +_deps +build.ninja +cmake_install.cmake +perf.data +perf.data.old +lib +bazel-bin +bazel-out +bazel-testlogs +bazel-* +python_build_chromobius +chromobius.egg-info +.clwb +wheelhouse +build +package_data +.eggs +dist +MODULE.bazel +MODULE.bazel.lock diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..55db422 --- /dev/null +++ b/BUILD @@ -0,0 +1,127 @@ +package(default_visibility = ["//visibility:public"]) + +load("@rules_python//python:packaging.bzl", "py_wheel") + +SOURCE_FILES_NO_MAIN = glob( + [ + "src/**/*.cc", + "src/**/*.h", + "src/**/*.inl", + ], + exclude = glob([ + "src/**/*.test.cc", + "src/**/*.test.h", + "src/**/*.perf.cc", + "src/**/*.perf.h", + "src/**/*.pybind.cc", + "src/**/*.pybind.h", + "src/**/main.cc", + ]), +) + +TEST_FILES = glob( + [ + "src/**/*.test.cc", + "src/**/*.test.h", + ], +) + +PERF_FILES = glob( + [ + "src/**/*.perf.cc", + "src/**/*.perf.h", + ], +) + +PYBIND_FILES = glob( + [ + "src/**/*.pybind.cc", + "src/**/*.pybind.h", + ], +) + +cc_binary( + name = "chromobius", + srcs = SOURCE_FILES_NO_MAIN + glob(["src/**/main.cc"]), + copts = [ + "-std=c++20", + "-O3", + "-DNDEBUG", + ], + includes = ["src/"], + deps = [ + "@pymatching//:libpymatching", + "@stim//:stim_lib", + ], +) + +cc_binary( + name = "chromobius_perf", + srcs = SOURCE_FILES_NO_MAIN + PERF_FILES, + copts = [ + "-O3", + "-std=c++20", + "-DNDEBUG", + ], + data = glob(["test_data/**"]), + includes = ["src/"], + deps = [ + "@pymatching//:libpymatching", + "@stim//:stim_lib", + ], +) + +cc_test( + name = "chromobius_test", + srcs = SOURCE_FILES_NO_MAIN + TEST_FILES, + copts = [ + "-std=c++20", + ], + data = glob(["test_data/**"]), + includes = ["src/"], + deps = [ + "@gtest", + "@gtest//:gtest_main", + "@pymatching//:libpymatching", + "@stim//:stim_lib", + ], +) + +cc_binary( + name = "chromobius.so", + srcs = SOURCE_FILES_NO_MAIN + PYBIND_FILES, + copts = [ + "-O3", + "-std=c++20", + "-fvisibility=hidden", + "-DNDEBUG", + ], + includes = ["src/"], + linkshared = 1, + deps = [ + "@pybind11", + "@pymatching//:libpymatching", + "@stim//:stim_lib", + ], +) + +genrule( + name = "chromobius_wheel_files", + srcs = ["doc/chromobius.pyi"], + outs = ["chromobius.pyi"], + cmd = "cp $(location doc/chromobius.pyi) $@", +) + +py_wheel( + name = "chromobius_dev_wheel", + distribution = "chromobius", + requires = [ + "numpy", + "stim", + ], + version = "0.0.dev0", + deps = [ + ":chromobius.so", + ":chromobius_wheel_files", + ], +) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d31e9a4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,111 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.13) +project(chromobius) +include_directories(src) +set(CMAKE_CXX_STANDARD 20) +if (NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY out) +endif() +if (NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY out) +endif() +if (NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY out) +endif() +if (NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET) + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15) +endif() + +# Make changes to file_lists trigger a reconfigure. +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS file_lists/source_files_no_main) +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS file_lists/test_files) +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS file_lists/perf_files) +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS file_lists/pybind_files) +file(STRINGS file_lists/source_files_no_main SOURCE_FILES_NO_MAIN) +file(STRINGS file_lists/test_files TEST_FILES) +file(STRINGS file_lists/perf_files PERF_FILES) +file(STRINGS file_lists/pybind_files PYBIND_FILES) + +set(SIMD_WIDTH 128) +include(FetchContent) +FetchContent_Declare(stim + GIT_REPOSITORY https://github.com/quantumlib/stim.git + GIT_TAG 3e38d12d0a0fb3022646b694137b733a4700d300) +FetchContent_GetProperties(stim) +if(NOT stim_POPULATED) + FetchContent_Populate(stim) + add_subdirectory(${stim_SOURCE_DIR}) +endif() + +FetchContent_Declare(pymatching + GIT_REPOSITORY https://github.com/oscarhiggott/pymatching.git + GIT_TAG 40dcf8c01273ff7e23a7105d5cdc410ada067001) +FetchContent_GetProperties(pymatching) +if(NOT pymatching_POPULATED) + FetchContent_Populate(pymatching) + add_subdirectory(${pymatching_SOURCE_DIR}) +endif() + +add_executable(chromobius src/main.cc ${SOURCE_FILES_NO_MAIN} ${PYMATCHING_SOURCE_FILES_NO_MAIN}) +target_compile_options(chromobius PRIVATE -O3 -Wall -Wpedantic) +target_link_options(chromobius PRIVATE -O3) +target_link_libraries(chromobius libstim libpymatching) +install(TARGETS chromobius RUNTIME DESTINATION bin) + +add_library(libchromobius ${SOURCE_FILES_NO_MAIN}) +set_target_properties(libchromobius PROPERTIES PREFIX "") +target_include_directories(libchromobius PUBLIC src) +target_link_libraries(libchromobius PRIVATE libstim libpymatching) +if(NOT(MSVC)) + target_compile_options(libchromobius PRIVATE -O3 -Wall -Wpedantic -fPIC -fno-strict-aliasing) + target_link_options(libchromobius PRIVATE -O3) +else() + target_compile_options(libchromobius PRIVATE) +endif() +install(TARGETS libchromobius LIBRARY DESTINATION) +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/" DESTINATION "include" FILES_MATCHING PATTERN "*.h" PATTERN "*.inl") + +add_executable(chromobius_perf ${SOURCE_FILES_NO_MAIN} ${PYMATCHING_SOURCE_FILES_NO_MAIN} ${PERF_FILES}) +target_compile_options(chromobius_perf PRIVATE -Wall -Wpedantic -O3 -g -fno-omit-frame-pointer -DNDEBUG) +target_link_options(chromobius_perf PRIVATE -pthread) +target_link_libraries(chromobius_perf PRIVATE libstim libpymatching) + +find_package(GTest QUIET) +if(${GTest_FOUND}) + add_executable(chromobius_test ${SOURCE_FILES_NO_MAIN} ${PYMATCHING_SOURCE_FILES_NO_MAIN} ${TEST_FILES}) + target_link_libraries(chromobius_test GTest::gtest GTest::gtest_main libstim libpymatching) + target_compile_options(chromobius_test PRIVATE -Wall -Wpedantic -g -fno-omit-frame-pointer -fno-strict-aliasing -fsanitize=undefined -fsanitize=address) + target_link_options(chromobius_test PRIVATE -g -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address) + + add_executable(chromobius_test_o3 ${SOURCE_FILES_NO_MAIN} ${PYMATCHING_SOURCE_FILES_NO_MAIN} ${TEST_FILES}) + target_link_libraries(chromobius_test_o3 GTest::gtest GTest::gtest_main libstim libpymatching) + target_compile_options(chromobius_test_o3 PRIVATE -O3 -Wall -Wpedantic -fno-strict-aliasing) + target_link_options(chromobius_test_o3 PRIVATE) +else() + message("WARNING: Skipped chromobius_test target. `GTest` not found. To fix, follow Standalone CMake Project install instructions at https://github.com/google/googletest/blob/master/googletest/README.md") +endif() + +find_package(Python COMPONENTS Interpreter Development) +find_package(pybind11 CONFIG) +if ((${pybind11_FOUND} AND ${Python_FOUND}) OR "$ENV{CMAKE_FORCE_PYBIND_CHROMOBIUS}") + pybind11_add_module(chromobius_pybind ${PYBIND_FILES} ${SOURCE_FILES_NO_MAIN}) + set_target_properties(chromobius_pybind PROPERTIES OUTPUT_NAME chromobius) + target_compile_options(chromobius_pybind PRIVATE -O3 -DNDEBUG) + target_link_libraries(chromobius_pybind PRIVATE libstim libpymatching) + target_link_options(chromobius_pybind PRIVATE -O3) +else() + message("WARNING: Skipped chromobius_pybind target. `pybind11` not found. To fix, install pybind11. On debian based distributions, the package name is `pybind11-dev`") +endif() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..bc23aae --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# How to contribute + +We'd love to accept your patches and contributions to this project. + +## Before you begin + +### Sign our Contributor License Agreement + +Contributions to this project must be accompanied by a +[Contributor License Agreement](https://cla.developers.google.com/about) (CLA). +You (or your employer) retain the copyright to your contribution; this simply +gives us permission to use and redistribute your contributions as part of the +project. + +If you or your current employer have already signed the Google CLA (even if it +was for a different project), you probably don't need to do it again. + +Visit to see your current agreements or to +sign a new one. + +### Review our community guidelines + +This project follows +[Google's Open Source Community Guidelines](https://opensource.google/conduct/). + +## Contribution process + +### Code reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult +[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +information on using pull requests. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..12379f6 --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ +# Chromobius: color code decoder + +Chromobius is an implementation of a ["mobius decoder"](https://arxiv.org/abs/2108.11395), which approximates the color code decoding problem as a minimum weight matching problem. +Chromobius uses [PyMatching](https://github.com/oscarhiggott/PyMatching/) to solve the minimum weight matching problem. + +See ((((the paper "New circuits and an open source decoder for the color code")))) for more details on how Chromobius works. + +## How to use Chromobius + +See the [**getting started notebook**](doc/getting_started.ipynb). + +Also see the [python api reference](doc/chromobius_api_reference.md). + +Programmers who want to edit and build Chromobius can check the [developer documentation](doc/developers.md). + +## Example Snippets + +### Decoding a shot with Chromobius + +From python: + +```python +import stim +import chromobius +import numpy as np + +def count_mistakes(circuit: stim.Circuit, shots: int) -> int: + # Sample the circuit. + dets, actual_obs_flips = circuit.compile_detector_sampler().sample( + shots=shots, + separate_observables=True, + bit_packed=True, + ) + + # Decode with Chromobius. + decoder = chromobius.compile_decoder_for_dem(circuit.detector_error_model()) + predicted_obs_flips = decoder.predict_obs_flips_from_dets_bit_packed(dets) + + # Count mistakes. + return np.count_nonzero(np.any(predicted_obs_flips != actual_obs_flips, axis=1)) +``` + +From the command line: + +```bash +# Sample shots of detectors and observable flips. +stim detect \ + --shots 100000 \ + --in "example_circuit.stim" \ + --out "dets.b8" \ + --out_format "b8" \ + --obs_out "obs_actual.txt" \ + --obs_out_format "01" + +# Extract a detector error model used to configure Chromobius. +stim analyze_errors \ + --in "example_circuit.stim" \ + --fold_loops \ + --out "dem.dem" + +# Decode the shots. +chromobius predict \ + --dem "dem.dem" \ + --in "dets.b8" \ + --in_format "b8" \ + --out "obs_predicted.txt" \ + --out_format "01" + +# Count the number of shots with a prediction mistake. +paste obs_actual.txt obs_predicted.txt \ + | grep -Pv "^([01]*)\\s*\\1$" \ + | wc -l +``` + +From python using sinter: + +```python +import sinter +import chromobius +import os + +tasks: list[sinter.Task] = ... +stats: list[sinter.TaskStats] = sinter.collect( + decoders=["chromobius"], + custom_decoders=chromobius.sinter_decoders(), + tasks=tasks, + num_workers=os.cpu_count(), + max_shots=100_000, + max_errors=100, +) +``` + +From the command line using sinter: + +```bash +sinter collect \ + --circuits "example_circuit.stim" \ + --decoders chromobius \ + --custom_decoders_module_function "chromobius:sinter_decoders" \ + --max_shots 100_000 \ + --max_errors 100 + --processes auto \ + --save_resume_filepath "stats.csv" \ +``` diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..29e3ebb --- /dev/null +++ b/WORKSPACE @@ -0,0 +1,50 @@ +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +git_repository( + name = "stim", + commit = "3e38d12d0a0fb3022646b694137b733a4700d300", + remote = "https://github.com/quantumlib/stim.git", +) + +git_repository( + name = "pymatching", + commit = "40dcf8c01273ff7e23a7105d5cdc410ada067001", + remote = "https://github.com/oscarhiggott/pymatching.git", +) + +http_archive( + name = "gtest", + sha256 = "353571c2440176ded91c2de6d6cd88ddd41401d14692ec1f99e35d013feda55a", + strip_prefix = "googletest-release-1.11.0", + urls = ["https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip"], +) + +http_archive( + name = "pybind11", + build_file = "@pybind11_bazel//:pybind11.BUILD", + sha256 = "832e2f309c57da9c1e6d4542dedd34b24e4192ecb4d62f6f4866a737454c9970", + strip_prefix = "pybind11-2.10.4", + urls = ["https://github.com/pybind/pybind11/archive/v2.10.4.tar.gz"], +) + +http_archive( + name = "pybind11_bazel", + sha256 = "e8355ee56c2ff772334b4bfa22be17c709e5573f6d1d561c7176312156c27bd4", + strip_prefix = "pybind11_bazel-2.11.1", + urls = ["https://github.com/pybind/pybind11_bazel/releases/download/v2.11.1/pybind11_bazel-2.11.1.tar.gz"], +) + +http_archive( + name = "rules_python", + sha256 = "0a8003b044294d7840ac7d9d73eef05d6ceb682d7516781a4ec62eeb34702578", + strip_prefix = "rules_python-0.24.0", + url = "https://github.com/bazelbuild/rules_python/releases/download/0.24.0/rules_python-0.24.0.tar.gz", +) + +load("@rules_python//python:repositories.bzl", "py_repositories") +load("@pybind11_bazel//:python_configure.bzl", "python_configure") + +py_repositories() + +python_configure(name = "local_config_python") diff --git a/assets/ablated_stabilizers.png b/assets/ablated_stabilizers.png new file mode 100644 index 0000000..6481247 Binary files /dev/null and b/assets/ablated_stabilizers.png differ diff --git a/assets/cmp_transit_from_prev.png b/assets/cmp_transit_from_prev.png new file mode 100644 index 0000000..93dd357 Binary files /dev/null and b/assets/cmp_transit_from_prev.png differ diff --git a/assets/color2surface.png b/assets/color2surface.png new file mode 100644 index 0000000..6f9dd1a Binary files /dev/null and b/assets/color2surface.png differ diff --git a/assets/color_code_layouts.png b/assets/color_code_layouts.png new file mode 100644 index 0000000..3c0a69f Binary files /dev/null and b/assets/color_code_layouts.png differ diff --git a/assets/color_code_layouts.svg b/assets/color_code_layouts.svg new file mode 100644 index 0000000..c77cff4 --- /dev/null +++ b/assets/color_code_layouts.svg @@ -0,0 +1,15641 @@ + + + +Standard Color Code (base width=11){4,8,8} Color Code (base width=11)superdense circuit layoutmiddle-out circuit layout{4,8,8} middle-out circuit layoutadd spursadd spurshex-to-rectfit ancillaeoct-to-rect diff --git a/assets/example_boundary_match.png b/assets/example_boundary_match.png new file mode 100644 index 0000000..2f35e45 Binary files /dev/null and b/assets/example_boundary_match.png differ diff --git a/assets/generated/cmp_transit.png b/assets/generated/cmp_transit.png new file mode 100644 index 0000000..4c3a13b Binary files /dev/null and b/assets/generated/cmp_transit.png differ diff --git a/assets/generated/compare_X.png b/assets/generated/compare_X.png new file mode 100644 index 0000000..5a18f7b Binary files /dev/null and b/assets/generated/compare_X.png differ diff --git a/assets/generated/compare_XZ.png b/assets/generated/compare_XZ.png new file mode 100644 index 0000000..f256f2c Binary files /dev/null and b/assets/generated/compare_XZ.png differ diff --git a/assets/generated/compare_Z.png b/assets/generated/compare_Z.png new file mode 100644 index 0000000..15c2678 Binary files /dev/null and b/assets/generated/compare_Z.png differ diff --git a/assets/generated/midout_error_X.png b/assets/generated/midout_error_X.png new file mode 100644 index 0000000..0860f25 Binary files /dev/null and b/assets/generated/midout_error_X.png differ diff --git a/assets/generated/midout_error_XZ.png b/assets/generated/midout_error_XZ.png new file mode 100644 index 0000000..040c189 Binary files /dev/null and b/assets/generated/midout_error_XZ.png differ diff --git a/assets/generated/midout_error_Z.png b/assets/generated/midout_error_Z.png new file mode 100644 index 0000000..da312df Binary files /dev/null and b/assets/generated/midout_error_Z.png differ diff --git a/assets/generated/midout_footprint_X.png b/assets/generated/midout_footprint_X.png new file mode 100644 index 0000000..f29f1a4 Binary files /dev/null and b/assets/generated/midout_footprint_X.png differ diff --git a/assets/generated/midout_footprint_XZ.png b/assets/generated/midout_footprint_XZ.png new file mode 100644 index 0000000..f8528e1 Binary files /dev/null and b/assets/generated/midout_footprint_XZ.png differ diff --git a/assets/generated/midout_footprint_Z.png b/assets/generated/midout_footprint_Z.png new file mode 100644 index 0000000..db1a449 Binary files /dev/null and b/assets/generated/midout_footprint_Z.png differ diff --git a/assets/generated/phenom.png b/assets/generated/phenom.png new file mode 100644 index 0000000..97d429d Binary files /dev/null and b/assets/generated/phenom.png differ diff --git a/assets/generated/prev_work_comparison_0.0001.png b/assets/generated/prev_work_comparison_0.0001.png new file mode 100644 index 0000000..6117e8b Binary files /dev/null and b/assets/generated/prev_work_comparison_0.0001.png differ diff --git a/assets/generated/prev_work_comparison_0.0002.png b/assets/generated/prev_work_comparison_0.0002.png new file mode 100644 index 0000000..cfd9ac0 Binary files /dev/null and b/assets/generated/prev_work_comparison_0.0002.png differ diff --git a/assets/generated/prev_work_comparison_0.0003.png b/assets/generated/prev_work_comparison_0.0003.png new file mode 100644 index 0000000..f868819 Binary files /dev/null and b/assets/generated/prev_work_comparison_0.0003.png differ diff --git a/assets/generated/prev_work_comparison_0.0005.png b/assets/generated/prev_work_comparison_0.0005.png new file mode 100644 index 0000000..1438fa1 Binary files /dev/null and b/assets/generated/prev_work_comparison_0.0005.png differ diff --git a/assets/generated/prev_work_comparison_0.001.png b/assets/generated/prev_work_comparison_0.001.png new file mode 100644 index 0000000..f1ef0a3 Binary files /dev/null and b/assets/generated/prev_work_comparison_0.001.png differ diff --git a/assets/generated/prev_work_comparison_0.002.png b/assets/generated/prev_work_comparison_0.002.png new file mode 100644 index 0000000..196ceca Binary files /dev/null and b/assets/generated/prev_work_comparison_0.002.png differ diff --git a/assets/generated/stats-xz-combo.csv b/assets/generated/stats-xz-combo.csv new file mode 100644 index 0000000..bf50ada --- /dev/null +++ b/assets/generated/stats-xz-combo.csv @@ -0,0 +1,896 @@ + shots, errors, discards, seconds,decoder,strong_id,json_metadata,custom_counts + 8053, 1006, 0, 0.131,chromobius,dc8a8b0b38a83885b96b6529a9f5f5dea87ed11e5e5890cb772ab86084758d92,"{""c"":""midout_color_code_488_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":9,""r"":12}", + 5802, 1019, 0, 0.068,chromobius,06ac46fd8ef9b844361b0a124023d7120d0c67ca82275995ddbf94ca8e468c8d,"{""c"":""midout_color_code_488_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":9,""r"":12}", + 5802, 1617, 0, 0.199,chromobius,06ac46fd8ef9b844361b0a124023d7120d0c67ca82275995ddbf94ca8e468c8d*dc8a8b0b38a83885b96b6529a9f5f5dea87ed11e5e5890cb772ab86084758d92,"{""c"":""midout_color_code_488_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":9,""r"":12}", + 6936, 1017, 0, 0.734,chromobius,d857db1f0debac8705a37faf9ca51802434e633b05931b885d7bb4b5d6806348,"{""c"":""midout_color_code_488_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":21,""r"":20}", + 10813, 1064, 0, 0.392,chromobius,26658b46f4d6a5781df30e418ab964678b33635e4e6cdde7d7c631edd3028139,"{""c"":""midout_color_code_488_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":21,""r"":20}", + 6936, 1599, 0, 1.13,chromobius,d857db1f0debac8705a37faf9ca51802434e633b05931b885d7bb4b5d6806348*26658b46f4d6a5781df30e418ab964678b33635e4e6cdde7d7c631edd3028139,"{""c"":""midout_color_code_488_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":21,""r"":20}", + 14735, 1113, 0, 1.77,chromobius,731c367d069afbafeff01aa21ddd44bdb90bd0df09f60b50c04ff778da7e5356,"{""c"":""midout_color_code_488_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":37,""r"":28}", + 13426, 1032, 0, 1.44,chromobius,bba7a1eaa8e80184a2256ab3034a6f35c82f2beb9105984dcd00186efa04cd6b,"{""c"":""midout_color_code_488_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":37,""r"":28}", + 13426, 1968, 0, 3.21,chromobius,bba7a1eaa8e80184a2256ab3034a6f35c82f2beb9105984dcd00186efa04cd6b*731c367d069afbafeff01aa21ddd44bdb90bd0df09f60b50c04ff778da7e5356,"{""c"":""midout_color_code_488_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":37,""r"":28}", + 8875, 1000, 0, 3.02,chromobius,870453b363ca6ebda36742c661a40d79fb8ba27a61940ed187b4da9d394a7e9d,"{""c"":""midout_color_code_488_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":57,""r"":36}", + 9200, 1002, 0, 3.35,chromobius,5dce626311a7429b8d8e5909ff8d311f581e4ad1e06a9b12f0c6dd947d8e0b8b,"{""c"":""midout_color_code_488_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":57,""r"":36}", + 8875, 1858, 0, 6.37,chromobius,870453b363ca6ebda36742c661a40d79fb8ba27a61940ed187b4da9d394a7e9d*5dce626311a7429b8d8e5909ff8d311f581e4ad1e06a9b12f0c6dd947d8e0b8b,"{""c"":""midout_color_code_488_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":57,""r"":36}", + 33386, 1038, 0, 15.9,chromobius,4edb9408d768deb425edec64ccd5d27be493eafa42a4ab0bc391af1a22e8eccd,"{""c"":""midout_color_code_488_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":81,""r"":44}", + 33346, 1029, 0, 15.3,chromobius,48b3baae33e8d622401e5ab598e3cd2f3a77abad37a118134173092fa4403f1d,"{""c"":""midout_color_code_488_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":81,""r"":44}", + 33346, 2034, 0, 31.2,chromobius,48b3baae33e8d622401e5ab598e3cd2f3a77abad37a118134173092fa4403f1d*4edb9408d768deb425edec64ccd5d27be493eafa42a4ab0bc391af1a22e8eccd,"{""c"":""midout_color_code_488_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":81,""r"":44}", + 78076, 1079, 0, 55.2,chromobius,f234ea89f3e23b569626df94bb720fcb0264dcfb302846b03db2b92292f84eab,"{""c"":""midout_color_code_488_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":109,""r"":52}", + 77400, 1049, 0, 46.0,chromobius,9e014120f7100adf533620defd113a27f0792f943333f61dee82f59ce0aad258,"{""c"":""midout_color_code_488_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":109,""r"":52}", + 77400, 2104, 0, 101.2,chromobius,9e014120f7100adf533620defd113a27f0792f943333f61dee82f59ce0aad258*f234ea89f3e23b569626df94bb720fcb0264dcfb302846b03db2b92292f84eab,"{""c"":""midout_color_code_488_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":109,""r"":52}", + 105451, 1046, 0, 110.3,chromobius,3ec32b1797d0b0c61572ccf7e2257d8c9f31d1510c00c523b48f6c5fe8bba6f9,"{""c"":""midout_color_code_488_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":141,""r"":60}", + 108873, 1042, 0, 120.5,chromobius,74f930788405cc1b93b97a80305b89e60db81ef0a05a0921d7d689be5b625a72,"{""c"":""midout_color_code_488_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":141,""r"":60}", + 105451, 2045, 0, 230.8,chromobius,3ec32b1797d0b0c61572ccf7e2257d8c9f31d1510c00c523b48f6c5fe8bba6f9*74f930788405cc1b93b97a80305b89e60db81ef0a05a0921d7d689be5b625a72,"{""c"":""midout_color_code_488_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":141,""r"":60}", + 211250, 1000, 0, 328.8,chromobius,f46495cdac49d51cac14c0644f4bea348c2e9a8459491e6b6070662aa128d586,"{""c"":""midout_color_code_488_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":177,""r"":68}", + 203876, 1005, 0, 306.5,chromobius,4e944f1a5ca3ecf8871ac8c068b88d790dd01071a6273f01026c340c0c6de4af,"{""c"":""midout_color_code_488_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":177,""r"":68}", + 203876, 1965, 0, 635.3,chromobius,4e944f1a5ca3ecf8871ac8c068b88d790dd01071a6273f01026c340c0c6de4af*f46495cdac49d51cac14c0644f4bea348c2e9a8459491e6b6070662aa128d586,"{""c"":""midout_color_code_488_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":177,""r"":68}", + 340314, 1057, 0, 740.8,chromobius,0c4ca6f70f7026078c65f91eb68dd55a3e913684ce58c785025684c8ff57efbd,"{""c"":""midout_color_code_488_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":217,""r"":76}", + 339552, 1028, 0, 734.3,chromobius,070e282476c30eae8caac1ef67b2169f9b84736ac614497489f7850f916fb1b3,"{""c"":""midout_color_code_488_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":217,""r"":76}", + 339552, 2079, 0, 1475.1,chromobius,070e282476c30eae8caac1ef67b2169f9b84736ac614497489f7850f916fb1b3*0c4ca6f70f7026078c65f91eb68dd55a3e913684ce58c785025684c8ff57efbd,"{""c"":""midout_color_code_488_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":217,""r"":76}", + 92986, 1098, 0, 0.189,chromobius,a83d902b1fb34dd83f53b20039159a7cc1c4a9b90803f58919022277490c1987,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":9,""r"":12}", + 95444, 1129, 0, 0.156,chromobius,3a828d8b47b727807f8191dc6c7fd5bc91d3aeac44604a267f7c2309ccad7d04,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":9,""r"":12}", + 92986, 2185, 0, 0.345,chromobius,a83d902b1fb34dd83f53b20039159a7cc1c4a9b90803f58919022277490c1987*3a828d8b47b727807f8191dc6c7fd5bc91d3aeac44604a267f7c2309ccad7d04,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":9,""r"":12}", + 41758, 1004, 0, 0.142,chromobius,d114b1ff54242d2c91e65f826b3a937921bbb2c5e00119c180785e3d399b096c,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":9,""r"":12}", + 45638, 1000, 0, 0.106,chromobius,adb35de2faaaacfe7af5c31d74fbc08602044c7b6ba5fb8991e26e783625c1c5,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":9,""r"":12}", + 41758, 1897, 0, 0.248,chromobius,d114b1ff54242d2c91e65f826b3a937921bbb2c5e00119c180785e3d399b096c*adb35de2faaaacfe7af5c31d74fbc08602044c7b6ba5fb8991e26e783625c1c5,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":9,""r"":12}", + 27255, 1006, 0, 0.091,chromobius,e3f6114952b84b36ec43dea6cb8504e39752cf44c93637a4983dd32c04529707,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":9,""r"":12}", + 28534, 1041, 0, 0.087,chromobius,1d8e25a620b54ac781cda629d85303cb176e68d782dc1ce931d26a86603b1016,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":9,""r"":12}", + 27255, 1964, 0, 0.178,chromobius,e3f6114952b84b36ec43dea6cb8504e39752cf44c93637a4983dd32c04529707*1d8e25a620b54ac781cda629d85303cb176e68d782dc1ce931d26a86603b1016,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":9,""r"":12}", + 17030, 1004, 0, 0.154,chromobius,470f06088a6b23c02a6f1aa05e6724f110fedc8ae2dc504ec423ee68d18455ef,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":9,""r"":12}", + 18334, 1045, 0, 0.090,chromobius,8e3441d3af8a687a9bc4d9ac2f3312721e5bd3525064f12c302793de03659ac1,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":9,""r"":12}", + 17030, 1917, 0, 0.244,chromobius,470f06088a6b23c02a6f1aa05e6724f110fedc8ae2dc504ec423ee68d18455ef*8e3441d3af8a687a9bc4d9ac2f3312721e5bd3525064f12c302793de03659ac1,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":9,""r"":12}", + 13881, 1031, 0, 0.122,chromobius,cc266790d8c6a20df9e67a8cb9910cba4acf25656dec49cb8b78d2d895f35555,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":9,""r"":12}", + 12897, 1019, 0, 0.077,chromobius,2a30f1af908c5e87c6ef0237ade2876261a506f03fb26f7dade39c0667aa1bc1,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":9,""r"":12}", + 12897, 1901, 0, 0.199,chromobius,2a30f1af908c5e87c6ef0237ade2876261a506f03fb26f7dade39c0667aa1bc1*cc266790d8c6a20df9e67a8cb9910cba4acf25656dec49cb8b78d2d895f35555,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":9,""r"":12}", + 9591, 1024, 0, 0.105,chromobius,e39a2c03a77d7757d2e9b0f20177e3531231aebc6e90c1930497a93c9bb69899,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":9,""r"":12}", + 9371, 1005, 0, 0.107,chromobius,20bfda9a59c8fe51cdc7144a0b58ce299d1292b5641ff0e6652bc738bd23741d,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":9,""r"":12}", + 9371, 1898, 0, 0.212,chromobius,20bfda9a59c8fe51cdc7144a0b58ce299d1292b5641ff0e6652bc738bd23741d*e39a2c03a77d7757d2e9b0f20177e3531231aebc6e90c1930497a93c9bb69899,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":9,""r"":12}", + 5271, 1002, 0, 0.119,chromobius,a419b9fb39f6dc05e659db55f78428011e9145e1d8585e76d45be56c4bb386e2,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":9,""r"":12}", + 5423, 1023, 0, 0.073,chromobius,a262a58fe8efaff52a34706e534dcd43b437267ca6c45ca5a01b8f0486557e8e,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":9,""r"":12}", + 5271, 1807, 0, 0.192,chromobius,a419b9fb39f6dc05e659db55f78428011e9145e1d8585e76d45be56c4bb386e2*a262a58fe8efaff52a34706e534dcd43b437267ca6c45ca5a01b8f0486557e8e,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":9,""r"":12}", + 3881, 1010, 0, 0.073,chromobius,887bbd376d8dc741e6aa7ba44fd84445c58a5d5b77486236ebfe75824017f9fb,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":9,""r"":12}", + 4114, 1037, 0, 0.059,chromobius,4086c7efe98e27d9021eba53933c266c2c6977c05efac3cd64d3e1f0a4661b52,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":9,""r"":12}", + 3881, 1734, 0, 0.132,chromobius,887bbd376d8dc741e6aa7ba44fd84445c58a5d5b77486236ebfe75824017f9fb*4086c7efe98e27d9021eba53933c266c2c6977c05efac3cd64d3e1f0a4661b52,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":9,""r"":12}", + 2878, 1004, 0, 0.101,chromobius,58c9b9499b4cb90a1cfbcff6b39fc7e4e74401a360620e4e81250dfb06144364,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":9,""r"":12}", + 2765, 1002, 0, 0.083,chromobius,58e96c350b65d0d7d549592ae574121fbf2f847695e645b67ac2e27855b47e3a,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":9,""r"":12}", + 2765, 1617, 0, 0.184,chromobius,58e96c350b65d0d7d549592ae574121fbf2f847695e645b67ac2e27855b47e3a*58c9b9499b4cb90a1cfbcff6b39fc7e4e74401a360620e4e81250dfb06144364,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":9,""r"":12}", + 2586, 1004, 0, 0.086,chromobius,22e7bc2b90a911ea92dca32178980420d5d969c39e63dd75d7a611e0793d7016,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":9,""r"":12}", + 2790, 1093, 0, 0.071,chromobius,1b77ed7b89fd1e34b7ef91591ed7ab69215424a1960aa5d2d0e51fc314e995dc,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":9,""r"":12}", + 2586, 1624, 0, 0.157,chromobius,22e7bc2b90a911ea92dca32178980420d5d969c39e63dd75d7a611e0793d7016*1b77ed7b89fd1e34b7ef91591ed7ab69215424a1960aa5d2d0e51fc314e995dc,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":9,""r"":12}", + 2367, 1012, 0, 0.081,chromobius,9b5b8c0ec1a9a225875ecef89f201c649a31070d105ddfd5809484aedf9478ec,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":9,""r"":12}", + 2422, 1023, 0, 0.107,chromobius,db90d8bfa43346872978ab1908ffa78dd97d795b83096702e514dd54031ef24c,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":9,""r"":12}", + 2367, 1584, 0, 0.188,chromobius,9b5b8c0ec1a9a225875ecef89f201c649a31070d105ddfd5809484aedf9478ec*db90d8bfa43346872978ab1908ffa78dd97d795b83096702e514dd54031ef24c,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":9,""r"":12}", + 2450, 1080, 0, 0.085,chromobius,0f1ad12768f5423e4d61fc5ea03295959dee2efba5df4ad8037b6538d8b16825,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":9,""r"":12}", + 2428, 1017, 0, 0.087,chromobius,92c9ffaf578b92f51d8634d96087d3e8c9be00a22e38a5244f3d21316e9988a0,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":9,""r"":12}", + 2428, 1639, 0, 0.172,chromobius,92c9ffaf578b92f51d8634d96087d3e8c9be00a22e38a5244f3d21316e9988a0*0f1ad12768f5423e4d61fc5ea03295959dee2efba5df4ad8037b6538d8b16825,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":9,""r"":12}", + 2184, 1026, 0, 0.075,chromobius,4d15f53ff5eaa8c73227a8d9d400a90c6b20dddcc95fe58bddfc2207c95eea9b,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":9,""r"":12}", + 2201, 1003, 0, 0.063,chromobius,90223c6c80b7df2e23c8f79fbbeacdb8d2c53e24b85a55ce03a191d1402ed7f9,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":9,""r"":12}", + 2184, 1554, 0, 0.138,chromobius,4d15f53ff5eaa8c73227a8d9d400a90c6b20dddcc95fe58bddfc2207c95eea9b*90223c6c80b7df2e23c8f79fbbeacdb8d2c53e24b85a55ce03a191d1402ed7f9,"{""c"":""midout_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":9,""r"":12}", + 4030141, 1027, 0, 14.3,chromobius,9d7b85be9c89548a8bc40425a81765b505aca08df6fc112bc2bdc641ee9ef5fb,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":23,""r"":20}", + 4009896, 1010, 0, 13.4,chromobius,c76b8229ef9547e49f7a3ac6b139911657d08078ce057a2a68642839f6ec5499,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":23,""r"":20}", + 4009896, 2032, 0, 27.7,chromobius,c76b8229ef9547e49f7a3ac6b139911657d08078ce057a2a68642839f6ec5499*9d7b85be9c89548a8bc40425a81765b505aca08df6fc112bc2bdc641ee9ef5fb,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":23,""r"":20}", + 940376, 1005, 0, 5.63,chromobius,c512191047eabd479184058fc6663b9b1b86440f4abd36c5b499859239c30091,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":23,""r"":20}", + 964973, 1018, 0, 5.25,chromobius,1ee718955cb4c2fcd23d00a68ca4ad6f414b0bab77cd29a430437e71bfe4a9e5,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":23,""r"":20}", + 940376, 1996, 0, 10.9,chromobius,c512191047eabd479184058fc6663b9b1b86440f4abd36c5b499859239c30091*1ee718955cb4c2fcd23d00a68ca4ad6f414b0bab77cd29a430437e71bfe4a9e5,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":23,""r"":20}", + 429539, 1009, 0, 3.68,chromobius,5537f8fd764d00077ce5b8517403566b889b8cd0f3df2ee46432932612656bf1,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":23,""r"":20}", + 489605, 1068, 0, 3.83,chromobius,d24e75f3a803732c693e0bedf97f78d008a1ab7b8f9edc4f441d60254eec7b75,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":23,""r"":20}", + 429539, 1944, 0, 7.51,chromobius,5537f8fd764d00077ce5b8517403566b889b8cd0f3df2ee46432932612656bf1*d24e75f3a803732c693e0bedf97f78d008a1ab7b8f9edc4f441d60254eec7b75,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":23,""r"":20}", + 169589, 1071, 0, 2.19,chromobius,e957254e8e28f9336dac58ed6d5b08bee7b6f876502d577181325e3427706d53,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":23,""r"":20}", + 163349, 1052, 0, 2.20,chromobius,8c65b4ae76b9154fd3e68c41f65215c017f4c87e18d28c9056e7b8be808cebfe,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":23,""r"":20}", + 163349, 2077, 0, 4.39,chromobius,8c65b4ae76b9154fd3e68c41f65215c017f4c87e18d28c9056e7b8be808cebfe*e957254e8e28f9336dac58ed6d5b08bee7b6f876502d577181325e3427706d53,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":23,""r"":20}", + 79740, 1000, 0, 1.60,chromobius,cd290599dc49b147ab7de68d0befb3d0778912a719c2e99f17a75662aef03db0,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":23,""r"":20}", + 86489, 1023, 0, 1.60,chromobius,908c7b8b1de0633d69cc0c74a1e71c27f9bcfbf33b20d79a8d121b16b3acb39e,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":23,""r"":20}", + 79740, 1931, 0, 3.20,chromobius,cd290599dc49b147ab7de68d0befb3d0778912a719c2e99f17a75662aef03db0*908c7b8b1de0633d69cc0c74a1e71c27f9bcfbf33b20d79a8d121b16b3acb39e,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":23,""r"":20}", + 40295, 1003, 0, 1.36,chromobius,e88b3d80fd9b7782f576bcbfde923642923c87cbd37d645a6ea81b3853cde112,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":23,""r"":20}", + 39539, 1021, 0, 1.19,chromobius,6850edc67fd4913b80008eab17244c03a5d925fdada129a2a861ff29e92a9c6e,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":23,""r"":20}", + 39539, 1980, 0, 2.55,chromobius,6850edc67fd4913b80008eab17244c03a5d925fdada129a2a861ff29e92a9c6e*e88b3d80fd9b7782f576bcbfde923642923c87cbd37d645a6ea81b3853cde112,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":23,""r"":20}", + 11880, 1061, 0, 0.859,chromobius,9959dfefdf9ac06118ed9d473d04e68d2535892ffe9cf806a8ce1ac96a1d3d79,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":23,""r"":20}", + 11705, 1052, 0, 0.737,chromobius,8d6cf338539da6e269d390cd45fa213a4ed7e1a9444d522313f76f42b9b7cdcb,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":23,""r"":20}", + 11705, 2003, 0, 1.60,chromobius,8d6cf338539da6e269d390cd45fa213a4ed7e1a9444d522313f76f42b9b7cdcb*9959dfefdf9ac06118ed9d473d04e68d2535892ffe9cf806a8ce1ac96a1d3d79,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":23,""r"":20}", + 5730, 1002, 0, 0.876,chromobius,2c98713fc8824c3b9ea627047fd8110aa3b4bc01a3b9b8aedf1cb18b63a6d4b3,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":23,""r"":20}", + 6370, 1045, 0, 0.700,chromobius,d44deffad33ee2a3fdf53a5b0ff6e51230feb5e29fa3b44519042d8c9beffa75,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":23,""r"":20}", + 5730, 1778, 0, 1.58,chromobius,2c98713fc8824c3b9ea627047fd8110aa3b4bc01a3b9b8aedf1cb18b63a6d4b3*d44deffad33ee2a3fdf53a5b0ff6e51230feb5e29fa3b44519042d8c9beffa75,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":23,""r"":20}", + 3320, 1046, 0, 0.643,chromobius,c7b1dc694b0d3f4a770b7394da69619138f1badf5ab936a61f6ccc7649fa185c,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":23,""r"":20}", + 3066, 1013, 0, 0.519,chromobius,4f6517cf99c0859288031a1fab3652de0f4eb81dfdfa36628cb6d3b7f4da606f,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":23,""r"":20}", + 3066, 1660, 0, 1.16,chromobius,4f6517cf99c0859288031a1fab3652de0f4eb81dfdfa36628cb6d3b7f4da606f*c7b1dc694b0d3f4a770b7394da69619138f1badf5ab936a61f6ccc7649fa185c,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":23,""r"":20}", + 2719, 1026, 0, 0.638,chromobius,359ed3ae084a1a9c0a5709b98e4d4a1980418c666067a5ed49d57b020b2b5de2,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":23,""r"":20}", + 2691, 1027, 0, 0.456,chromobius,d328073250400d6039e1c7f5515440471dfd7462c15277a8d8505dbbf30166bf,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":23,""r"":20}", + 2691, 1655, 0, 1.09,chromobius,d328073250400d6039e1c7f5515440471dfd7462c15277a8d8505dbbf30166bf*359ed3ae084a1a9c0a5709b98e4d4a1980418c666067a5ed49d57b020b2b5de2,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":23,""r"":20}", + 2480, 1028, 0, 0.488,chromobius,6fa52661d55b9e4904c29355acd4d7ec68c16f6d48f3b1f5687ed1e6acc44a8d,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":23,""r"":20}", + 2490, 1034, 0, 0.503,chromobius,85da861bec2aeedd15e1c0c80fb387453da97c5c39f842d9d1bc140a99a44889,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":23,""r"":20}", + 2480, 1631, 0, 0.991,chromobius,6fa52661d55b9e4904c29355acd4d7ec68c16f6d48f3b1f5687ed1e6acc44a8d*85da861bec2aeedd15e1c0c80fb387453da97c5c39f842d9d1bc140a99a44889,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":23,""r"":20}", + 2147, 1003, 0, 0.611,chromobius,5e6d75761dc17229f60b7bd5c31288cede1171268a0cbf08cd8b353765461eb6,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":23,""r"":20}", + 2093, 1003, 0, 0.533,chromobius,2335e0d7866e69bd39621acf939262e48fc31a06ed394f842769bd44385266db,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":23,""r"":20}", + 2093, 1512, 0, 1.14,chromobius,2335e0d7866e69bd39621acf939262e48fc31a06ed394f842769bd44385266db*5e6d75761dc17229f60b7bd5c31288cede1171268a0cbf08cd8b353765461eb6,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":23,""r"":20}", + 2222, 1067, 0, 0.638,chromobius,8647ed48a818af4c2d5e63bac9d0dc67069ad40fb8c5573d22ab203801109d48,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":23,""r"":20}", + 2095, 1003, 0, 0.628,chromobius,1878110a843d7b818608581b4fa452521835bd2895105bb09c0bd740e46b5fd4,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":23,""r"":20}", + 2095, 1527, 0, 1.27,chromobius,1878110a843d7b818608581b4fa452521835bd2895105bb09c0bd740e46b5fd4*8647ed48a818af4c2d5e63bac9d0dc67069ad40fb8c5573d22ab203801109d48,"{""c"":""midout_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":23,""r"":20}", + 8241626, 1065, 0, 89.8,chromobius,fd24ac42f8bee7055b5fad9bc342875494f30e80a31cead70e7a64c0abe8a386,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":43,""r"":28}", + 7453742, 1005, 0, 72.5,chromobius,6fcc1445ed71bc6f4617638017089992bea5519d0eb8c5223b06a0b4b9d6b2d4,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":43,""r"":28}", + 7453742, 1968, 0, 162.3,chromobius,6fcc1445ed71bc6f4617638017089992bea5519d0eb8c5223b06a0b4b9d6b2d4*fd24ac42f8bee7055b5fad9bc342875494f30e80a31cead70e7a64c0abe8a386,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":43,""r"":28}", + 1962098, 1106, 0, 32.9,chromobius,4c6419912d8b28adc7682dc160a598d77f9851f6b2598448739f7978277b0f61,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":43,""r"":28}", + 1900425, 1061, 0, 30.7,chromobius,a046dec633c85227a90558c95b189632057d9c32bfe97af5dd63e4da3a7dfebc,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":43,""r"":28}", + 1900425, 2132, 0, 63.6,chromobius,a046dec633c85227a90558c95b189632057d9c32bfe97af5dd63e4da3a7dfebc*4c6419912d8b28adc7682dc160a598d77f9851f6b2598448739f7978277b0f61,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":43,""r"":28}", + 781943, 1000, 0, 19.5,chromobius,5b25f9723c1cade7bd157c9f3c8e1f5bb630aeecf408bca2449a6d810619775e,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":43,""r"":28}", + 885412, 1136, 0, 19.6,chromobius,de2363a10d1c4560731b4b8e0ea1ea7bdf1ad15e58a072fee85220acb7342d4a,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":43,""r"":28}", + 781943, 2002, 0, 39.1,chromobius,5b25f9723c1cade7bd157c9f3c8e1f5bb630aeecf408bca2449a6d810619775e*de2363a10d1c4560731b4b8e0ea1ea7bdf1ad15e58a072fee85220acb7342d4a,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":43,""r"":28}", + 256932, 1003, 0, 11.2,chromobius,b82d70742dcd813405d25a5fe00d833c72c7af03f5a5279564eb0cf92c8652f1,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":43,""r"":28}", + 272378, 1046, 0, 10.5,chromobius,9d54e876a5b352e5889c82694d94c6c16bf4698ec921571ea174597e0da6208a,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":43,""r"":28}", + 256932, 1986, 0, 21.7,chromobius,b82d70742dcd813405d25a5fe00d833c72c7af03f5a5279564eb0cf92c8652f1*9d54e876a5b352e5889c82694d94c6c16bf4698ec921571ea174597e0da6208a,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":43,""r"":28}", + 128485, 1007, 0, 8.23,chromobius,bf3de27545df21f22ff51f031ac05358a583f9c03f9ff9a968b4b06251beab18,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":43,""r"":28}", + 128531, 1002, 0, 7.81,chromobius,7a01c78a73f313fb4e82b059c94c08707b86f3d25b3c9f5d6218e855704db617,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":43,""r"":28}", + 128485, 2001, 0, 16.0,chromobius,bf3de27545df21f22ff51f031ac05358a583f9c03f9ff9a968b4b06251beab18*7a01c78a73f313fb4e82b059c94c08707b86f3d25b3c9f5d6218e855704db617,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":43,""r"":28}", + 60919, 1001, 0, 5.68,chromobius,648205c904ec814cf26bb8c196cb4a7227bc081fce4263ab2e297bff5731e0de,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":43,""r"":28}", + 63910, 1046, 0, 5.75,chromobius,726fa2993b808b9cf22a216fe0e2c4110670d6962fd899db58bd3872bcd482df,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":43,""r"":28}", + 60919, 1982, 0, 11.4,chromobius,648205c904ec814cf26bb8c196cb4a7227bc081fce4263ab2e297bff5731e0de*726fa2993b808b9cf22a216fe0e2c4110670d6962fd899db58bd3872bcd482df,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":43,""r"":28}", + 13763, 1007, 0, 3.41,chromobius,9acfca7b3487f8af8b1f5c93c74fe224ce4ec2dc073a335cddc034b09810027e,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":43,""r"":28}", + 13297, 1003, 0, 3.19,chromobius,cf799aebbb44d078812d844f3c01cf14cf2645f1807aa5ab9145cdd516f51ef6,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":43,""r"":28}", + 13297, 1903, 0, 6.60,chromobius,cf799aebbb44d078812d844f3c01cf14cf2645f1807aa5ab9145cdd516f51ef6*9acfca7b3487f8af8b1f5c93c74fe224ce4ec2dc073a335cddc034b09810027e,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":43,""r"":28}", + 5924, 1023, 0, 2.68,chromobius,eb2567747028bef0e920db2b549ac9527dae7a28b474e25237b47d0688763047,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":43,""r"":28}", + 5937, 1007, 0, 2.03,chromobius,093d2086d7d8e4f9bad675da4c0c7cf7fc420a9f25cf8d576d3e7d6a44a797c8,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":43,""r"":28}", + 5924, 1854, 0, 4.71,chromobius,eb2567747028bef0e920db2b549ac9527dae7a28b474e25237b47d0688763047*093d2086d7d8e4f9bad675da4c0c7cf7fc420a9f25cf8d576d3e7d6a44a797c8,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":43,""r"":28}", + 2742, 1011, 0, 2.29,chromobius,e9422e4ddafd68d42bd9c1691bd04ac345148e39cd3ac52fcfa5544c929281f7,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":43,""r"":28}", + 2860, 1008, 0, 1.80,chromobius,b903cdffde92c0b9de53cbf72e420fdfa410cd2b19ea0708a421b4a7f12d6230,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":43,""r"":28}", + 2742, 1621, 0, 4.09,chromobius,e9422e4ddafd68d42bd9c1691bd04ac345148e39cd3ac52fcfa5544c929281f7*b903cdffde92c0b9de53cbf72e420fdfa410cd2b19ea0708a421b4a7f12d6230,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":43,""r"":28}", + 2411, 1009, 0, 2.08,chromobius,6745e0c1f44d4b7a4d0d19aacd07d2f861629086397bd84e38364a5aa4e26c45,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":43,""r"":28}", + 2543, 1055, 0, 1.72,chromobius,4124a85625d303c95b625279bbe620aef0ef19b51f26693a602dbd3a632ef8c6,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":43,""r"":28}", + 2411, 1591, 0, 3.80,chromobius,6745e0c1f44d4b7a4d0d19aacd07d2f861629086397bd84e38364a5aa4e26c45*4124a85625d303c95b625279bbe620aef0ef19b51f26693a602dbd3a632ef8c6,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":43,""r"":28}", + 2163, 1003, 0, 2.29,chromobius,00ec1b9d9ef66426fce2cf0ae1623827c00cdc126c76ca20c77a3018bb0915a8,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":43,""r"":28}", + 2135, 1003, 0, 1.85,chromobius,89d0051da1112b9069c48d40eff00e5500c47c5b82b805cd2b368b2c25fe5f1b,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":43,""r"":28}", + 2135, 1528, 0, 4.14,chromobius,89d0051da1112b9069c48d40eff00e5500c47c5b82b805cd2b368b2c25fe5f1b*00ec1b9d9ef66426fce2cf0ae1623827c00cdc126c76ca20c77a3018bb0915a8,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":43,""r"":28}", + 2061, 1017, 0, 2.04,chromobius,ab1000960fd3c871c7f747bef4846e8404ab45b55427820b29e3424e7e33e280,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":43,""r"":28}", + 2150, 1023, 0, 2.32,chromobius,0e75071a2ef118d245a2ba9796571d044ac4b4e0e40a0c76cf52a1130d5498f0,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":43,""r"":28}", + 2061, 1514, 0, 4.36,chromobius,ab1000960fd3c871c7f747bef4846e8404ab45b55427820b29e3424e7e33e280*0e75071a2ef118d245a2ba9796571d044ac4b4e0e40a0c76cf52a1130d5498f0,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":43,""r"":28}", + 2128, 1060, 0, 2.51,chromobius,72c6d08ad07f310e87984d66317d97bc697a68f88b1d981d7c13febbe03e01e6,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":43,""r"":28}", + 2036, 1019, 0, 2.46,chromobius,3dc224b2ea79a39a3f0db648544cd9c976b01ed0b144daf3a3a2ce9ab96d5ee8,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":43,""r"":28}", + 2036, 1526, 0, 4.97,chromobius,3dc224b2ea79a39a3f0db648544cd9c976b01ed0b144daf3a3a2ce9ab96d5ee8*72c6d08ad07f310e87984d66317d97bc697a68f88b1d981d7c13febbe03e01e6,"{""c"":""midout_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":43,""r"":28}", + 100000000, 550, 0, 2403.8,chromobius,bbf98c90695da3335dfe603c15558da2865c7506a6d7dec669c6a079676300d8,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":69,""r"":36}", + 100000000, 521, 0, 2336.0,chromobius,1e16179d44e84f6644d62ed1e28aa345b0170773c68def4956b4317b4c1f3f2a,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":69,""r"":36}", + 100000000, 1071, 0, 4739.8,chromobius,bbf98c90695da3335dfe603c15558da2865c7506a6d7dec669c6a079676300d8*1e16179d44e84f6644d62ed1e28aa345b0170773c68def4956b4317b4c1f3f2a,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":69,""r"":36}", + 24940366, 1082, 0, 1008.5,chromobius,cff4285a8269f8561b8c28937789cf9401c06b00203d3090e05fab44da261538,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":69,""r"":36}", + 23863356, 1023, 0, 930.4,chromobius,81598eb134b09bd0635e120bfb4cbcaf28713261f9b45d79c68dbe09e5a7b4ca,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":69,""r"":36}", + 23863356, 2058, 0, 1938.9,chromobius,81598eb134b09bd0635e120bfb4cbcaf28713261f9b45d79c68dbe09e5a7b4ca*cff4285a8269f8561b8c28937789cf9401c06b00203d3090e05fab44da261538,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":69,""r"":36}", + 7381070, 1079, 0, 414.7,chromobius,832708356fb4153d02e7549bfe0b146ccdcb75eb8679373a55db38d31772fa56,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":69,""r"":36}", + 7159030, 1006, 0, 371.6,chromobius,571a22a65a65c2c9c42787f4aa695071d8c744da166563f16112e53de64417b6,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":69,""r"":36}", + 7159030, 2052, 0, 786.3,chromobius,571a22a65a65c2c9c42787f4aa695071d8c744da166563f16112e53de64417b6*832708356fb4153d02e7549bfe0b146ccdcb75eb8679373a55db38d31772fa56,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":69,""r"":36}", + 1642833, 1110, 0, 164.4,chromobius,d1a16f3772500b17092867a333019bd203af3309c8dcd69816f2a26e057a23a3,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":69,""r"":36}", + 1444696, 1000, 0, 120.9,chromobius,998d59d45a3aa1f1108fbbdb0f350e34e7357f66044f6db6361452c53493f394,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":69,""r"":36}", + 1444696, 1975, 0, 285.3,chromobius,998d59d45a3aa1f1108fbbdb0f350e34e7357f66044f6db6361452c53493f394*d1a16f3772500b17092867a333019bd203af3309c8dcd69816f2a26e057a23a3,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":69,""r"":36}", + 553992, 1051, 0, 73.2,chromobius,ec2fb7c07a65e87c27018622cb3beb3261ad77bcd178411acc09d0f3b304d483,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":69,""r"":36}", + 554037, 1007, 0, 70.3,chromobius,94f2b410a7377fbea18180e40ff90354d2a2321e48b3681848e8e0ed715d573e,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":69,""r"":36}", + 553992, 2056, 0, 143.5,chromobius,ec2fb7c07a65e87c27018622cb3beb3261ad77bcd178411acc09d0f3b304d483*94f2b410a7377fbea18180e40ff90354d2a2321e48b3681848e8e0ed715d573e,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":69,""r"":36}", + 172968, 1038, 0, 35.3,chromobius,ebf69f72191412c7503e6a9151f6c4c74264d8ae813afc4e37f674c3549063fc,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":69,""r"":36}", + 170496, 1021, 0, 32.2,chromobius,ad2a0d50f03a3eaa7b58d04a8dce438bd8b63b804b158b13434be2bbb1fc8e25,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":69,""r"":36}", + 170496, 2038, 0, 67.5,chromobius,ad2a0d50f03a3eaa7b58d04a8dce438bd8b63b804b158b13434be2bbb1fc8e25*ebf69f72191412c7503e6a9151f6c4c74264d8ae813afc4e37f674c3549063fc,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":69,""r"":36}", + 22951, 1042, 0, 13.4,chromobius,eab45abe94841c28571cbc7d38185c9030d125a68a9106880720b439d4478f40,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":69,""r"":36}", + 23268, 1059, 0, 10.0,chromobius,536f02600480e97b48d1633236d3bd8b031baecb387b4f62f6b61d4e7892595a,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":69,""r"":36}", + 22951, 2039, 0, 23.4,chromobius,eab45abe94841c28571cbc7d38185c9030d125a68a9106880720b439d4478f40*536f02600480e97b48d1633236d3bd8b031baecb387b4f62f6b61d4e7892595a,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":69,""r"":36}", + 7538, 1036, 0, 7.55,chromobius,2294fe18333a4a23184930922d048d93d704257b07be917145032399ca7660b8,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":69,""r"":36}", + 7384, 1004, 0, 7.77,chromobius,984049ff45a88deb6f7eae76ae148fbd7745127483de0b457f3e10380eb16725,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":69,""r"":36}", + 7384, 1881, 0, 15.3,chromobius,984049ff45a88deb6f7eae76ae148fbd7745127483de0b457f3e10380eb16725*2294fe18333a4a23184930922d048d93d704257b07be917145032399ca7660b8,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":69,""r"":36}", + 2620, 1009, 0, 4.73,chromobius,8b9cf9938c9150d19d380ffaf8ba11ac342e1074a4b3655251652a7c7d120b34,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":69,""r"":36}", + 2705, 1004, 0, 4.34,chromobius,519f5ff738cbd6e95e1167423039c663226cd0646cd3039804324f7e790222e5,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":69,""r"":36}", + 2620, 1607, 0, 9.07,chromobius,8b9cf9938c9150d19d380ffaf8ba11ac342e1074a4b3655251652a7c7d120b34*519f5ff738cbd6e95e1167423039c663226cd0646cd3039804324f7e790222e5,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":69,""r"":36}", + 2230, 1002, 0, 5.57,chromobius,0ef29c8ba29ee44e888d931b389e4ff8172c4ec98590d10c36383c792db7d18d,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":69,""r"":36}", + 2324, 1029, 0, 4.29,chromobius,f29c0d2a490973d36d88447b68e24369e8d32f4ff3aaf561ec80054517a31d15,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":69,""r"":36}", + 2230, 1546, 0, 9.86,chromobius,0ef29c8ba29ee44e888d931b389e4ff8172c4ec98590d10c36383c792db7d18d*f29c0d2a490973d36d88447b68e24369e8d32f4ff3aaf561ec80054517a31d15,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":69,""r"":36}", + 2104, 1010, 0, 5.95,chromobius,6d196bf7d99847b624e1b0764811327a695ac5bf83be72b5e6b16f3972b540f6,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":69,""r"":36}", + 2100, 1036, 0, 3.91,chromobius,ba499811af13ffbff91925c9ceb87ba0a828141dc9e0c90d91a4bb27e38f9a6e,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":69,""r"":36}", + 2100, 1547, 0, 9.86,chromobius,ba499811af13ffbff91925c9ceb87ba0a828141dc9e0c90d91a4bb27e38f9a6e*6d196bf7d99847b624e1b0764811327a695ac5bf83be72b5e6b16f3972b540f6,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":69,""r"":36}", + 2141, 1050, 0, 6.94,chromobius,87d057d7a1ec5f4df047c18cee480ec887895b7d6b762393b9e6e2bea3dc9c66,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":69,""r"":36}", + 2099, 1028, 0, 4.72,chromobius,dd052a01a9c542b7d99ba0fa55e05400279f5e72c317fb0cd42ab775d2356913,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":69,""r"":36}", + 2099, 1553, 0, 11.7,chromobius,dd052a01a9c542b7d99ba0fa55e05400279f5e72c317fb0cd42ab775d2356913*87d057d7a1ec5f4df047c18cee480ec887895b7d6b762393b9e6e2bea3dc9c66,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":69,""r"":36}", + 2015, 1003, 0, 7.08,chromobius,d6f2a42c008a3177d61dbf61a9406220fa7c1b02bdb50f8da36d5525a0c4d7b3,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":69,""r"":36}", + 2000, 1059, 0, 5.54,chromobius,eb2d184f273940c20d3d087392d73f092c4cd53ac44ea88a902d72487e116c6c,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":69,""r"":36}", + 2000, 1527, 0, 12.6,chromobius,eb2d184f273940c20d3d087392d73f092c4cd53ac44ea88a902d72487e116c6c*d6f2a42c008a3177d61dbf61a9406220fa7c1b02bdb50f8da36d5525a0c4d7b3,"{""c"":""midout_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":69,""r"":36}", + 100000000, 88, 0, 4607.5,chromobius,12bc040914eb53018cadd462657c30700c527a7dc6e3794c821d2d5253755cf0,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":101,""r"":44}", + 100000000, 119, 0, 4693.5,chromobius,36b644790d6be3a8dd8e767eb96ee025fe8b181afbdc473c5f3544837c0336d6,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":101,""r"":44}", + 100000000, 207, 0, 9301.0,chromobius,12bc040914eb53018cadd462657c30700c527a7dc6e3794c821d2d5253755cf0*36b644790d6be3a8dd8e767eb96ee025fe8b181afbdc473c5f3544837c0336d6,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":101,""r"":44}", + 100000000, 881, 0, 7743.7,chromobius,b6ec735825d9024f00a355bca449c93e508b6ee178f08fe0b12900fbd4f92293,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":101,""r"":44}", + 100000000, 908, 0, 7949.6,chromobius,d10eac5ef4d914ca8c233a985aa16df4afd8aeae6bbb50d1416ac9042c239731,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":101,""r"":44}", + 100000000, 1789, 0, 15693.3,chromobius,b6ec735825d9024f00a355bca449c93e508b6ee178f08fe0b12900fbd4f92293*d10eac5ef4d914ca8c233a985aa16df4afd8aeae6bbb50d1416ac9042c239731,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":101,""r"":44}", + 29929457, 1009, 0, 3336.6,chromobius,d0347ce5c9c430f969387bbb5560a97f8efea5b81bb3db6ffa22c321f3fee099,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":101,""r"":44}", + 31106755, 1027, 0, 3484.1,chromobius,ab8b6c5731519fc146e8c715cf59028db954dca568f67ead1e411adb6175908b,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":101,""r"":44}", + 29929457, 1997, 0, 6820.7,chromobius,d0347ce5c9c430f969387bbb5560a97f8efea5b81bb3db6ffa22c321f3fee099*ab8b6c5731519fc146e8c715cf59028db954dca568f67ead1e411adb6175908b,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":101,""r"":44}", + 5379538, 1010, 0, 1096.7,chromobius,fdd4a386ff5b731e4c48b9525ce95e37bb53fd8297ad82ec2f29f7c835d94a0c,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":101,""r"":44}", + 5179230, 1006, 0, 928.5,chromobius,4a3e55f1fe85ce18b75ef1be5934d5f0cac0494929aa8059eed5810a54b365af,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":101,""r"":44}", + 5179230, 1978, 0, 2025.2,chromobius,4a3e55f1fe85ce18b75ef1be5934d5f0cac0494929aa8059eed5810a54b365af*fdd4a386ff5b731e4c48b9525ce95e37bb53fd8297ad82ec2f29f7c835d94a0c,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":101,""r"":44}", + 1669739, 1016, 0, 428.7,chromobius,1ec8ca10f186c49889e2ced35f42a129221df98c808a3b4cbd45dbe369b15547,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":101,""r"":44}", + 1659890, 1002, 0, 423.0,chromobius,42064af0eced562a5d9ed93675d4b604a0d7db6c8c1d79ad787717a3447ff0a8,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":101,""r"":44}", + 1659890, 2011, 0, 851.7,chromobius,42064af0eced562a5d9ed93675d4b604a0d7db6c8c1d79ad787717a3447ff0a8*1ec8ca10f186c49889e2ced35f42a129221df98c808a3b4cbd45dbe369b15547,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":101,""r"":44}", + 451602, 1002, 0, 198.1,chromobius,1ba5216e8f89b8f54853a30d741c1bbb4ddba70e6025fae47c5820ce1b4d8af6,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":101,""r"":44}", + 459136, 1006, 0, 172.2,chromobius,ebcb27e4ecd2ac20dee1a8a7705a6367855de8db2dcdb558283c16b4cc2cc585,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":101,""r"":44}", + 451602, 1989, 0, 370.3,chromobius,1ba5216e8f89b8f54853a30d741c1bbb4ddba70e6025fae47c5820ce1b4d8af6*ebcb27e4ecd2ac20dee1a8a7705a6367855de8db2dcdb558283c16b4cc2cc585,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":101,""r"":44}", + 37175, 1012, 0, 39.7,chromobius,ef2dadee0ba4c48b27221b98a347f07f2a572ca1815485afa92e98858a46923d,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":101,""r"":44}", + 37919, 1061, 0, 36.1,chromobius,e52ddd722302518c00683a7db04ff39ce689459d33fbf88376460a9ab9b0f4ea,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":101,""r"":44}", + 37175, 2024, 0, 75.8,chromobius,ef2dadee0ba4c48b27221b98a347f07f2a572ca1815485afa92e98858a46923d*e52ddd722302518c00683a7db04ff39ce689459d33fbf88376460a9ab9b0f4ea,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":101,""r"":44}", + 9184, 1005, 0, 21.0,chromobius,a3781ca09f34535e9235f79b4c31d03b09ce86cf1535614481374146810d0ccb,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":101,""r"":44}", + 9749, 1107, 0, 16.6,chromobius,58707a48ea5f0044b7fc1e5d0c5f6e95d205fd8d0818245825a152de6c58a94b,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":101,""r"":44}", + 9184, 1934, 0, 37.6,chromobius,a3781ca09f34535e9235f79b4c31d03b09ce86cf1535614481374146810d0ccb*58707a48ea5f0044b7fc1e5d0c5f6e95d205fd8d0818245825a152de6c58a94b,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":101,""r"":44}", + 2731, 1031, 0, 13.1,chromobius,4d3f1ec21ec40b790b036fe1b6bc02f088bdddced4798dd0922de60ce1b46111,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":101,""r"":44}", + 2730, 1030, 0, 8.96,chromobius,04cbe46ba6b8e031d718ede7223df56c8eca44001d5e698fdd19907435322b1b,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":101,""r"":44}", + 2730, 1672, 0, 22.1,chromobius,04cbe46ba6b8e031d718ede7223df56c8eca44001d5e698fdd19907435322b1b*4d3f1ec21ec40b790b036fe1b6bc02f088bdddced4798dd0922de60ce1b46111,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":101,""r"":44}", + 2168, 1016, 0, 10.6,chromobius,599dbd3df7f50b2f5ea9548fc9aea6c1b65292f6b84cbd0d765520464d2ed977,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":101,""r"":44}", + 2191, 1028, 0, 9.40,chromobius,8c44fdc0851edcc42f2879b1106e32bbc783eb5d5c4e82182f094d44f6739162,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":101,""r"":44}", + 2168, 1557, 0, 20.0,chromobius,599dbd3df7f50b2f5ea9548fc9aea6c1b65292f6b84cbd0d765520464d2ed977*8c44fdc0851edcc42f2879b1106e32bbc783eb5d5c4e82182f094d44f6739162,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":101,""r"":44}", + 2018, 1003, 0, 11.4,chromobius,3cd1cf70bf549ebcc63b7bd4071d780b7dd09bb1e9d43ed95ef173efaec65255,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":101,""r"":44}", + 2033, 1003, 0, 10.9,chromobius,d95a1131c0284f88092ef645aa5d4076ba96ed72fab36b77cb3152e18b62fe53,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":101,""r"":44}", + 2018, 1504, 0, 22.3,chromobius,3cd1cf70bf549ebcc63b7bd4071d780b7dd09bb1e9d43ed95ef173efaec65255*d95a1131c0284f88092ef645aa5d4076ba96ed72fab36b77cb3152e18b62fe53,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":101,""r"":44}", + 2016, 1004, 0, 12.2,chromobius,01d7b59f7e77172fd38b89758f2f3a07d4447d5cf5854bba469c67996a622a79,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":101,""r"":44}", + 2056, 1009, 0, 11.9,chromobius,3ebb9c0eb724371fb8a379925f7ab85ee91dbde8265f90673fa11a3a83a2c5a3,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":101,""r"":44}", + 2016, 1501, 0, 24.1,chromobius,01d7b59f7e77172fd38b89758f2f3a07d4447d5cf5854bba469c67996a622a79*3ebb9c0eb724371fb8a379925f7ab85ee91dbde8265f90673fa11a3a83a2c5a3,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":101,""r"":44}", + 2064, 1027, 0, 18.5,chromobius,59e368c03ba6213e19fa7a396263dc8f0720729e6c9ea4775b0aedd88e7914c4,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":101,""r"":44}", + 2072, 1015, 0, 14.3,chromobius,0ab6b34b3a6846a7bc42c2f439636e5b9e1b09e429a0b9abd9c9d3aff135dd93,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":101,""r"":44}", + 2064, 1535, 0, 32.8,chromobius,59e368c03ba6213e19fa7a396263dc8f0720729e6c9ea4775b0aedd88e7914c4*0ab6b34b3a6846a7bc42c2f439636e5b9e1b09e429a0b9abd9c9d3aff135dd93,"{""c"":""midout_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":101,""r"":44}", + 100000000, 6, 0, 8303.5,chromobius,11fa4a8537525a6da132baf377d10c9fd1ecbfbae91b504e8607b1656f71826b,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":139,""r"":52}", + 100000000, 1, 0, 8502.6,chromobius,c71e5cee0af61de4c37c0ef0a6ca8ef9bf95f1149777300c7f10e5b4778587fb,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":139,""r"":52}", + 100000000, 7, 0, 16806.1,chromobius,11fa4a8537525a6da132baf377d10c9fd1ecbfbae91b504e8607b1656f71826b*c71e5cee0af61de4c37c0ef0a6ca8ef9bf95f1149777300c7f10e5b4778587fb,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":139,""r"":52}", + 100000000, 80, 0, 14694.5,chromobius,e951d5ab6226cb25c903beca8c50797d7c960ec135ab807c6a420003516b4627,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":139,""r"":52}", + 100000000, 90, 0, 14715.0,chromobius,8df23a1ea7715bf2eb92557fe887529a00f35e0cde526cc0a5fed9c8ca2ec446,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":139,""r"":52}", + 100000000, 170, 0, 29409.5,chromobius,e951d5ab6226cb25c903beca8c50797d7c960ec135ab807c6a420003516b4627*8df23a1ea7715bf2eb92557fe887529a00f35e0cde526cc0a5fed9c8ca2ec446,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":139,""r"":52}", + 100000000, 458, 0, 21259.8,chromobius,b6364c6db7e6fe53373bd57c0c5e33dacd79208a409bcc4026ac179b5d6daafd,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":139,""r"":52}", + 100000000, 447, 0, 21017.9,chromobius,5868471e5431445e739606bcac17e2094204e1c83421bcb4ee791251290eee0a,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":139,""r"":52}", + 100000000, 905, 0, 42277.7,chromobius,b6364c6db7e6fe53373bd57c0c5e33dacd79208a409bcc4026ac179b5d6daafd*5868471e5431445e739606bcac17e2094204e1c83421bcb4ee791251290eee0a,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":139,""r"":52}", + 24574786, 1024, 0, 8666.7,chromobius,b265bdbc5d8c55cf1c4278e8630d8d49525ad35967f71038fba9a2eaa7d4e2ff,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":139,""r"":52}", + 26491594, 1068, 0, 9292.3,chromobius,4560e7c7629ae1fb8872c64ba12c27aba9c5aa03d57cbf00865b8afd0d198f1e,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":139,""r"":52}", + 24574786, 2015, 0, 17959.0,chromobius,b265bdbc5d8c55cf1c4278e8630d8d49525ad35967f71038fba9a2eaa7d4e2ff*4560e7c7629ae1fb8872c64ba12c27aba9c5aa03d57cbf00865b8afd0d198f1e,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":139,""r"":52}", + 6013934, 1015, 0, 2951.9,chromobius,dca188490108986568e3c8c82348c043bef5fda9f2827c9f4e3cdda21b3efc7b,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":139,""r"":52}", + 5814578, 1003, 0, 2870.2,chromobius,e56f4b4e9588ed64dd9b587094ddb31942ad0b1d53c5f903a465dd5ef4a944e7,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":139,""r"":52}", + 5814578, 1984, 0, 5822.1,chromobius,e56f4b4e9588ed64dd9b587094ddb31942ad0b1d53c5f903a465dd5ef4a944e7*dca188490108986568e3c8c82348c043bef5fda9f2827c9f4e3cdda21b3efc7b,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":139,""r"":52}", + 1261889, 1003, 0, 979.6,chromobius,b0c43b360ff89f67458784e63908430a932f1ea716f4a9f82c1bad3f5e314525,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":139,""r"":52}", + 1265099, 1006, 0, 915.0,chromobius,419d81247cd8c0fa2da8762d2e82b8acd51963dec4b231a78c5b55cec8060913,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":139,""r"":52}", + 1261889, 2006, 0, 1894.6,chromobius,b0c43b360ff89f67458784e63908430a932f1ea716f4a9f82c1bad3f5e314525*419d81247cd8c0fa2da8762d2e82b8acd51963dec4b231a78c5b55cec8060913,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":139,""r"":52}", + 64006, 1012, 0, 113.7,chromobius,fcf3313594355c9bb31cf6830830bb4fe31c889f43e608a9e0a76835ab6d70d7,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":139,""r"":52}", + 64481, 1087, 0, 103.2,chromobius,3b7a395fef8f5e479b4f01cf116340e7a1472f784c9949db17d23f419055cb8d,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":139,""r"":52}", + 64006, 2074, 0, 216.9,chromobius,fcf3313594355c9bb31cf6830830bb4fe31c889f43e608a9e0a76835ab6d70d7*3b7a395fef8f5e479b4f01cf116340e7a1472f784c9949db17d23f419055cb8d,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":139,""r"":52}", + 11429, 1022, 0, 34.3,chromobius,e25addba3fb3092f5b48c0443d2f801bd015672a2a560af9ad4a46556a15c5ce,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":139,""r"":52}", + 11888, 1006, 0, 36.4,chromobius,3de7b34325d0f8f5df393b684e08edf86e8031fdd3b13f0e70e8f4794834687e,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":139,""r"":52}", + 11429, 1903, 0, 70.7,chromobius,e25addba3fb3092f5b48c0443d2f801bd015672a2a560af9ad4a46556a15c5ce*3de7b34325d0f8f5df393b684e08edf86e8031fdd3b13f0e70e8f4794834687e,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":139,""r"":52}", + 2816, 1003, 0, 18.6,chromobius,92f7f4116b69e62a9db0c8a076cbd62406ac457668cc3a11b7378f5cda5eedb7,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":139,""r"":52}", + 2618, 1044, 0, 17.3,chromobius,fe81bec1a770a2ebaac7f955f29d9cf6c4ab5c10c82891f6c7373647bd7c404b,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":139,""r"":52}", + 2618, 1605, 0, 35.9,chromobius,fe81bec1a770a2ebaac7f955f29d9cf6c4ab5c10c82891f6c7373647bd7c404b*92f7f4116b69e62a9db0c8a076cbd62406ac457668cc3a11b7378f5cda5eedb7,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":139,""r"":52}", + 2194, 1058, 0, 19.7,chromobius,c2a9a4e19345cf800842bf0049f78e731b2842e204c89d92d5004f11fb9ab536,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":139,""r"":52}", + 2296, 1079, 0, 19.8,chromobius,047b46d596270ba09adb22e96c4af5e922b8527d97d14e8cc280a4739661d19a,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":139,""r"":52}", + 2194, 1592, 0, 39.5,chromobius,c2a9a4e19345cf800842bf0049f78e731b2842e204c89d92d5004f11fb9ab536*047b46d596270ba09adb22e96c4af5e922b8527d97d14e8cc280a4739661d19a,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":139,""r"":52}", + 2054, 1032, 0, 21.6,chromobius,0a6752b0b4a169b2e997f8f14d30a413ae5d0fee818d3365107ad8c80d668bf6,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":139,""r"":52}", + 2208, 1077, 0, 21.8,chromobius,e0d118dd3bdff5492c0fb09c33550056c575d2b984ba11be4732fc0da919828e,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":139,""r"":52}", + 2054, 1531, 0, 43.4,chromobius,0a6752b0b4a169b2e997f8f14d30a413ae5d0fee818d3365107ad8c80d668bf6*e0d118dd3bdff5492c0fb09c33550056c575d2b984ba11be4732fc0da919828e,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":139,""r"":52}", + 1923, 1014, 0, 23.1,chromobius,ba35b4175057a67b3fe82a0d80909bd15700aa44542f14f56402ce85df969b6a,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":139,""r"":52}", + 2016, 1009, 0, 23.3,chromobius,1afa6226f411c0fc796b51f5db1e5011131a86aa50d4b02f82959849acf8b477,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":139,""r"":52}", + 1923, 1469, 0, 46.4,chromobius,ba35b4175057a67b3fe82a0d80909bd15700aa44542f14f56402ce85df969b6a*1afa6226f411c0fc796b51f5db1e5011131a86aa50d4b02f82959849acf8b477,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":139,""r"":52}", + 1939, 1006, 0, 33.1,chromobius,8876a62c36d5ec00f472c9adb6942754666ea9a3e64e57446ab4b1e6be681b83,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":139,""r"":52}", + 2054, 1001, 0, 36.3,chromobius,fc3fe81e7c32721af0ed853be3b632741bf3a99de470d6e1da6af7ffb4f611cc,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":139,""r"":52}", + 1939, 1461, 0, 69.4,chromobius,8876a62c36d5ec00f472c9adb6942754666ea9a3e64e57446ab4b1e6be681b83*fc3fe81e7c32721af0ed853be3b632741bf3a99de470d6e1da6af7ffb4f611cc,"{""c"":""midout_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":139,""r"":52}", + 100000000, 1, 0, 14056.4,chromobius,39556819fc00137e901699d3985b77d46286134e3f35af8e563858b3386db766,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":183,""r"":60}", + 100000000, 1, 0, 13903.4,chromobius,df2bcb2be2b781d8e4a110373648b17c815973f46c7bccd33d0f1a71d3bbca32,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":183,""r"":60}", + 100000000, 2, 0, 27959.8,chromobius,39556819fc00137e901699d3985b77d46286134e3f35af8e563858b3386db766*df2bcb2be2b781d8e4a110373648b17c815973f46c7bccd33d0f1a71d3bbca32,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":183,""r"":60}", + 100000000, 14, 0, 24712.8,chromobius,31a512cef9e54722251a8eb03012a338ed41414c15552ae5e2be675fb35400a5,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":183,""r"":60}", + 100000000, 13, 0, 24255.1,chromobius,7c43faf77d331d47b0a672e07640a6855e076f3521a939c2ca1d383e706b9601,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":183,""r"":60}", + 100000000, 27, 0, 48967.9,chromobius,31a512cef9e54722251a8eb03012a338ed41414c15552ae5e2be675fb35400a5*7c43faf77d331d47b0a672e07640a6855e076f3521a939c2ca1d383e706b9601,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":183,""r"":60}", + 100000000, 67, 0, 35127.1,chromobius,4098252749ac3fd4923d549cb3314252aec1112cb5354580dc3f436f381fd381,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":183,""r"":60}", + 100000000, 91, 0, 34941.2,chromobius,1ec5148c23c8a066fc6bd90c8ae56fbdf476f064cb2d23a84ce637d25395a41c,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":183,""r"":60}", + 100000000, 158, 0, 70068.3,chromobius,4098252749ac3fd4923d549cb3314252aec1112cb5354580dc3f436f381fd381*1ec5148c23c8a066fc6bd90c8ae56fbdf476f064cb2d23a84ce637d25395a41c,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":183,""r"":60}", + 100000000, 844, 0, 57426.8,chromobius,8d96d650475b66d3a12d8ddfd04d31a52db644d85662fd31378834b8c2693132,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":183,""r"":60}", + 100000000, 874, 0, 57273.7,chromobius,d37641f493952b9aaacf8d514e76f881f5973f6ff5802d468a1cbf2267463e74,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":183,""r"":60}", + 100000000, 1718, 0,114700.5,chromobius,8d96d650475b66d3a12d8ddfd04d31a52db644d85662fd31378834b8c2693132*d37641f493952b9aaacf8d514e76f881f5973f6ff5802d468a1cbf2267463e74,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":183,""r"":60}", + 23117529, 1003, 0, 18778.3,chromobius,f50511af55697152f8cb826aa88e6d9d0e73d6b15164d5df6785e92adb478172,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":183,""r"":60}", + 23574688, 1008, 0, 19218.4,chromobius,98cccaa1719a9b6d85fac16484fdcf7a4587fda2839e0ac50de4d2da0c5a3570,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":183,""r"":60}", + 23117529, 1991, 0, 37996.7,chromobius,f50511af55697152f8cb826aa88e6d9d0e73d6b15164d5df6785e92adb478172*98cccaa1719a9b6d85fac16484fdcf7a4587fda2839e0ac50de4d2da0c5a3570,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":183,""r"":60}", + 3632067, 1020, 0, 4422.7,chromobius,615553fb1cc726aaffa4806c65001b9a842390bf4a996f12ecc374267198da5a,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":183,""r"":60}", + 3984997, 1063, 0, 4761.8,chromobius,58c11737a48e068b5f5bfe2bf303562dd966efe466f1ee195531bbc9dfed2c50,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":183,""r"":60}", + 3632067, 1989, 0, 9184.5,chromobius,615553fb1cc726aaffa4806c65001b9a842390bf4a996f12ecc374267198da5a*58c11737a48e068b5f5bfe2bf303562dd966efe466f1ee195531bbc9dfed2c50,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":183,""r"":60}", + 110523, 1023, 0, 291.1,chromobius,70e5d3802594a11364adea78d318e90135b539677db56f9213a56d4e54885f3e,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":183,""r"":60}", + 117238, 1039, 0, 314.6,chromobius,4d2b9359950dcb933959257cd7ba970acc3910f760ac385ff330e62ec2885f52,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":183,""r"":60}", + 110523, 1993, 0, 605.7,chromobius,70e5d3802594a11364adea78d318e90135b539677db56f9213a56d4e54885f3e*4d2b9359950dcb933959257cd7ba970acc3910f760ac385ff330e62ec2885f52,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":183,""r"":60}", + 16182, 1053, 0, 75.6,chromobius,65ec72c03fcfaa971ce0a63dac5b9834f9762ad84a77a0db03e1135e7ead1cbc,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":183,""r"":60}", + 14920, 1005, 0, 75.5,chromobius,bb850c01a65229a3dc37ef41e7c055dbc3829e608ac466fb49d058f5c6985b89,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":183,""r"":60}", + 14920, 1910, 0, 151.1,chromobius,bb850c01a65229a3dc37ef41e7c055dbc3829e608ac466fb49d058f5c6985b89*65ec72c03fcfaa971ce0a63dac5b9834f9762ad84a77a0db03e1135e7ead1cbc,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":183,""r"":60}", + 2598, 1038, 0, 29.4,chromobius,0b58068615ae919c0344fe2e80215c1d64def2b4c68bb872f073b5cd96294182,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":183,""r"":60}", + 2615, 1004, 0, 30.9,chromobius,90748bb150920b4a5bfbd3d8c9e227cda1bd256a1876b509c678c95029799b07,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":183,""r"":60}", + 2598, 1637, 0, 60.3,chromobius,0b58068615ae919c0344fe2e80215c1d64def2b4c68bb872f073b5cd96294182*90748bb150920b4a5bfbd3d8c9e227cda1bd256a1876b509c678c95029799b07,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":183,""r"":60}", + 2108, 1030, 0, 32.5,chromobius,c38e6664ad0398ba09748cb3e51d9040be0b5d916d38619d3aa939610943f003,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":183,""r"":60}", + 2077, 1004, 0, 53.2,chromobius,3a7b8f4c234bd427a4cdb30fda08421db09b0924ae2293e13a85c4ab51a34643,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":183,""r"":60}", + 2077, 1528, 0, 85.7,chromobius,3a7b8f4c234bd427a4cdb30fda08421db09b0924ae2293e13a85c4ab51a34643*c38e6664ad0398ba09748cb3e51d9040be0b5d916d38619d3aa939610943f003,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":183,""r"":60}", + 2114, 1036, 0, 41.1,chromobius,217458492d9501c4c5151188355214c31339b96c8919b165eae93f5b10f4ed97,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":183,""r"":60}", + 2225, 1056, 0, 44.4,chromobius,bcc96e6bf15d7917420df77c5b13cd8c7d6e09cf618eee4e4a5f2877e3b66c8c,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":183,""r"":60}", + 2114, 1548, 0, 85.5,chromobius,217458492d9501c4c5151188355214c31339b96c8919b165eae93f5b10f4ed97*bcc96e6bf15d7917420df77c5b13cd8c7d6e09cf618eee4e4a5f2877e3b66c8c,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":183,""r"":60}", + 2057, 1023, 0, 44.1,chromobius,c56c94d8184b5944e85e62e8f37642aff7a88f89732d8c8e97f6ed8cf773c774,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":183,""r"":60}", + 2008, 1004, 0, 50.4,chromobius,8c77ddf8fc046b147682ab3e9702c6d33e181cbccb42e3ff89f6974a14f4ec5e,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":183,""r"":60}", + 2008, 1503, 0, 94.5,chromobius,8c77ddf8fc046b147682ab3e9702c6d33e181cbccb42e3ff89f6974a14f4ec5e*c56c94d8184b5944e85e62e8f37642aff7a88f89732d8c8e97f6ed8cf773c774,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":183,""r"":60}", + 2044, 1001, 0, 68.0,chromobius,2768359b047c748102e1734f35536abc163572ec01b3c1ab2980428d69e119d4,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":183,""r"":60}", + 1987, 1002, 0, 64.2,chromobius,2074e18793f5aafa004cf694e6ada8118f01f259ffb9ca70945d4329ff0ad938,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":183,""r"":60}", + 1987, 1484, 0, 132.2,chromobius,2074e18793f5aafa004cf694e6ada8118f01f259ffb9ca70945d4329ff0ad938*2768359b047c748102e1734f35536abc163572ec01b3c1ab2980428d69e119d4,"{""c"":""midout_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":183,""r"":60}", + 100000000, 0, 0, 21348.6,chromobius,f1932f66daacfdf0f437d3eaa596f0d54d20c96bd3c5681540ae1db75f24886f,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":233,""r"":68}", + 100000000, 0, 0, 21272.4,chromobius,49f66d7b12a5055bb90d125396da32f8db4320fafa6c94c0bfe9367e14d98506,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":233,""r"":68}", + 100000000, 0, 0, 42621.0,chromobius,f1932f66daacfdf0f437d3eaa596f0d54d20c96bd3c5681540ae1db75f24886f*49f66d7b12a5055bb90d125396da32f8db4320fafa6c94c0bfe9367e14d98506,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":233,""r"":68}", + 100000000, 0, 0, 38095.6,chromobius,909a073d9c06855a675e2ffa33e72d04c633a095c30a36b3b312790af8ecd4a8,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":233,""r"":68}", + 100000000, 0, 0, 37855.6,chromobius,c8935abf8066b3c5990626155aa4d58bd29b678fb1a460914cf96d6e000e6e2d,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":233,""r"":68}", + 100000000, 0, 0, 75951.2,chromobius,909a073d9c06855a675e2ffa33e72d04c633a095c30a36b3b312790af8ecd4a8*c8935abf8066b3c5990626155aa4d58bd29b678fb1a460914cf96d6e000e6e2d,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":233,""r"":68}", + 100000000, 11, 0, 55371.9,chromobius,5698ab310881a3ae78bc702b93aedbce7c62ae22c5f9f61714a87286a051fca3,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":233,""r"":68}", + 100000000, 9, 0, 54949.7,chromobius,9d8fbd9e2542ae95f69df924cdece55442a4b5102768d6826a645daa1bbd5052,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":233,""r"":68}", + 100000000, 20, 0,110321.6,chromobius,5698ab310881a3ae78bc702b93aedbce7c62ae22c5f9f61714a87286a051fca3*9d8fbd9e2542ae95f69df924cdece55442a4b5102768d6826a645daa1bbd5052,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":233,""r"":68}", + 100000000, 180, 0, 90265.3,chromobius,ced803f00600e88155a48a3a5539f16e66029dc36146cb21d4dc571bd2883df4,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":233,""r"":68}", + 100000000, 151, 0, 90198.9,chromobius,8657121ea124e822254de16d73f5ac79a6b2c95cd86741544815c5cafb44c03a,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":233,""r"":68}", + 100000000, 331, 0,180464.2,chromobius,ced803f00600e88155a48a3a5539f16e66029dc36146cb21d4dc571bd2883df4*8657121ea124e822254de16d73f5ac79a6b2c95cd86741544815c5cafb44c03a,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":233,""r"":68}", + 95931055, 1006, 0,121319.4,chromobius,e2af04cb5c2636d6605cc26e36ef1ece7659188d3819e5f8c8528e98ab891cd2,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":233,""r"":68}", + 85023316, 1003, 0,106732.3,chromobius,590e12cfbbb071d53b860967e02a50d8c6fa2ff478d8a4313366eab92365a8d6,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":233,""r"":68}", + 85023316, 1895, 0,228051.7,chromobius,590e12cfbbb071d53b860967e02a50d8c6fa2ff478d8a4313366eab92365a8d6*e2af04cb5c2636d6605cc26e36ef1ece7659188d3819e5f8c8528e98ab891cd2,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":233,""r"":68}", + 11217632, 1037, 0, 21032.3,chromobius,ca21e98a394fb28a987bbc3afe9e88fbf00980d5eb96e17014b1354b9c658747,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":233,""r"":68}", + 11931380, 1021, 0, 21888.7,chromobius,301fa3d415e89fbe6a70b1b57357b43dd0893e350953807c54f46ffb4c35c848,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":233,""r"":68}", + 11217632, 1997, 0, 42921.0,chromobius,ca21e98a394fb28a987bbc3afe9e88fbf00980d5eb96e17014b1354b9c658747*301fa3d415e89fbe6a70b1b57357b43dd0893e350953807c54f46ffb4c35c848,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":233,""r"":68}", + 223055, 1073, 0, 923.1,chromobius,d49064829e951cdaa8d3342119739bfbe268ee585c4984f37371d9ef9bf2c2e4,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":233,""r"":68}", + 234924, 1166, 0, 953.5,chromobius,31ddbf0445e7aa707fa45753afe4761f367ead319827839324b252c217efc94a,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":233,""r"":68}", + 223055, 2175, 0, 1876.6,chromobius,d49064829e951cdaa8d3342119739bfbe268ee585c4984f37371d9ef9bf2c2e4*31ddbf0445e7aa707fa45753afe4761f367ead319827839324b252c217efc94a,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":233,""r"":68}", + 20202, 1016, 0, 178.2,chromobius,a003d3b9689527023865f526ab6f9e538a504b13fbc55cf5d5f5ede0f5689d2e,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":233,""r"":68}", + 22289, 1111, 0, 183.7,chromobius,36b17b581d019ee020a258284668a1fa0576a310d88df350641585756b000d69,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":233,""r"":68}", + 20202, 1972, 0, 361.9,chromobius,a003d3b9689527023865f526ab6f9e538a504b13fbc55cf5d5f5ede0f5689d2e*36b17b581d019ee020a258284668a1fa0576a310d88df350641585756b000d69,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":233,""r"":68}", + 2569, 1014, 0, 56.5,chromobius,da745027cfa33604f9b9cc66a9b59ca11b7435b7561f3747f994b4c3d11c26c8,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":233,""r"":68}", + 2587, 1050, 0, 49.3,chromobius,42cf88c8a26adaded845264c1514f0f8a4482eec9bb642a8286aa4abada5fbf8,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":233,""r"":68}", + 2569, 1645, 0, 105.8,chromobius,da745027cfa33604f9b9cc66a9b59ca11b7435b7561f3747f994b4c3d11c26c8*42cf88c8a26adaded845264c1514f0f8a4482eec9bb642a8286aa4abada5fbf8,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":233,""r"":68}", + 2071, 1003, 0, 66.2,chromobius,04e58068070f6e2fa7e0dc2de471b888fd3ff833e88956f56d02ce1f50ffc4e2,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":233,""r"":68}", + 2075, 1000, 0, 59.5,chromobius,6095a8064503dd0a69fda86b9db7ba5d2cd5dc715e3f355fc14d76a51bcdd3e8,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":233,""r"":68}", + 2071, 1518, 0, 125.7,chromobius,04e58068070f6e2fa7e0dc2de471b888fd3ff833e88956f56d02ce1f50ffc4e2*6095a8064503dd0a69fda86b9db7ba5d2cd5dc715e3f355fc14d76a51bcdd3e8,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":233,""r"":68}", + 2082, 1064, 0, 65.9,chromobius,47c0b93ff9c1133552c945b984465d6cae0db1f8edc149e1f9a7629a74e1f716,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":233,""r"":68}", + 1947, 1003, 0, 72.5,chromobius,45c52b49f246785963bf0bc51703595cbe26f74c0ec8ab55573012ce90608745,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":233,""r"":68}", + 1947, 1485, 0, 138.4,chromobius,45c52b49f246785963bf0bc51703595cbe26f74c0ec8ab55573012ce90608745*47c0b93ff9c1133552c945b984465d6cae0db1f8edc149e1f9a7629a74e1f716,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":233,""r"":68}", + 2119, 1058, 0, 95.2,chromobius,3572192f6be7b89fd3e6b3fe95d121c784383278f797d936de05cf4a0999b586,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":233,""r"":68}", + 2026, 1001, 0, 90.6,chromobius,522a38c7b17326ee9083ee135caf7fa31e0250e8c7433b3d4c94e1b4c7c6237b,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":233,""r"":68}", + 2026, 1513, 0, 185.8,chromobius,522a38c7b17326ee9083ee135caf7fa31e0250e8c7433b3d4c94e1b4c7c6237b*3572192f6be7b89fd3e6b3fe95d121c784383278f797d936de05cf4a0999b586,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":233,""r"":68}", + 2028, 1003, 0, 128.4,chromobius,488ba7fd5d302034d99cf495aa170a647ad15061cc5e831df998c355cbd104b4,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":233,""r"":68}", + 1926, 1000, 0, 124.1,chromobius,15d912bfa4a732d3c87d935f6c276293fae9a304f84f811899dbf6eebf280470,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":233,""r"":68}", + 1926, 1458, 0, 252.5,chromobius,15d912bfa4a732d3c87d935f6c276293fae9a304f84f811899dbf6eebf280470*488ba7fd5d302034d99cf495aa170a647ad15061cc5e831df998c355cbd104b4,"{""c"":""midout_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":233,""r"":68}", + 100000000, 0, 0, 30983.7,chromobius,32d80cc4414c7209ac932c5862d5ac7e5631ca5923fbf859ed8ebf3e585684b0,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":289,""r"":76}", + 100000000, 0, 0, 30885.5,chromobius,97414b9215d1039fa5955adbbbda3abf4ce8aaceefe12b14581ca281cfeed3b9,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":289,""r"":76}", + 100000000, 0, 0, 61869.2,chromobius,32d80cc4414c7209ac932c5862d5ac7e5631ca5923fbf859ed8ebf3e585684b0*97414b9215d1039fa5955adbbbda3abf4ce8aaceefe12b14581ca281cfeed3b9,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":289,""r"":76}", + 100000000, 0, 0, 55528.4,chromobius,36bfa56d1a4a18a17cc91bd813bf945d474465c33021f7c513620372bf53cb62,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":289,""r"":76}", + 100000000, 0, 0, 55454.1,chromobius,a2aff099e95945aa9650d28175e9c69620d4a1c0d64006cb4fb422efbcac5ec0,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":289,""r"":76}", + 100000000, 0, 0,110982.5,chromobius,36bfa56d1a4a18a17cc91bd813bf945d474465c33021f7c513620372bf53cb62*a2aff099e95945aa9650d28175e9c69620d4a1c0d64006cb4fb422efbcac5ec0,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":289,""r"":76}", + 100000000, 0, 0, 80836.6,chromobius,bde3ed8f8b6be584572bfa160ec0afe67013d3e5bd29cf360fce89438bc078c1,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":289,""r"":76}", + 100000000, 2, 0, 80358.2,chromobius,5a36c176b76624a079e7bbac6ffc36deb1a50e1a24cafa4119666afc91876965,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":289,""r"":76}", + 100000000, 2, 0,161194.8,chromobius,bde3ed8f8b6be584572bfa160ec0afe67013d3e5bd29cf360fce89438bc078c1*5a36c176b76624a079e7bbac6ffc36deb1a50e1a24cafa4119666afc91876965,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":289,""r"":76}", + 100000000, 30, 0,132645.9,chromobius,fb13a064ae16fe72025ed7fdc403f7e386fc6f02f4bdc4cfb37aa2a6a594f6ec,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":289,""r"":76}", + 100000000, 33, 0,132351.5,chromobius,5461a505614679663f5052118742c1c6963842add67a26d893114184ec2df66c,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":289,""r"":76}", + 100000000, 63, 0,264997.4,chromobius,fb13a064ae16fe72025ed7fdc403f7e386fc6f02f4bdc4cfb37aa2a6a594f6ec*5461a505614679663f5052118742c1c6963842add67a26d893114184ec2df66c,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":289,""r"":76}", + 100000000, 292, 0,186061.4,chromobius,e2151757c6be0be74a0c33adfcb67172dd61e913c899bf8f4f9479306b9cbe1b,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":289,""r"":76}", + 100000000, 272, 0,185662.2,chromobius,4982268e5441ae58b455230cee8751d3e9c3668d8a297557ebdefa8f1a759d06,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":289,""r"":76}", + 100000000, 564, 0,371723.6,chromobius,e2151757c6be0be74a0c33adfcb67172dd61e913c899bf8f4f9479306b9cbe1b*4982268e5441ae58b455230cee8751d3e9c3668d8a297557ebdefa8f1a759d06,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":289,""r"":76}", + 35111265, 1010, 0, 96800.4,chromobius,1d3deb57b24a360ba5a9bb7c4a6814c1c810defcf24443f1b4eb40e04206d3e6,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":289,""r"":76}", + 36660419, 1006, 0,102573.0,chromobius,6891aef6a2ccee349fdac760af57bf65cc327caa26975388f44a5506b4fe8198,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":289,""r"":76}", + 35111265, 1973, 0,199373.4,chromobius,1d3deb57b24a360ba5a9bb7c4a6814c1c810defcf24443f1b4eb40e04206d3e6*6891aef6a2ccee349fdac760af57bf65cc327caa26975388f44a5506b4fe8198,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":289,""r"":76}", + 369537, 1005, 0, 2415.3,chromobius,6f33555ca1ab8bba3643a57043b6a2a1eef8be48955be36d936255bc412488e3,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":289,""r"":76}", + 369977, 1006, 0, 2473.1,chromobius,328da22d9deabea21019862d6539230c135368f9572d278f937eb63dca6f657a,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":289,""r"":76}", + 369537, 2007, 0, 4888.4,chromobius,6f33555ca1ab8bba3643a57043b6a2a1eef8be48955be36d936255bc412488e3*328da22d9deabea21019862d6539230c135368f9572d278f937eb63dca6f657a,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":289,""r"":76}", + 27038, 1011, 0, 317.4,chromobius,94dd0c2002241c6a4973439ddad20f2fee86e5b7f4c049db70622d4e589ef30b,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":289,""r"":76}", + 27297, 1001, 0, 330.3,chromobius,b75cb954a450fc5814b8d24bc7931d66b90d18050dffbe6d12a04a8b9dbb3cca,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":289,""r"":76}", + 27038, 1965, 0, 647.7,chromobius,94dd0c2002241c6a4973439ddad20f2fee86e5b7f4c049db70622d4e589ef30b*b75cb954a450fc5814b8d24bc7931d66b90d18050dffbe6d12a04a8b9dbb3cca,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":289,""r"":76}", + 2714, 1065, 0, 73.7,chromobius,fb472158390e7f98c4853bb9a5ca88e35613b821241372afa3c9856ffc311336,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":289,""r"":76}", + 2499, 1001, 0, 84.9,chromobius,b7f4f2dd98d820c1ddb6481f7b2bb7fc20020cb425fed8084bbd3ecd40a0aa05,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":289,""r"":76}", + 2499, 1589, 0, 158.6,chromobius,b7f4f2dd98d820c1ddb6481f7b2bb7fc20020cb425fed8084bbd3ecd40a0aa05*fb472158390e7f98c4853bb9a5ca88e35613b821241372afa3c9856ffc311336,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":289,""r"":76}", + 2112, 1032, 0, 89.0,chromobius,71f5657bb050049073567efc40e2fb2a37a23e0ecb775f838795034c8d436acd,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":289,""r"":76}", + 2057, 1013, 0, 82.4,chromobius,bc99608cbdd629c14615232210d691c8c28ec1cf92837209cbbf7de45c872f21,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":289,""r"":76}", + 2057, 1523, 0, 171.4,chromobius,bc99608cbdd629c14615232210d691c8c28ec1cf92837209cbbf7de45c872f21*71f5657bb050049073567efc40e2fb2a37a23e0ecb775f838795034c8d436acd,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":289,""r"":76}", + 1972, 1009, 0, 111.5,chromobius,78b251c9f531274cdcbb59c2136f6d7c8f28a2e14bd3d649e06d7f182d1c75d9,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":289,""r"":76}", + 2063, 1005, 0, 126.6,chromobius,6556dd4a490023e9be0721a8400617d26a00a44aeda75cd14507880cfdc80b39,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":289,""r"":76}", + 1972, 1478, 0, 238.1,chromobius,78b251c9f531274cdcbb59c2136f6d7c8f28a2e14bd3d649e06d7f182d1c75d9*6556dd4a490023e9be0721a8400617d26a00a44aeda75cd14507880cfdc80b39,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":289,""r"":76}", + 2004, 1017, 0, 161.6,chromobius,f643ac4da74c740126036e120c219164a9e9e041cb61990bdcb7e7417f154fe3,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":289,""r"":76}", + 2052, 1042, 0, 168.6,chromobius,1d6fe30332fa61d8004172d4a10bbbfc4023bf1f4f8bb164fdb031da9280039a,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":289,""r"":76}", + 2004, 1518, 0, 330.2,chromobius,f643ac4da74c740126036e120c219164a9e9e041cb61990bdcb7e7417f154fe3*1d6fe30332fa61d8004172d4a10bbbfc4023bf1f4f8bb164fdb031da9280039a,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":289,""r"":76}", + 1984, 1025, 0, 240.5,chromobius,3821cff04ba855b60a99ab611e8b86bb6600dbf1a49572fad705f8ca46ecfd16,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":289,""r"":76}", + 2002, 1006, 0, 246.9,chromobius,711398443a4e6a9016bcfd08e0394f1a1c8ae46159dc4aaa878c390733fbba82,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":289,""r"":76}", + 1984, 1507, 0, 487.4,chromobius,3821cff04ba855b60a99ab611e8b86bb6600dbf1a49572fad705f8ca46ecfd16*711398443a4e6a9016bcfd08e0394f1a1c8ae46159dc4aaa878c390733fbba82,"{""c"":""midout_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":289,""r"":76}", + 7395, 1089, 0, 0.544,chromobius,e6f3dd22aea879bafba98cec8388fa26f78b0274228bb31a438e812dc724277d,"{""c"":""phenom_ablated_toric_color_code"",""d"":6,""gates"":""all"",""h"":8,""noise"":""uniform"",""p"":0.01,""q"":26,""r"":24,""w"":6}", + 6669, 1009, 0, 2.32,pymatching,a0af8a28acf30b6909239b98bab00f6e62dd86dff6a48ba56925177bc5660c65,"{""c"":""phenom_ablated_toric_color_code"",""d"":6,""gates"":""all"",""h"":8,""noise"":""uniform"",""p"":0.01,""q"":26,""r"":24,""w"":6}", + 11921, 1046, 0, 0.241,sparse_blossom_correlated,0d6cfc60ac79f1010a30191366fdb2316c1a7125f78a0a89e5fc7ff741f6ed75,"{""c"":""phenom_ablated_toric_color_code"",""d"":6,""gates"":""all"",""h"":8,""noise"":""uniform"",""p"":0.01,""q"":26,""r"":24,""w"":6}", + 196957, 1062, 0, 81.2,chromobius,e06c3f3938044d1a06c52666730a3c848a255df51940355c80283f47916942da,"{""c"":""phenom_ablated_toric_color_code"",""d"":12,""gates"":""all"",""h"":16,""noise"":""uniform"",""p"":0.01,""q"":98,""r"":48,""w"":12}", + 741679, 1028, 0, 188.9,sparse_blossom_correlated,9fc258ad5c64d1b1c4f4e41658dac6712cbd989e3f345d87fdf9a15c6c70ca2c,"{""c"":""phenom_ablated_toric_color_code"",""d"":12,""gates"":""all"",""h"":16,""noise"":""uniform"",""p"":0.01,""q"":98,""r"":48,""w"":12}", + 195381, 1053, 0, 15.6,pymatching,6b4ecbe56bc6ab854635c3d2932cae179399acca908d9f3150e634ff1604ed8f,"{""c"":""phenom_ablated_toric_color_code"",""d"":12,""gates"":""all"",""h"":16,""noise"":""uniform"",""p"":0.01,""q"":98,""r"":48,""w"":12}", + 5654490, 1003, 0, 21175.4,chromobius,141985ce6e186d020a31a428e88af3a288236b21436b351f21353f3aea0ecbd5,"{""c"":""phenom_ablated_toric_color_code"",""d"":18,""gates"":""all"",""h"":24,""noise"":""uniform"",""p"":0.01,""q"":218,""r"":72,""w"":18}", + 40555658, 1040, 0, 56305.7,sparse_blossom_correlated,7ee784bcb009e303f394594943fa171fcd7d6691f240716ff7118685f1e72497,"{""c"":""phenom_ablated_toric_color_code"",""d"":18,""gates"":""all"",""h"":24,""noise"":""uniform"",""p"":0.01,""q"":218,""r"":72,""w"":18}", + 6204179, 1041, 0, 2865.0,pymatching,a478bc1fbfc1b0e8cdc7881590fa35eebdc01956900c9a21dc50d3a660efa32c,"{""c"":""phenom_ablated_toric_color_code"",""d"":18,""gates"":""all"",""h"":24,""noise"":""uniform"",""p"":0.01,""q"":218,""r"":72,""w"":18}", + 100000000, 598, 0,1337580.6,chromobius,e88e022e4b1c0cb1829fa2ce462673861fe566fd765cdbe7236af4e2d31ab1a9,"{""c"":""phenom_ablated_toric_color_code"",""d"":24,""gates"":""all"",""h"":32,""noise"":""uniform"",""p"":0.01,""q"":386,""r"":96,""w"":24}", + 187826556, 1090, 0,285682.2,pymatching,2d8e96cb0d4906505408bfba30d3bddb08d14f3072afd13e6eba0e299402dc92,"{""c"":""phenom_ablated_toric_color_code"",""d"":24,""gates"":""all"",""h"":32,""noise"":""uniform"",""p"":0.01,""q"":386,""r"":96,""w"":24}", + 190000000, 94, 0,848107.1,sparse_blossom_correlated,9288726df7daad1b521ed5a50ffeb9f5cd3b07b38e0860c144b6fdd73c858b2b,"{""c"":""phenom_ablated_toric_color_code"",""d"":24,""gates"":""all"",""h"":32,""noise"":""uniform"",""p"":0.01,""q"":386,""r"":96,""w"":24}", + 20099, 1021, 0, 0.296,chromobius,5468219ffcc3e1e2f7800b147b90f2970fef91dd458987e3bd5688158737477c,"{""c"":""phenom_color2surface_code"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":14,""r"":12}", + 46955, 1003, 0, 4.68,chromobius,e0d78b7c3a2fa1a95ce0588a056b669903a060d2f32b21c16a5d48ec8694fe88,"{""c"":""phenom_color2surface_code"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":40,""r"":20}", + 210782, 1004, 0, 87.9,chromobius,5bc1a599ea2e3e536dfce09171c7eacccde1e5aae36a6df53c34d599fe2b9470,"{""c"":""phenom_color2surface_code"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":80,""r"":28}", + 1002828, 1017, 0, 1234.8,chromobius,345d252c3591300403f6e8792ed7227f4828a6e264b8cd30ab996fd85fd35087,"{""c"":""phenom_color2surface_code"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":134,""r"":36}", + 4846447, 1019, 0, 13438.3,chromobius,9638589908b2d352a4fcd003701625d75a06f4b9560afd847e3a1b08ec2cec81,"{""c"":""phenom_color2surface_code"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":202,""r"":44}", + 26415021, 1022, 0,152591.8,chromobius,c34a0e155635bf29fb141b31d0076fc8ff80697272a025adf97eae07f4789a86,"{""c"":""phenom_color2surface_code"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":284,""r"":52}", + 21275, 1003, 0, 0.164,chromobius,bd7af6a64ac435454412bc8c6f56fe57c2749d08f5390d80225c265860170652,"{""c"":""phenom_color_code"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":8,""r"":12}", + 65246, 1011, 0, 2.86,chromobius,c99d466b6bf2d8ed205aefc02de44033fda35d4af7eabadd0c77e00f136ae334,"{""c"":""phenom_color_code"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":20,""r"":20}", + 256394, 1043, 0, 40.1,chromobius,458e8aea04ece5bb19d190c4e0e6bdad422f6fde099003277243145611ec7211,"{""c"":""phenom_color_code"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":38,""r"":28}", + 1190358, 1031, 0, 578.5,chromobius,30d8bc6eb1affc68fad0c6ef68b8626b2ce9f66f0740a87bdb450361198268cc,"{""c"":""phenom_color_code"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":62,""r"":36}", + 6412349, 1041, 0, 7582.2,chromobius,1776006a4e7ad668d389d9c1e7512b5595357a95b796435afbdcf3b2671bd2a2,"{""c"":""phenom_color_code"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":92,""r"":44}", + 38234182, 1001, 0, 82436.8,chromobius,d702e9e630a2da41abcf403e35cef91364504d7b3ab23fcf75912f3eb574ecb1,"{""c"":""phenom_color_code"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":128,""r"":52}", + 23295, 1052, 0, 0.175,chromobius,352303b98ec7090ba90aa2d76e0a1590c34101588b3abe5e9994e88d41e1ebbe,"{""c"":""phenom_color_code_488"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":8,""r"":12}", + 29179, 1001, 0, 1.10,chromobius,68feb4d486a390cda06afb9d994dcc0502e865068eb9de8fca63cc5a24d5492e,"{""c"":""phenom_color_code_488"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":18,""r"":20}", + 140914, 1083, 0, 16.4,chromobius,0f23a8be9dfe7ace9bd72c8b1b52ea33aee17004342fc6568541927033c8ca85,"{""c"":""phenom_color_code_488"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":32,""r"":28}", + 440090, 1078, 0, 148.1,chromobius,e77c322b2cf7846d14ec0754e821c06b8b682e8518618c8d31cd1f4e1461da56,"{""c"":""phenom_color_code_488"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":50,""r"":36}", + 1497416, 1001, 0, 1182.7,chromobius,5e67ee0269793a346584aea15ece33c998762e7e999639d522ac7fa1b5d8b763,"{""c"":""phenom_color_code_488"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":72,""r"":44}", + 5699028, 1024, 0, 8636.1,chromobius,7a2147b25a57e12cd49f9ca09bcc17811b92180318c0ed110b2bb3a51a35351c,"{""c"":""phenom_color_code_488"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":98,""r"":52}", + 14135, 1045, 0, 0.535,chromobius,84181b485b8844c764e3946f3055b6a9a7bef5e719cfadc8e0da5a515bd93736,"{""c"":""phenom_pyramid_code"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":27,""r"":12}", + 86527, 1000, 0, 19.8,chromobius,0955db26b8369c4ec7e88a72d522a440c529a5a46bf3a20aac8310d7bc555c06,"{""c"":""phenom_pyramid_code"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":74,""r"":20}", + 744760, 1004, 0, 763.9,chromobius,658410e042c82ab969a393133192cf22fe0e73c6ce06b56cd1495c0856a5f97f,"{""c"":""phenom_pyramid_code"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":145,""r"":28}", + 7450640, 1012, 0, 20457.4,chromobius,1f0b0e4bbddbc773bf0b238358f037ba63ad214f2f54deb1eb71b99c64daf74b,"{""c"":""phenom_pyramid_code"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":240,""r"":36}", + 78087738, 1005, 0,516404.7,chromobius,704005592d0a81d82c63ad687e0a43fad7aec6d6ff68a202b47c69aa0663b2b5,"{""c"":""phenom_pyramid_code"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":359,""r"":44}", + 100000000, 125, 0,1287790.6,chromobius,f64da85d926cbf268b82f5b86011285d435b705f41a3b609acc0757e30469d0d,"{""c"":""phenom_pyramid_code"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":502,""r"":52}", + 256953, 1139, 0, 0.406,chromobius,60ec60fa63625819240e2bddb9872fdad644ae002ef6c503122d2ec9257ae5b9,"{""c"":""phenom_rep_code"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":3,""r"":12}", + 3074955, 1009, 0, 13.5,chromobius,8550e7160bbfddf995d015df544201791971f687a297e20e34d60e376fbccb3a,"{""c"":""phenom_rep_code"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":5,""r"":20}", + 59276185, 1046, 0, 502.0,chromobius,c56db3abf48531871ae7c00c907f819861273ac23f83650a768c157237be0c7a,"{""c"":""phenom_rep_code"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":7,""r"":28}", + 100000000, 101, 0, 1423.4,chromobius,1b91727ac018ccf3bdd3eb75edcd3f3635c52d9a580221f68c183b6f44b1f068,"{""c"":""phenom_rep_code"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":9,""r"":36}", + 100000000, 8, 0, 2283.4,chromobius,c087af4982632309dee968c89b6f538abb45f0733c6d52da791447de05935f22,"{""c"":""phenom_rep_code"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":11,""r"":44}", + 100000000, 0, 0, 3423.9,chromobius,366ec1e5ea56951bd1e70d0dbe2451dcdb81e65ef1e02a37857e70c6ab876645,"{""c"":""phenom_rep_code"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":13,""r"":52}", + 20577, 1058, 0, 0.129,chromobius,c5ed4c0d3170a74ad2842b24b95325dd2fe7a17c7ef675cf434eebbfa7a83cc4,"{""c"":""phenom_surface_code"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":10,""r"":12}", + 63336, 1035, 0, 2.68,chromobius,a5c9ee3b7b59ac026e81462847a9e38310d51ddbcfdf55203e68832a0fb4125a,"{""c"":""phenom_surface_code"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":26,""r"":20}", + 260760, 1002, 0, 42.7,chromobius,20ec79518766327f0c282a0605d0604bd3d2eb43ecb4212ee2c28f99b107508c,"{""c"":""phenom_surface_code"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":50,""r"":28}", + 1133661, 1020, 0, 613.0,chromobius,6dc0e981506d0981900e5982bae9310bb80ffe7de184543c199e2390f91518f0,"{""c"":""phenom_surface_code"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":82,""r"":36}", + 6034821, 1007, 0, 7819.5,chromobius,f9585af86752bdf84e9cf0afb084852a9212a5770f1ad976e8e6b4451628417e,"{""c"":""phenom_surface_code"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":122,""r"":44}", + 29077030, 1028, 0, 67614.2,chromobius,ba983ff731fce222fd2e9438820b02d294afd0064d75d9bcfc07aa0e296ac02a,"{""c"":""phenom_surface_code"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":170,""r"":52}", + 1478, 1025, 0, 0.566,chromobius,3ef26d111ee6dc4973333560f8dd7c90acfa103c13cb674a51f3ca7e4c6849f5,"{""c"":""phenom_toric_color_code"",""d"":6,""gates"":""all"",""h"":8,""noise"":""uniform"",""p"":0.01,""q"":26,""r"":24,""w"":6}", + 157849, 1003, 0, 115.4,chromobius,47f6c88ac7f532d7c5c18f9e750859d961460c3371e83b0a16bb6f7c0a0664a4,"{""c"":""phenom_toric_color_code"",""d"":12,""gates"":""all"",""h"":16,""noise"":""uniform"",""p"":0.01,""q"":98,""r"":48,""w"":12}", + 4620356, 1007, 0, 33758.0,chromobius,be93b7ab968c5c8797048ef8b119739c175fc3fde451a708a93ccf25d5aa394d,"{""c"":""phenom_toric_color_code"",""d"":18,""gates"":""all"",""h"":24,""noise"":""uniform"",""p"":0.01,""q"":218,""r"":72,""w"":18}", + 100000000, 817, 0,2255896.3,chromobius,eb9ca535552405cd2164db403e3843517b9bd0b37abfb8374363fa18d652c38f,"{""c"":""phenom_toric_color_code"",""d"":24,""gates"":""all"",""h"":32,""noise"":""uniform"",""p"":0.01,""q"":386,""r"":96,""w"":24}", + 445797, 1089, 0, 0.809,chromobius,3cb8293fbf05882b24eb9666bdcac3ea190f9e76e1368a1b0526f55d719d31f4,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":13,""r"":12}", + 3094975, 1035, 0, 4.24,chromobius,88832e31a429e45f383dac2f931722fef7e1a9f72dd771f4716fdc630c5c1375,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":13,""r"":12}", + 445797, 1238, 0, 5.05,chromobius,3cb8293fbf05882b24eb9666bdcac3ea190f9e76e1368a1b0526f55d719d31f4*88832e31a429e45f383dac2f931722fef7e1a9f72dd771f4716fdc630c5c1375,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":13,""r"":12}", + 201949, 1067, 0, 0.658,chromobius,d7e1ff504da4effe50c5e3a4aa6942b48322b23f3daffea1c053ad1e3ec9afb9,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":13,""r"":12}", + 782280, 1003, 0, 1.66,chromobius,b766e84e3482cc03342901cb43ee52d90964d214f0494ad31c196b22c398a1be,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":13,""r"":12}", + 201949, 1325, 0, 2.32,chromobius,d7e1ff504da4effe50c5e3a4aa6942b48322b23f3daffea1c053ad1e3ec9afb9*b766e84e3482cc03342901cb43ee52d90964d214f0494ad31c196b22c398a1be,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":13,""r"":12}", + 121171, 1004, 0, 0.530,chromobius,730c75ea6e8fd8f683a21967161f7fb9d833d1561eb86442d22f04f70a0fb076,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":13,""r"":12}", + 382263, 1076, 0, 1.15,chromobius,c99ea53c84fc848d344d6fffe2faad5a421e1102cfc150b59ce8182654644d20,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":13,""r"":12}", + 121171, 1342, 0, 1.68,chromobius,730c75ea6e8fd8f683a21967161f7fb9d833d1561eb86442d22f04f70a0fb076*c99ea53c84fc848d344d6fffe2faad5a421e1102cfc150b59ce8182654644d20,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":13,""r"":12}", + 58605, 1003, 0, 0.499,chromobius,0b1cedf14d5c56ffd26dca82912875871fd4e7cf07d4b596fcf04b3606d99044,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":13,""r"":12}", + 130606, 1004, 0, 0.688,chromobius,62af4df25f2c451513345430484daefef0c073c12bb28d33bef5f513ffc667d9,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":13,""r"":12}", + 58605, 1446, 0, 1.19,chromobius,0b1cedf14d5c56ffd26dca82912875871fd4e7cf07d4b596fcf04b3606d99044*62af4df25f2c451513345430484daefef0c073c12bb28d33bef5f513ffc667d9,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":13,""r"":12}", + 37569, 1021, 0, 0.347,chromobius,93591c8c2534ebb52cd0424c72b485b0abc8e26924145015ec25f58a9cf12b39,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":13,""r"":12}", + 74968, 1051, 0, 0.509,chromobius,d0fe62c6a1ff493f85824466e4b93a7bac451db49c8e5d66eb00b394ef852607,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":13,""r"":12}", + 37569, 1533, 0, 0.856,chromobius,93591c8c2534ebb52cd0424c72b485b0abc8e26924145015ec25f58a9cf12b39*d0fe62c6a1ff493f85824466e4b93a7bac451db49c8e5d66eb00b394ef852607,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":13,""r"":12}", + 23816, 1008, 0, 0.511,chromobius,34e5b69ad805fa8b424b41f6de8cd829e9e5673f72b9db6a69d4db6613eaa0d1,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":13,""r"":12}", + 37244, 1001, 0, 0.377,chromobius,8698aabc9d9aba0562bed0ea6dc79f37b8449ebb7f0153d66fab61afab8ae02a,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":13,""r"":12}", + 23816, 1621, 0, 0.888,chromobius,34e5b69ad805fa8b424b41f6de8cd829e9e5673f72b9db6a69d4db6613eaa0d1*8698aabc9d9aba0562bed0ea6dc79f37b8449ebb7f0153d66fab61afab8ae02a,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":13,""r"":12}", + 8331, 1002, 0, 0.226,chromobius,ad3ce10010630d2a249f5b790a66d382e82c15b97b0b144a3e200087916e06b2,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":13,""r"":12}", + 10847, 1022, 0, 0.216,chromobius,454955023e4643a33586e0d9c448f069571640f577e127ee57943c6c9c1fdada,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":13,""r"":12}", + 8331, 1693, 0, 0.442,chromobius,ad3ce10010630d2a249f5b790a66d382e82c15b97b0b144a3e200087916e06b2*454955023e4643a33586e0d9c448f069571640f577e127ee57943c6c9c1fdada,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":13,""r"":12}", + 5169, 1009, 0, 0.196,chromobius,ba42dbb8d880b69efcf977be780786b60e9c5dad4aa92c791b0c5667e8cd0e3f,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":13,""r"":12}", + 5882, 1050, 0, 0.207,chromobius,2de2e0cb71525f405ddf0ce532024490c8754d97c2ff3e54f5c694e5bc293bec,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":13,""r"":12}", + 5169, 1752, 0, 0.403,chromobius,ba42dbb8d880b69efcf977be780786b60e9c5dad4aa92c791b0c5667e8cd0e3f*2de2e0cb71525f405ddf0ce532024490c8754d97c2ff3e54f5c694e5bc293bec,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":13,""r"":12}", + 3124, 1038, 0, 0.173,chromobius,1b43b35b6de1748a2e3a2fd1187e1e3b339e4745fbb838fb55dc63c5d692fde3,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":13,""r"":12}", + 3078, 1008, 0, 0.177,chromobius,0ae0b2a36962f40ca9db53aa38eedc7ce500b0ca185460728ceba30df7cafeba,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":13,""r"":12}", + 3078, 1696, 0, 0.350,chromobius,0ae0b2a36962f40ca9db53aa38eedc7ce500b0ca185460728ceba30df7cafeba*1b43b35b6de1748a2e3a2fd1187e1e3b339e4745fbb838fb55dc63c5d692fde3,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":13,""r"":12}", + 2740, 1023, 0, 0.162,chromobius,4a6a12530a363d0179c3b35c8aa4757be1195d1b02a3a279d2ae92a84e7c67ea,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":13,""r"":12}", + 3044, 1125, 0, 0.175,chromobius,16f53429d5ba424bc870902e2d1a09879430abd810491ac68f11ebfa0b31aed5,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":13,""r"":12}", + 2740, 1658, 0, 0.337,chromobius,4a6a12530a363d0179c3b35c8aa4757be1195d1b02a3a279d2ae92a84e7c67ea*16f53429d5ba424bc870902e2d1a09879430abd810491ac68f11ebfa0b31aed5,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":13,""r"":12}", + 2450, 1020, 0, 0.197,chromobius,565e2656b08dfacdeb7f8588146f297e1983a7219e10232915a88d6de1c971cb,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":13,""r"":12}", + 2422, 1013, 0, 0.192,chromobius,fee33cca71e88cc2b6e42878c8a76cb543a4ed83a688b833cbbd7e3beadda70c,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":13,""r"":12}", + 2422, 1600, 0, 0.389,chromobius,fee33cca71e88cc2b6e42878c8a76cb543a4ed83a688b833cbbd7e3beadda70c*565e2656b08dfacdeb7f8588146f297e1983a7219e10232915a88d6de1c971cb,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":13,""r"":12}", + 2379, 1067, 0, 0.180,chromobius,c9c5dc02fa8e97c94ec49b93c8118eab1c780cae88eb34a5049ccbfdb734bf0c,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":13,""r"":12}", + 2259, 1030, 0, 0.188,chromobius,474c43dd88ee2113d303a89683c23ea9ab3f40078332f8d92c31fb63b8c64bfc,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":13,""r"":12}", + 2259, 1581, 0, 0.368,chromobius,474c43dd88ee2113d303a89683c23ea9ab3f40078332f8d92c31fb63b8c64bfc*c9c5dc02fa8e97c94ec49b93c8118eab1c780cae88eb34a5049ccbfdb734bf0c,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":13,""r"":12}", + 2132, 1001, 0, 0.201,chromobius,3e23d3db21a9340c137829777ee4e40bf23e5ff88ccceea537d3fd9d80aded8f,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":13,""r"":12}", + 2128, 1004, 0, 0.220,chromobius,2bbca0f72410ca58a6f44d96ddbd936d9b3a29038583fcac8797174ab57354b0,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":13,""r"":12}", + 2128, 1532, 0, 0.421,chromobius,2bbca0f72410ca58a6f44d96ddbd936d9b3a29038583fcac8797174ab57354b0*3e23d3db21a9340c137829777ee4e40bf23e5ff88ccceea537d3fd9d80aded8f,"{""c"":""superdense_color_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":13,""r"":12}", + 948263, 1008, 0, 9.79,chromobius,18957294fc92650542fe0cf2408ebbdd03235f5a5c92e49fc2f0833deb0db806,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":37,""r"":20}", + 4148584, 1024, 0, 31.0,chromobius,c5895a225ce3dc417544d484dd35e83072dcc2a557e7b4b641a27003aff19a57,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":37,""r"":20}", + 948263, 1242, 0, 40.8,chromobius,18957294fc92650542fe0cf2408ebbdd03235f5a5c92e49fc2f0833deb0db806*c5895a225ce3dc417544d484dd35e83072dcc2a557e7b4b641a27003aff19a57,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":37,""r"":20}", + 370027, 1030, 0, 7.37,chromobius,a9e57855c634570c13ca6fca8719873d524ac871a61a55e6f3b56a9f82558d26,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":37,""r"":20}", + 910691, 1004, 0, 13.7,chromobius,96081e23f1bd9f0e75db6d02f1c14d694e82711d8e69fe5c74221d1c44f42898,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":37,""r"":20}", + 370027, 1437, 0, 21.1,chromobius,a9e57855c634570c13ca6fca8719873d524ac871a61a55e6f3b56a9f82558d26*96081e23f1bd9f0e75db6d02f1c14d694e82711d8e69fe5c74221d1c44f42898,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":37,""r"":20}", + 219893, 1067, 0, 6.14,chromobius,7230a7f8f260d951151e137708172c275163ac186f238812fb1ef03b4fa4a617,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":37,""r"":20}", + 437748, 1045, 0, 9.40,chromobius,37a7205f0bee6d43857f6c9ab34779615608c2eb9d159e0d40875385c75ab6f7,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":37,""r"":20}", + 219893, 1589, 0, 15.5,chromobius,7230a7f8f260d951151e137708172c275163ac186f238812fb1ef03b4fa4a617*37a7205f0bee6d43857f6c9ab34779615608c2eb9d159e0d40875385c75ab6f7,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":37,""r"":20}", + 94974, 1009, 0, 4.41,chromobius,b3725c34a958912514a80a3a470008b8ded4976f05222d7e1de1e328f0c16536,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":37,""r"":20}", + 137404, 1014, 0, 5.71,chromobius,c17104be12bcb3fafc2c9e78882a460efa2a560bf5314ca1d25188979dcdfd29,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":37,""r"":20}", + 94974, 1702, 0, 10.1,chromobius,b3725c34a958912514a80a3a470008b8ded4976f05222d7e1de1e328f0c16536*c17104be12bcb3fafc2c9e78882a460efa2a560bf5314ca1d25188979dcdfd29,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":37,""r"":20}", + 54623, 1016, 0, 4.00,chromobius,ce4fb708dbcd85a59aba8c1da5f13a039e1099892080c65d8ddcb27ea6bdb0ee,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":37,""r"":20}", + 71683, 1019, 0, 4.69,chromobius,8b25767f24964ce527cfb5d4982a53b8989e86e258945deb7788560cecbb7fda,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":37,""r"":20}", + 54623, 1778, 0, 8.69,chromobius,ce4fb708dbcd85a59aba8c1da5f13a039e1099892080c65d8ddcb27ea6bdb0ee*8b25767f24964ce527cfb5d4982a53b8989e86e258945deb7788560cecbb7fda,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":37,""r"":20}", + 28865, 1031, 0, 2.81,chromobius,24ba7a6e14a5ce45744fbec429c6aa30a9832e5c4e41c37a37c6ec9c00ddc02b,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":37,""r"":20}", + 34731, 1021, 0, 3.53,chromobius,8a26aee338843f084b465c3cbf42ead4332ce873e564e8e9dab4a83a445484b6,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":37,""r"":20}", + 28865, 1849, 0, 6.34,chromobius,24ba7a6e14a5ce45744fbec429c6aa30a9832e5c4e41c37a37c6ec9c00ddc02b*8a26aee338843f084b465c3cbf42ead4332ce873e564e8e9dab4a83a445484b6,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":37,""r"":20}", + 7613, 1010, 0, 2.39,chromobius,c0b9a46adec914027aecd1629935f3e66afe71c6dfb70f7a97917a8417227fa8,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":37,""r"":20}", + 8277, 1002, 0, 1.86,chromobius,7e985255732f231907a79781cad7ea9ce3cd3fee71142068a1256ea653e9b05e,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":37,""r"":20}", + 7613, 1809, 0, 4.25,chromobius,c0b9a46adec914027aecd1629935f3e66afe71c6dfb70f7a97917a8417227fa8*7e985255732f231907a79781cad7ea9ce3cd3fee71142068a1256ea653e9b05e,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":37,""r"":20}", + 3987, 1005, 0, 1.73,chromobius,08e89afb3339ac3a06ae198180af2c48bcc947f5d33f6493fcd42a27abcf6bcd,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":37,""r"":20}", + 4089, 1006, 0, 1.71,chromobius,97f5c8c1ee5368003b7d957b4e9262e2b3d81158d3e8ee099c25cd24e604dff7,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":37,""r"":20}", + 3987, 1739, 0, 3.44,chromobius,08e89afb3339ac3a06ae198180af2c48bcc947f5d33f6493fcd42a27abcf6bcd*97f5c8c1ee5368003b7d957b4e9262e2b3d81158d3e8ee099c25cd24e604dff7,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":37,""r"":20}", + 2522, 1103, 0, 1.24,chromobius,ce8ed65f5c1096a8f26fed647bd6c2f06ab7dacf36ea09993a724ace77d126cc,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":37,""r"":20}", + 2371, 1021, 0, 1.31,chromobius,cebe983d7948c63daa04f8f9593a829855617165c4d77d1add2490a0d09b4639,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":37,""r"":20}", + 2371, 1611, 0, 2.55,chromobius,cebe983d7948c63daa04f8f9593a829855617165c4d77d1add2490a0d09b4639*ce8ed65f5c1096a8f26fed647bd6c2f06ab7dacf36ea09993a724ace77d126cc,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":37,""r"":20}", + 2146, 1004, 0, 1.53,chromobius,afc517f5ab67b8c94f3999eedee786c187d26aab668075423cccdc404da2b860,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":37,""r"":20}", + 2129, 1003, 0, 1.71,chromobius,9df54b1f4d2a967dc8e2d0fb675fd055067d3ffbaee7e536909906f89ad20494,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":37,""r"":20}", + 2129, 1530, 0, 3.24,chromobius,9df54b1f4d2a967dc8e2d0fb675fd055067d3ffbaee7e536909906f89ad20494*afc517f5ab67b8c94f3999eedee786c187d26aab668075423cccdc404da2b860,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":37,""r"":20}", + 2266, 1093, 0, 1.85,chromobius,43a6367d7bc5598520e0a71a9c4ba7be31fca9eefcc4ef07d6604ed0f668fccf,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":37,""r"":20}", + 2128, 1018, 0, 1.57,chromobius,23a2066e28a44833f0079541c04356330dd621210989706b6e77f7419f02d17c,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":37,""r"":20}", + 2128, 1553, 0, 3.42,chromobius,23a2066e28a44833f0079541c04356330dd621210989706b6e77f7419f02d17c*43a6367d7bc5598520e0a71a9c4ba7be31fca9eefcc4ef07d6604ed0f668fccf,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":37,""r"":20}", + 2104, 1058, 0, 2.31,chromobius,1d788f548df37c0981735fb974dbb77680ed8221d4c52c8118e8f1a88cde2b4b,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":37,""r"":20}", + 2021, 1043, 0, 1.79,chromobius,6af088e129b82072cd538052d9f89815e220b2c994ba747ae78cfebeaed276fa,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":37,""r"":20}", + 2021, 1535, 0, 4.10,chromobius,6af088e129b82072cd538052d9f89815e220b2c994ba747ae78cfebeaed276fa*1d788f548df37c0981735fb974dbb77680ed8221d4c52c8118e8f1a88cde2b4b,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":37,""r"":20}", + 2105, 1063, 0, 2.05,chromobius,2164a57a3d6647fa154debc7be07e2f5e0cfb7b92a98b4eba05d55b4f64bcb01,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":37,""r"":20}", + 1868, 1003, 0, 1.97,chromobius,346455e30704879a1ab17867ac7df2ea4f6c6babfc6be84a45b15aa5a3117c93,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":37,""r"":20}", + 1868, 1440, 0, 4.02,chromobius,346455e30704879a1ab17867ac7df2ea4f6c6babfc6be84a45b15aa5a3117c93*2164a57a3d6647fa154debc7be07e2f5e0cfb7b92a98b4eba05d55b4f64bcb01,"{""c"":""superdense_color_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":37,""r"":20}", + 64699027, 1029, 0, 1626.5,chromobius,89277409cd7cec0a9bf25f73d8d39da8511264c1be22f0d9bdf1aa75b4080063,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":73,""r"":28}", + 45161211, 1080, 0, 1152.6,chromobius,1f650be6c78ab04948dbba538dfd72cf2dd21090381ebe79dfbe725a28495d13,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":73,""r"":28}", + 45161211, 1798, 0, 2779.1,chromobius,1f650be6c78ab04948dbba538dfd72cf2dd21090381ebe79dfbe725a28495d13*89277409cd7cec0a9bf25f73d8d39da8511264c1be22f0d9bdf1aa75b4080063,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":73,""r"":28}", + 10357677, 1020, 0, 463.3,chromobius,2082d5afc1a2b9719f068ab17c45c05b87cc185abad5b1dac110ec17c2f5669f,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":73,""r"":28}", + 7855039, 1028, 0, 354.1,chromobius,322971036dd99575b01a69b6eabad93c95e0014e62772e2d14a7459aa37f04a9,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":73,""r"":28}", + 7855039, 1801, 0, 817.4,chromobius,322971036dd99575b01a69b6eabad93c95e0014e62772e2d14a7459aa37f04a9*2082d5afc1a2b9719f068ab17c45c05b87cc185abad5b1dac110ec17c2f5669f,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":73,""r"":28}", + 3341054, 1008, 0, 205.3,chromobius,13bc8373d6c5e2f504c24b3096b33a6280f0dcbff7d73af3300873da099dda9b,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":73,""r"":28}", + 2508345, 1020, 0, 158.6,chromobius,2d69ff1f8f6e006500450f344f67c7ed0f0c5b2eaa7a755c7cdd5dfbd01068d3,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":73,""r"":28}", + 2508345, 1776, 0, 363.9,chromobius,2d69ff1f8f6e006500450f344f67c7ed0f0c5b2eaa7a755c7cdd5dfbd01068d3*13bc8373d6c5e2f504c24b3096b33a6280f0dcbff7d73af3300873da099dda9b,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":73,""r"":28}", + 752902, 1098, 0, 77.3,chromobius,36508f6a4d46f56802b7d7cef6ce4238662701ea1348a7086708e9fbed273f19,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":73,""r"":28}", + 669260, 1089, 0, 70.9,chromobius,c0d76f1b77ac9c0832c21b751d531725e1acdd7a9381e0749374636b7c5e3c08,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":73,""r"":28}", + 669260, 2063, 0, 148.2,chromobius,c0d76f1b77ac9c0832c21b751d531725e1acdd7a9381e0749374636b7c5e3c08*36508f6a4d46f56802b7d7cef6ce4238662701ea1348a7086708e9fbed273f19,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":73,""r"":28}", + 256557, 1002, 0, 44.1,chromobius,c1c37b9d2a2bcb59284d1075c4dbfac4757ae0d0155d59be8fd361f3ab4f957a,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":73,""r"":28}", + 240911, 1080, 0, 38.0,chromobius,a9333a680371ae24ff8d55ecc7a10c6c57ec06045f34faafb3cb55364c07f8d9,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":73,""r"":28}", + 240911, 2017, 0, 82.1,chromobius,a9333a680371ae24ff8d55ecc7a10c6c57ec06045f34faafb3cb55364c07f8d9*c1c37b9d2a2bcb59284d1075c4dbfac4757ae0d0155d59be8fd361f3ab4f957a,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":73,""r"":28}", + 91127, 1004, 0, 24.1,chromobius,c001b906f818624c84b44392c40b14558cdfc7a9303a2349c565d1ea9ded0593,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":73,""r"":28}", + 88071, 1038, 0, 22.7,chromobius,bf719f8bd31a9f1549fdaeda59c56df7e433eb5eccebaf94bbfd3c73b29aca0d,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":73,""r"":28}", + 88071, 1997, 0, 46.8,chromobius,bf719f8bd31a9f1549fdaeda59c56df7e433eb5eccebaf94bbfd3c73b29aca0d*c001b906f818624c84b44392c40b14558cdfc7a9303a2349c565d1ea9ded0593,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":73,""r"":28}", + 11841, 1020, 0, 9.57,chromobius,23b8ad6738bde90a72ec17c4759a0de08feff9104cb52106ae2a04597089a6fe,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":73,""r"":28}", + 10493, 1010, 0, 10.2,chromobius,3281a16faff043438caebd93acf6e5cf90ebb7128a87f515f1153cffcb3c7201,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":73,""r"":28}", + 10493, 1827, 0, 19.8,chromobius,3281a16faff043438caebd93acf6e5cf90ebb7128a87f515f1153cffcb3c7201*23b8ad6738bde90a72ec17c4759a0de08feff9104cb52106ae2a04597089a6fe,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":73,""r"":28}", + 4366, 1026, 0, 6.32,chromobius,f9c42519b3342ae7c8aa5f87fad4ac88c906fff52366f8ce72e37c8b0321e995,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":73,""r"":28}", + 4218, 1037, 0, 6.14,chromobius,56e1a19886a89105851298468f432ddb532e0d438ad55c00f663f37492b77dce,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":73,""r"":28}", + 4218, 1785, 0, 12.5,chromobius,56e1a19886a89105851298468f432ddb532e0d438ad55c00f663f37492b77dce*f9c42519b3342ae7c8aa5f87fad4ac88c906fff52366f8ce72e37c8b0321e995,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":73,""r"":28}", + 2219, 1026, 0, 6.05,chromobius,ad2a72b8db91f51ce3c3c209db21ef6bd9e8fb89c9e0f9862e86cfd35d2546c8,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":73,""r"":28}", + 2176, 1024, 0, 5.30,chromobius,1c700d922a2ff09f94800c4926d22ea5bd42e47b31730f246c562910a7aaa1ca,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":73,""r"":28}", + 2176, 1557, 0, 11.3,chromobius,1c700d922a2ff09f94800c4926d22ea5bd42e47b31730f246c562910a7aaa1ca*ad2a72b8db91f51ce3c3c209db21ef6bd9e8fb89c9e0f9862e86cfd35d2546c8,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":73,""r"":28}", + 2137, 1012, 0, 6.09,chromobius,d98cbf98f68f25427dd88de6efcda5bccbff9b82b90d380d6ba4af2169daaaca,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":73,""r"":28}", + 2083, 1027, 0, 6.01,chromobius,9490637e5c0b3b7b77086b55e893bc06570c4bd7ff51435bcebca53ad40ac54c,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":73,""r"":28}", + 2083, 1527, 0, 12.1,chromobius,9490637e5c0b3b7b77086b55e893bc06570c4bd7ff51435bcebca53ad40ac54c*d98cbf98f68f25427dd88de6efcda5bccbff9b82b90d380d6ba4af2169daaaca,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":73,""r"":28}", + 2057, 1007, 0, 6.55,chromobius,8d51eba1654da0d4c605f0a0e649cab222fdd18c95beb4ca993b2fc2b669af4b,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":73,""r"":28}", + 2197, 1056, 0, 6.59,chromobius,091f9d1f805f77f1c88c44e9f4c2024dd17866b2e7c52515f2b67e20e5cc9f8e,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":73,""r"":28}", + 2057, 1512, 0, 13.1,chromobius,8d51eba1654da0d4c605f0a0e649cab222fdd18c95beb4ca993b2fc2b669af4b*091f9d1f805f77f1c88c44e9f4c2024dd17866b2e7c52515f2b67e20e5cc9f8e,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":73,""r"":28}", + 2209, 1086, 0, 7.48,chromobius,527e19b8ac2abaf356883b99cf6f45681d60f56fcb5862bb79fbc05834c3b4b6,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":73,""r"":28}", + 2073, 1059, 0, 6.95,chromobius,d120ada7f5a9a0daeb0c3cdfb17c95c794de20df716fb09b968601b780c9e84a,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":73,""r"":28}", + 2073, 1558, 0, 14.4,chromobius,d120ada7f5a9a0daeb0c3cdfb17c95c794de20df716fb09b968601b780c9e84a*527e19b8ac2abaf356883b99cf6f45681d60f56fcb5862bb79fbc05834c3b4b6,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":73,""r"":28}", + 2105, 1055, 0, 8.43,chromobius,a19eb793340e6e42ceda8c8d210465ed8ed964b9d59e548e50a88a31e4432e5e,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":73,""r"":28}", + 2011, 1018, 0, 8.18,chromobius,eb457293a45db4ec6d601d7d6b485468e9643fadeaf9570bdc889a582c763fd9,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":73,""r"":28}", + 2011, 1516, 0, 16.6,chromobius,eb457293a45db4ec6d601d7d6b485468e9643fadeaf9570bdc889a582c763fd9*a19eb793340e6e42ceda8c8d210465ed8ed964b9d59e548e50a88a31e4432e5e,"{""c"":""superdense_color_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":73,""r"":28}", + 100000000, 127, 0, 6072.8,chromobius,c89ab8cb65f525e854839a5814842c64e601ec879a376836e0d5376562f3ba6e,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":121,""r"":36}", + 100000000, 138, 0, 6060.8,chromobius,08599e733ed4ebc5fbb607d389da549a48f3c9e1a43b9c78761533487670b83b,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":121,""r"":36}", + 100000000, 265, 0, 12133.6,chromobius,c89ab8cb65f525e854839a5814842c64e601ec879a376836e0d5376562f3ba6e*08599e733ed4ebc5fbb607d389da549a48f3c9e1a43b9c78761533487670b83b,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":121,""r"":36}", + 91279513, 1022, 0, 10000.3,chromobius,15696dab5a6ebb6461a2bcaec00059596c95ce29cd5f64cc3fbdf7f494006324,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":121,""r"":36}", + 70946651, 1043, 0, 7770.5,chromobius,f85efbca7118dddcf6f43b536b4fca2a1646fdaf1321080936f0875fcb16f662,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":121,""r"":36}", + 70946651, 1837, 0, 17770.8,chromobius,f85efbca7118dddcf6f43b536b4fca2a1646fdaf1321080936f0875fcb16f662*15696dab5a6ebb6461a2bcaec00059596c95ce29cd5f64cc3fbdf7f494006324,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":121,""r"":36}", + 20677132, 1010, 0, 3317.3,chromobius,9feec3558818b971b4fe8317c6bb1b141dd18baab19e15508ccad1755ed97b28,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":121,""r"":36}", + 18976865, 1082, 0, 3025.8,chromobius,ac45a53c82c54bd2807181e3abcebed06b1793b6ee80c1468300487db6c7c03b,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":121,""r"":36}", + 18976865, 2009, 0, 6343.1,chromobius,ac45a53c82c54bd2807181e3abcebed06b1793b6ee80c1468300487db6c7c03b*9feec3558818b971b4fe8317c6bb1b141dd18baab19e15508ccad1755ed97b28,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":121,""r"":36}", + 3429146, 1008, 0, 880.3,chromobius,862aef8592d489176187404e6b51143fd8e0df71f6f960da0f91f389aa55a1a7,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":121,""r"":36}", + 2809938, 1004, 0, 720.8,chromobius,18ffab646e51e1004090f4f40448fada3e716366f5602b1fdfd3f928ea5b4e15,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":121,""r"":36}", + 2809938, 1830, 0, 1601.1,chromobius,18ffab646e51e1004090f4f40448fada3e716366f5602b1fdfd3f928ea5b4e15*862aef8592d489176187404e6b51143fd8e0df71f6f960da0f91f389aa55a1a7,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":121,""r"":36}", + 928504, 1039, 0, 339.3,chromobius,a7e9abfe57c5448242f232af0faeebccdef7bb2ee20058e903daff385a44b20c,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":121,""r"":36}", + 855898, 1071, 0, 310.4,chromobius,97cecf7888461a962bb2c61ca31ad556729cd1f33961a78ab4f9f0a1da9eaf88,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":121,""r"":36}", + 855898, 2028, 0, 649.7,chromobius,97cecf7888461a962bb2c61ca31ad556729cd1f33961a78ab4f9f0a1da9eaf88*a7e9abfe57c5448242f232af0faeebccdef7bb2ee20058e903daff385a44b20c,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":121,""r"":36}", + 233926, 1007, 0, 169.1,chromobius,f56b2a40f28f510719f821a52f1aea00ea860d4c2c1ec095828388c2c32ecb48,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":121,""r"":36}", + 217741, 1029, 0, 126.1,chromobius,e3fb53d2fc02a48db6ddf23900904c7509f0ee87cf5981bbdc6e91df39f7092f,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":121,""r"":36}", + 217741, 1962, 0, 295.2,chromobius,e3fb53d2fc02a48db6ddf23900904c7509f0ee87cf5981bbdc6e91df39f7092f*f56b2a40f28f510719f821a52f1aea00ea860d4c2c1ec095828388c2c32ecb48,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":121,""r"":36}", + 15061, 1003, 0, 30.4,chromobius,06c720e7d28d0b69972c0e8e590b5687fb0b34085c25e5c8512c54bae0a123f0,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":121,""r"":36}", + 14805, 1014, 0, 26.8,chromobius,26a11a0b4e7be68ecb719b76a2e4417d74edc2d325c7157e096962be3c8a6f25,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":121,""r"":36}", + 14805, 1932, 0, 57.2,chromobius,26a11a0b4e7be68ecb719b76a2e4417d74edc2d325c7157e096962be3c8a6f25*06c720e7d28d0b69972c0e8e590b5687fb0b34085c25e5c8512c54bae0a123f0,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":121,""r"":36}", + 4137, 1002, 0, 15.8,chromobius,755f1161287d6f6dc55f1500fb3b628a60ed20908bb06e9247bdffcf12ff7a31,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":121,""r"":36}", + 4114, 1047, 0, 12.6,chromobius,ee4c4adbbb2f2d5db6fb6fe69985660ea08f53320939493d6060c11d545cabe7,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":121,""r"":36}", + 4114, 1790, 0, 28.4,chromobius,ee4c4adbbb2f2d5db6fb6fe69985660ea08f53320939493d6060c11d545cabe7*755f1161287d6f6dc55f1500fb3b628a60ed20908bb06e9247bdffcf12ff7a31,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":121,""r"":36}", + 2160, 1042, 0, 12.6,chromobius,b9be4999727871c4a9389edf6a3a85865791b51b848248eceb2ee4f62d3cdc62,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":121,""r"":36}", + 2091, 1034, 0, 12.2,chromobius,da640a3e0e33444bc4465aa4da6663d883809ab807343f592726d3152e509f6f,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":121,""r"":36}", + 2091, 1544, 0, 24.8,chromobius,da640a3e0e33444bc4465aa4da6663d883809ab807343f592726d3152e509f6f*b9be4999727871c4a9389edf6a3a85865791b51b848248eceb2ee4f62d3cdc62,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":121,""r"":36}", + 2059, 1042, 0, 17.2,chromobius,a2c7eb4be6dd1c6e8fb2c1cd265b4859cae7b1da83d2eb9a070ac2dd6f425ac5,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":121,""r"":36}", + 2038, 1019, 0, 16.2,chromobius,b1e80a3099ed33a9f5895311e4f87caa064c7df4dd767079fb978e77cc090309,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":121,""r"":36}", + 2038, 1535, 0, 33.4,chromobius,b1e80a3099ed33a9f5895311e4f87caa064c7df4dd767079fb978e77cc090309*a2c7eb4be6dd1c6e8fb2c1cd265b4859cae7b1da83d2eb9a070ac2dd6f425ac5,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":121,""r"":36}", + 2043, 1012, 0, 18.4,chromobius,7a31020df01a08cc496af8c3301bc80b3b90beae1694f65de7b10bbc6d9428c7,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":121,""r"":36}", + 2041, 1012, 0, 19.0,chromobius,c0dc91f72ba63cd52dc3bb7172ac431b43d33217b3b809b58e14bd892d554b24,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":121,""r"":36}", + 2041, 1522, 0, 37.4,chromobius,c0dc91f72ba63cd52dc3bb7172ac431b43d33217b3b809b58e14bd892d554b24*7a31020df01a08cc496af8c3301bc80b3b90beae1694f65de7b10bbc6d9428c7,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":121,""r"":36}", + 1956, 1004, 0, 23.1,chromobius,81237f807cb60ad8682cc5465e0f12c21b87520cfd8e3fa163935f9b719e5963,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":121,""r"":36}", + 2059, 1005, 0, 20.9,chromobius,0c6ca24073511e4dbd5f6815221ffcd0dd278dbbac5b2c2a1631f0e0b3b45b7a,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":121,""r"":36}", + 1956, 1469, 0, 44.0,chromobius,81237f807cb60ad8682cc5465e0f12c21b87520cfd8e3fa163935f9b719e5963*0c6ca24073511e4dbd5f6815221ffcd0dd278dbbac5b2c2a1631f0e0b3b45b7a,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":121,""r"":36}", + 1980, 1008, 0, 26.1,chromobius,6da1b0dedb1968a34abbb744d0b4683bb23d887ea9cd9964c33bc8f4c99692a1,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":121,""r"":36}", + 2057, 1006, 0, 25.8,chromobius,eedcba2f6b067417cc1d554e13b033abba4688855c70b7b030311877cc0910a6,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":121,""r"":36}", + 1980, 1483, 0, 51.9,chromobius,6da1b0dedb1968a34abbb744d0b4683bb23d887ea9cd9964c33bc8f4c99692a1*eedcba2f6b067417cc1d554e13b033abba4688855c70b7b030311877cc0910a6,"{""c"":""superdense_color_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":121,""r"":36}", + 100000000, 10, 0, 13180.1,chromobius,ff06046e6e57e2f716d9a619c0d1074b81cb91291d318bdc4aba33a632091971,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":181,""r"":44}", + 100000000, 12, 0, 13103.7,chromobius,271295a338ceed2a0c0305a620eef84c5724fbdcedaabbfb5f1a1ea789c5dde0,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":181,""r"":44}", + 100000000, 22, 0, 26283.8,chromobius,ff06046e6e57e2f716d9a619c0d1074b81cb91291d318bdc4aba33a632091971*271295a338ceed2a0c0305a620eef84c5724fbdcedaabbfb5f1a1ea789c5dde0,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":181,""r"":44}", + 100000000, 137, 0, 24470.0,chromobius,b3ed0cba8fae18ceb952059053042fb87498595bde01facb44276382ba32c3bd,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":181,""r"":44}", + 100000000, 160, 0, 24173.4,chromobius,7f278b57cf9910a08b651e8cb2ba4912860c7308c25b00e2350ae587271c2939,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":181,""r"":44}", + 100000000, 297, 0, 48643.4,chromobius,b3ed0cba8fae18ceb952059053042fb87498595bde01facb44276382ba32c3bd*7f278b57cf9910a08b651e8cb2ba4912860c7308c25b00e2350ae587271c2939,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":181,""r"":44}", + 100000000, 714, 0, 35496.4,chromobius,896a3396cc5a4c42dec0ff1b3de7720ceabfd79b6cc4aefe412bab31233b5475,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":181,""r"":44}", + 100000000, 810, 0, 35187.7,chromobius,dc0155d9a2e0c3e9b8f9fab50e58af4115c53678d3e68e95fe497f5e32533ac1,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":181,""r"":44}", + 100000000, 1524, 0, 70684.1,chromobius,896a3396cc5a4c42dec0ff1b3de7720ceabfd79b6cc4aefe412bab31233b5475*dc0155d9a2e0c3e9b8f9fab50e58af4115c53678d3e68e95fe497f5e32533ac1,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":181,""r"":44}", + 14894279, 1020, 0, 8776.5,chromobius,fbe7fcc2bb5da441862b8095564d8273ed5e8e307fdded24ad797b3052f34aeb,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":181,""r"":44}", + 14520107, 1120, 0, 8493.5,chromobius,87e73866065e3696de0dfc481550691e70cdc6939e7a73563fe7016116120fc5,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":181,""r"":44}", + 14520107, 2114, 0, 17270.0,chromobius,87e73866065e3696de0dfc481550691e70cdc6939e7a73563fe7016116120fc5*fbe7fcc2bb5da441862b8095564d8273ed5e8e307fdded24ad797b3052f34aeb,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":181,""r"":44}", + 3582114, 1006, 0, 3010.0,chromobius,2a99b84586fc4829d3299880e8d1cc6f64057db65da7916cd4188e0a11f42ae0,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":181,""r"":44}", + 2932395, 1003, 0, 2396.7,chromobius,2bddac2a6b995842cf20a38c71a092109f0a4fa60756ae4935fdfa4f9db7d1a3,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":181,""r"":44}", + 2932395, 1826, 0, 5406.7,chromobius,2bddac2a6b995842cf20a38c71a092109f0a4fa60756ae4935fdfa4f9db7d1a3*2a99b84586fc4829d3299880e8d1cc6f64057db65da7916cd4188e0a11f42ae0,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":181,""r"":44}", + 609438, 1008, 0, 877.2,chromobius,795697a98d07be74a3fe080e2afbc77455d8aec74ca5ced27710e60f880d7419,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":181,""r"":44}", + 593559, 1040, 0, 725.5,chromobius,820d55ffc284bba038b5569beb94eac3f2deee22636843831f068f2d7feb5c47,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":181,""r"":44}", + 593559, 2020, 0, 1602.7,chromobius,820d55ffc284bba038b5569beb94eac3f2deee22636843831f068f2d7feb5c47*795697a98d07be74a3fe080e2afbc77455d8aec74ca5ced27710e60f880d7419,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":181,""r"":44}", + 23420, 1077, 0, 82.7,chromobius,eda2b9e3a65dfc9d9435b0318f6253eb5d41f8c5421430a100038f6e552e3cbb,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":181,""r"":44}", + 21600, 1025, 0, 74.9,chromobius,d30b5b3a5c055da3059bebb4308ac2b586508594bf3fd4a008f333cceb6e5791,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":181,""r"":44}", + 21600, 1971, 0, 157.6,chromobius,d30b5b3a5c055da3059bebb4308ac2b586508594bf3fd4a008f333cceb6e5791*eda2b9e3a65dfc9d9435b0318f6253eb5d41f8c5421430a100038f6e552e3cbb,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":181,""r"":44}", + 4350, 1005, 0, 36.5,chromobius,b95c900d0f7376f55353c8e2cc16f785ff3541c9c12223e459322e0acc2cf941,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":181,""r"":44}", + 4067, 1014, 0, 30.1,chromobius,c7b0ea550484a65d8548bfc607a6b9444a0013ebb8ef10b3ad8d1f732d296496,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":181,""r"":44}", + 4067, 1719, 0, 66.6,chromobius,c7b0ea550484a65d8548bfc607a6b9444a0013ebb8ef10b3ad8d1f732d296496*b95c900d0f7376f55353c8e2cc16f785ff3541c9c12223e459322e0acc2cf941,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":181,""r"":44}", + 2035, 1006, 0, 32.0,chromobius,f4f052634915bf9fa74a7da756c86d2ce5ea74433043766b434e95bc949127d7,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":181,""r"":44}", + 2043, 1021, 0, 30.7,chromobius,a2fd96600e4d1c5d64de59b8c0799c99c483fb61b21f42d43df9ea2939dca927,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":181,""r"":44}", + 2035, 1520, 0, 62.7,chromobius,f4f052634915bf9fa74a7da756c86d2ce5ea74433043766b434e95bc949127d7*a2fd96600e4d1c5d64de59b8c0799c99c483fb61b21f42d43df9ea2939dca927,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":181,""r"":44}", + 1913, 1005, 0, 40.1,chromobius,8c183827e9da4aca2814c26eff3dfafbc08cb4f6fca73a86ae95ebdc80b0c5d2,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":181,""r"":44}", + 2128, 1066, 0, 37.1,chromobius,28caf91dd8ee1dfc66aab99d707db88f034b940474d6ef057d49be54a0be4a91,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":181,""r"":44}", + 1913, 1460, 0, 77.2,chromobius,8c183827e9da4aca2814c26eff3dfafbc08cb4f6fca73a86ae95ebdc80b0c5d2*28caf91dd8ee1dfc66aab99d707db88f034b940474d6ef057d49be54a0be4a91,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":181,""r"":44}", + 2116, 1033, 0, 50.0,chromobius,9fdaca6204b04259cc3114fa5fb9496f3bec2e1afbf362c6274379f61fd740cf,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":181,""r"":44}", + 1926, 1002, 0, 47.2,chromobius,3ef2169f582111f55d7eb5a75ac619e2e4b9b813774d9c258df04686d0e8bbad,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":181,""r"":44}", + 1926, 1453, 0, 97.2,chromobius,3ef2169f582111f55d7eb5a75ac619e2e4b9b813774d9c258df04686d0e8bbad*9fdaca6204b04259cc3114fa5fb9496f3bec2e1afbf362c6274379f61fd740cf,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":181,""r"":44}", + 2110, 1037, 0, 57.3,chromobius,1909e4dae8d04cd68c4b6825d70333e7c20c2bc08dd5491f4834443567f7b902,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":181,""r"":44}", + 2110, 1026, 0, 57.9,chromobius,9eeb59f99c8ddfcb2d834a7904a09cfafec148d89b33e34a438297b0e6209ccc,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":181,""r"":44}", + 2110, 1559, 0, 115.2,chromobius,1909e4dae8d04cd68c4b6825d70333e7c20c2bc08dd5491f4834443567f7b902*9eeb59f99c8ddfcb2d834a7904a09cfafec148d89b33e34a438297b0e6209ccc,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":181,""r"":44}", + 2073, 1017, 0, 66.6,chromobius,5979684819b2793353200e3c46e440ec5cd2393f2b713a4a0f741602313f472f,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":181,""r"":44}", + 1958, 1002, 0, 66.8,chromobius,7a3715d81fb32a1fe065579f499515a2a0f1d05e0f688b2ec06c8f761a0fa21f,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":181,""r"":44}", + 1958, 1471, 0, 133.4,chromobius,7a3715d81fb32a1fe065579f499515a2a0f1d05e0f688b2ec06c8f761a0fa21f*5979684819b2793353200e3c46e440ec5cd2393f2b713a4a0f741602313f472f,"{""c"":""superdense_color_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":181,""r"":44}", + 100000000, 0, 0, 24234.6,chromobius,a7395cf7d73fc18d3870c25f6d86d1db547e86fe007aeb6608519e74ece42a89,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":253,""r"":52}", + 100000000, 1, 0, 24191.5,chromobius,e5d96a3e515bd3b8a35a66fe7bfb714d813fcce54e3a4b51897beab020d1b8e8,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":253,""r"":52}", + 100000000, 1, 0, 48426.1,chromobius,a7395cf7d73fc18d3870c25f6d86d1db547e86fe007aeb6608519e74ece42a89*e5d96a3e515bd3b8a35a66fe7bfb714d813fcce54e3a4b51897beab020d1b8e8,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":253,""r"":52}", + 100000000, 5, 0, 45113.5,chromobius,ae6b166b191da8b266454299c210e5bc9b7d0164ce6df6d8278eee0dbbd56a13,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":253,""r"":52}", + 100000000, 12, 0, 44958.4,chromobius,33bfcbde87af0c052135e2097b36cc5cad7b5628c041e7146b51cf451b0cf5ac,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":253,""r"":52}", + 100000000, 17, 0, 90071.9,chromobius,ae6b166b191da8b266454299c210e5bc9b7d0164ce6df6d8278eee0dbbd56a13*33bfcbde87af0c052135e2097b36cc5cad7b5628c041e7146b51cf451b0cf5ac,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":253,""r"":52}", + 100000000, 87, 0, 67423.9,chromobius,bd52be51fce85190559efed72efc5c96624de9e60704654946aba772c1bb6a2c,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":253,""r"":52}", + 100000000, 127, 0, 66639.2,chromobius,49debdb393eee866ce42aac229a829e1e502b31d6cc7f7589a236b402d96234b,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":253,""r"":52}", + 100000000, 214, 0,134063.1,chromobius,bd52be51fce85190559efed72efc5c96624de9e60704654946aba772c1bb6a2c*49debdb393eee866ce42aac229a829e1e502b31d6cc7f7589a236b402d96234b,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":253,""r"":52}", + 81606681, 1009, 0, 92659.5,chromobius,a24f1490a62b0a07bc9b00f2d6707bd121ecb53aa89a52b895434b0030025025,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":253,""r"":52}", + 65198143, 1006, 0, 73559.0,chromobius,374dd862709b283ca3ce85a19084732fe825c8c1eba2e3406b35b39890d40e44,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":253,""r"":52}", + 65198143, 1812, 0,166218.5,chromobius,374dd862709b283ca3ce85a19084732fe825c8c1eba2e3406b35b39890d40e44*a24f1490a62b0a07bc9b00f2d6707bd121ecb53aa89a52b895434b0030025025,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":253,""r"":52}", + 14222469, 1098, 0, 22967.3,chromobius,cf9a1d401926db9ab35862fd9ebd76ce0aa4af11635c02d0d4ea76976cf65db9,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":253,""r"":52}", + 11614335, 1008, 0, 18873.5,chromobius,e6d4c1d4f991bdf9e26463bc01ac402492e675060c5b681f96740d6b27636a07,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":253,""r"":52}", + 11614335, 1905, 0, 41840.8,chromobius,e6d4c1d4f991bdf9e26463bc01ac402492e675060c5b681f96740d6b27636a07*cf9a1d401926db9ab35862fd9ebd76ce0aa4af11635c02d0d4ea76976cf65db9,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":253,""r"":52}", + 1718448, 1016, 0, 4181.7,chromobius,41bd64e523ed2e27776695032df2da8cc0ce5fb0163a2358fcb266e9ea83cd76,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":253,""r"":52}", + 1586943, 1000, 0, 3775.6,chromobius,ac6593c1b0be522cea595258816c07d82de05693722b751e75e702fe6f4a1134,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":253,""r"":52}", + 1586943, 1938, 0, 7957.3,chromobius,ac6593c1b0be522cea595258816c07d82de05693722b751e75e702fe6f4a1134*41bd64e523ed2e27776695032df2da8cc0ce5fb0163a2358fcb266e9ea83cd76,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":253,""r"":52}", + 32753, 1010, 0, 212.3,chromobius,921cbdfc27fb7a943a19f4edf74783e88e35fa798d1f438ccb315853dfaab108,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":253,""r"":52}", + 30333, 1005, 0, 197.6,chromobius,5e86c2ad0076fd8794517f197d7b65c5fa47ca160aa8223a476a812f6e948bbd,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":253,""r"":52}", + 30333, 1909, 0, 409.9,chromobius,5e86c2ad0076fd8794517f197d7b65c5fa47ca160aa8223a476a812f6e948bbd*921cbdfc27fb7a943a19f4edf74783e88e35fa798d1f438ccb315853dfaab108,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":253,""r"":52}", + 4498, 1030, 0, 64.5,chromobius,fb21d1820c423b4c4b11c16a8f0be0756e4d3ad9e5898bc82a8b9d2518a1f325,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":253,""r"":52}", + 4422, 1037, 0, 57.8,chromobius,3059c12ca410c6861526550a9d717274a5cf2ddfbb489f8a2155ac8ccec64d43,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":253,""r"":52}", + 4422, 1812, 0, 122.3,chromobius,3059c12ca410c6861526550a9d717274a5cf2ddfbb489f8a2155ac8ccec64d43*fb21d1820c423b4c4b11c16a8f0be0756e4d3ad9e5898bc82a8b9d2518a1f325,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":253,""r"":52}", + 2160, 1034, 0, 63.2,chromobius,d9d97be50b8063aaadebc4ee10b22e928f3a9c4053df97746d58692ac4c86252,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":253,""r"":52}", + 2098, 1010, 0, 66.1,chromobius,59d00eb457d77e11eb732beaf2a061702ed3bff9e74f12956334b787cb6a1711,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":253,""r"":52}", + 2098, 1531, 0, 129.3,chromobius,59d00eb457d77e11eb732beaf2a061702ed3bff9e74f12956334b787cb6a1711*d9d97be50b8063aaadebc4ee10b22e928f3a9c4053df97746d58692ac4c86252,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":253,""r"":52}", + 1932, 1002, 0, 85.7,chromobius,8d8801cf0b263e4285a1191d201ed058be56f3368476c4711e89714e2944e928,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":253,""r"":52}", + 2058, 1038, 0, 89.0,chromobius,a3d4a72f42df3ced5d81954e4a4671ba9e33cc96661d1f9a0635accbde29c494,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":253,""r"":52}", + 1932, 1471, 0, 174.7,chromobius,8d8801cf0b263e4285a1191d201ed058be56f3368476c4711e89714e2944e928*a3d4a72f42df3ced5d81954e4a4671ba9e33cc96661d1f9a0635accbde29c494,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":253,""r"":52}", + 1999, 1003, 0, 109.7,chromobius,a604b3d971bec7274bbf8452b055ee339015bd41c8c1f70dd269f170c6e92e54,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":253,""r"":52}", + 2008, 1007, 0, 111.9,chromobius,7a8d7259fb59414cd58651662cd2a538e423e523b8d6dbbe436a213669f6675f,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":253,""r"":52}", + 1999, 1502, 0, 221.6,chromobius,a604b3d971bec7274bbf8452b055ee339015bd41c8c1f70dd269f170c6e92e54*7a8d7259fb59414cd58651662cd2a538e423e523b8d6dbbe436a213669f6675f,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":253,""r"":52}", + 2077, 1004, 0, 131.8,chromobius,402724225f89645c4445094713de6a7435ac9010cf7b1acbf3a0cb3d79a22d62,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":253,""r"":52}", + 2037, 1006, 0, 135.4,chromobius,e93edeccbfba2753a37c56469416d571192bc1d58dab878fd65b914d872fb52f,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":253,""r"":52}", + 2037, 1504, 0, 267.2,chromobius,e93edeccbfba2753a37c56469416d571192bc1d58dab878fd65b914d872fb52f*402724225f89645c4445094713de6a7435ac9010cf7b1acbf3a0cb3d79a22d62,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":253,""r"":52}", + 2094, 1014, 0, 173.2,chromobius,ae02429d4f0126dcd50b4a10a5a3b282dbca4453b9930333c9f25ea5c96a378c,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":253,""r"":52}", + 1978, 1006, 0, 178.4,chromobius,ea642fe3810fddddf114a67a3b0b77a878333774797a0acbebb62de91274e889,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":253,""r"":52}", + 1978, 1477, 0, 351.6,chromobius,ea642fe3810fddddf114a67a3b0b77a878333774797a0acbebb62de91274e889*ae02429d4f0126dcd50b4a10a5a3b282dbca4453b9930333c9f25ea5c96a378c,"{""c"":""superdense_color_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":253,""r"":52}", + 100000000, 0, 0, 40574.5,chromobius,2d2f521ca7494989c67fdf1a86164ca6ece8baaeabdbcfb0d3108a61ee970aae,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":337,""r"":60}", + 100000000, 0, 0, 40170.8,chromobius,dab60785de03bc0705ea232412a6ead462390967d9b03c9579b0f7ee5b6681ad,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":337,""r"":60}", + 100000000, 0, 0, 80745.3,chromobius,2d2f521ca7494989c67fdf1a86164ca6ece8baaeabdbcfb0d3108a61ee970aae*dab60785de03bc0705ea232412a6ead462390967d9b03c9579b0f7ee5b6681ad,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":337,""r"":60}", + 100000000, 3, 0, 75810.9,chromobius,436022c91c976baaf82ca6a50df305e4675845c67906f25af08eb3ea0669c50b,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":337,""r"":60}", + 100000000, 2, 0, 75219.7,chromobius,c971660856541f6a70992f979cb5e8f066a6095978bb045bdcebba75e7e71640,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":337,""r"":60}", + 100000000, 5, 0,151030.6,chromobius,436022c91c976baaf82ca6a50df305e4675845c67906f25af08eb3ea0669c50b*c971660856541f6a70992f979cb5e8f066a6095978bb045bdcebba75e7e71640,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":337,""r"":60}", + 100000000, 11, 0,112160.7,chromobius,4871f48916d71a11804458f45a04b418f784c24d4fbbd20e144b3a0e4ce34c06,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":337,""r"":60}", + 100000000, 15, 0,111557.6,chromobius,da5564a0397279bfd5028f6565e55e014a141baf7b012d61b6a24d682343fdcf,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":337,""r"":60}", + 100000000, 26, 0,223718.3,chromobius,4871f48916d71a11804458f45a04b418f784c24d4fbbd20e144b3a0e4ce34c06*da5564a0397279bfd5028f6565e55e014a141baf7b012d61b6a24d682343fdcf,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":337,""r"":60}", + 100000000, 232, 0,189243.5,chromobius,c8c14249d8fee0cce3a6b1049dd2a79c1f3bfbffd5191b0667a0b0bef6b21220,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":337,""r"":60}", + 100000000, 314, 0,187880.5,chromobius,d0624d6bafa55a5f3176f3e719f4597780fd8a23c0f7d4565c3ec08b605a339d,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":337,""r"":60}", + 100000000, 546, 0,377124.0,chromobius,c8c14249d8fee0cce3a6b1049dd2a79c1f3bfbffd5191b0667a0b0bef6b21220*d0624d6bafa55a5f3176f3e719f4597780fd8a23c0f7d4565c3ec08b605a339d,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":337,""r"":60}", + 51160355, 1020, 0,139779.7,chromobius,d7f3a442f53773f10a9cd4909af2d771c22ca3ed0b6790735470d26fd1d7d0d0,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":337,""r"":60}", + 45514960, 1007, 0,123330.3,chromobius,b36a6d71a729954ec7c074c0914c25f92027120fcc52bc7131ca3ba1bad5cd50,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":337,""r"":60}", + 45514960, 1914, 0,263110.0,chromobius,b36a6d71a729954ec7c074c0914c25f92027120fcc52bc7131ca3ba1bad5cd50*d7f3a442f53773f10a9cd4909af2d771c22ca3ed0b6790735470d26fd1d7d0d0,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":337,""r"":60}", + 5059342, 1002, 0, 21850.1,chromobius,835bccb6454c5b0d19f244551b3afa80e1ccb466a49c97f711cd4ef3955263c0,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":60}", + 4667459, 1023, 0, 19031.8,chromobius,89ec710e7d4b71a21e6cf2e66e53a005a63b3339fc5e768da8bd652bbf4978cc,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":60}", + 4667459, 1947, 0, 40881.9,chromobius,89ec710e7d4b71a21e6cf2e66e53a005a63b3339fc5e768da8bd652bbf4978cc*835bccb6454c5b0d19f244551b3afa80e1ccb466a49c97f711cd4ef3955263c0,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":60}", + 50995, 1014, 0, 562.1,chromobius,d68a9c28a16b07b4b6ebbc0420feb53707c7cfbfd7f1f3135a37118bbcd3d88b,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":337,""r"":60}", + 47956, 1141, 0, 539.4,chromobius,bd6f5ff7061222689309674ef4ac59f8dccf7dc721477fec322aaba19cbd906e,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":337,""r"":60}", + 47956, 2072, 0, 1101.5,chromobius,bd6f5ff7061222689309674ef4ac59f8dccf7dc721477fec322aaba19cbd906e*d68a9c28a16b07b4b6ebbc0420feb53707c7cfbfd7f1f3135a37118bbcd3d88b,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":337,""r"":60}", + 4531, 1008, 0, 112.0,chromobius,83918a24650b3e68305bc2473cb05baa8c95ddc15d6fa9a9b58feb41c3d86dbe,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":337,""r"":60}", + 4412, 1038, 0, 102.3,chromobius,e1b2ca77f1071861586550a15bcb38daa6a0b3b02ff2a97121f59bed7a7269cf,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":337,""r"":60}", + 4412, 1789, 0, 214.3,chromobius,e1b2ca77f1071861586550a15bcb38daa6a0b3b02ff2a97121f59bed7a7269cf*83918a24650b3e68305bc2473cb05baa8c95ddc15d6fa9a9b58feb41c3d86dbe,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":337,""r"":60}", + 2041, 1038, 0, 124.7,chromobius,fa7faf8a5cdbb3a83596152325d8425f2c9b2413da91f356319d7df452c6735f,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":337,""r"":60}", + 1946, 1031, 0, 122.9,chromobius,d79dd0967f410404a41937f04df1ab999c1af795be0dd732ba25884514048514,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":337,""r"":60}", + 1946, 1496, 0, 247.6,chromobius,d79dd0967f410404a41937f04df1ab999c1af795be0dd732ba25884514048514*fa7faf8a5cdbb3a83596152325d8425f2c9b2413da91f356319d7df452c6735f,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":337,""r"":60}", + 2005, 1020, 0, 195.8,chromobius,e5dff405d05889d8e7d5d234db2dd81ca1531561ae5cbf761ce03fcef1b78d74,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":337,""r"":60}", + 2379, 1127, 0, 217.8,chromobius,c3619da456ce38806f683b1fce10304aeb4db39b62364e21d293cb106f70b70b,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":337,""r"":60}", + 2005, 1487, 0, 413.6,chromobius,e5dff405d05889d8e7d5d234db2dd81ca1531561ae5cbf761ce03fcef1b78d74*c3619da456ce38806f683b1fce10304aeb4db39b62364e21d293cb106f70b70b,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":337,""r"":60}", + 2150, 1096, 0, 272.2,chromobius,cc6cc09e5b77bd38bd1841135dbed7940a21841ca70312976743b5112c4dfafe,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":337,""r"":60}", + 2139, 1069, 0, 255.0,chromobius,931560f5ffa673a27396dfd75ac16c33942a823fd50bee3d569a57888882fcb5,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":337,""r"":60}", + 2139, 1614, 0, 527.2,chromobius,931560f5ffa673a27396dfd75ac16c33942a823fd50bee3d569a57888882fcb5*cc6cc09e5b77bd38bd1841135dbed7940a21841ca70312976743b5112c4dfafe,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":337,""r"":60}", + 2101, 1008, 0, 345.9,chromobius,bbf77b3b8f78205839d7584bae45ff29e00963972fcb13384b05f3913af14d3a,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":337,""r"":60}", + 1991, 1025, 0, 328.2,chromobius,e51fc1bb588cc698d711ffc6ac452aaa314b4ec9ce39af814dd0b28adb2d8199,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":337,""r"":60}", + 1991, 1488, 0, 674.1,chromobius,e51fc1bb588cc698d711ffc6ac452aaa314b4ec9ce39af814dd0b28adb2d8199*bbf77b3b8f78205839d7584bae45ff29e00963972fcb13384b05f3913af14d3a,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":337,""r"":60}", + 2050, 1006, 0, 434.2,chromobius,e41d8413ca85be607f9cfc948e64426ffe248b7a28d556839fcaafab8dc242a2,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":337,""r"":60}", + 2002, 1029, 0, 455.5,chromobius,92463c3bd843325a55c0566732934205672ec9e18889b36c99360de0f71f4c83,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":337,""r"":60}", + 2002, 1506, 0, 889.7,chromobius,92463c3bd843325a55c0566732934205672ec9e18889b36c99360de0f71f4c83*e41d8413ca85be607f9cfc948e64426ffe248b7a28d556839fcaafab8dc242a2,"{""c"":""superdense_color_code_XZ"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":337,""r"":60}", + 100000000, 0, 0, 63965.9,chromobius,7a0ba4621a055bc19544f8973656d86fe8b9f9ac38c9a41c66ec13f2624636dd,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":433,""r"":68}", + 100000000, 0, 0, 63726.5,chromobius,1186e769a66c49a4e6baa53f663073ecff6a420349fda34498298d72966fc059,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":433,""r"":68}", + 100000000, 0, 0,127692.4,chromobius,7a0ba4621a055bc19544f8973656d86fe8b9f9ac38c9a41c66ec13f2624636dd*1186e769a66c49a4e6baa53f663073ecff6a420349fda34498298d72966fc059,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":433,""r"":68}", + 100000000, 0, 0,121328.0,chromobius,d0adc4b92c7edd74bbe8fe7c43b03c9f14e7b3c294e2291d63b35a67826c10c1,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":433,""r"":68}", + 100000000, 2, 0,120714.6,chromobius,a62cd9e63fb0b9d8289b61b64ba66af6fedffc9e8a9e7466fed99ce8dbd2f7ed,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":433,""r"":68}", + 100000000, 2, 0,242042.6,chromobius,d0adc4b92c7edd74bbe8fe7c43b03c9f14e7b3c294e2291d63b35a67826c10c1*a62cd9e63fb0b9d8289b61b64ba66af6fedffc9e8a9e7466fed99ce8dbd2f7ed,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":433,""r"":68}", + 100000000, 1, 0,181912.7,chromobius,0f5fb94bd0cc99af0046da808acc8a5c9d17015981d960b8b1b47df4109a847b,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":433,""r"":68}", + 100000000, 3, 0,180642.6,chromobius,3f4dad285ef0876bf40c9358118d483336e4d92e5ffcb21b9962db07f594b0b0,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":433,""r"":68}", + 100000000, 4, 0,362555.3,chromobius,0f5fb94bd0cc99af0046da808acc8a5c9d17015981d960b8b1b47df4109a847b*3f4dad285ef0876bf40c9358118d483336e4d92e5ffcb21b9962db07f594b0b0,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":433,""r"":68}", + 100000000, 38, 0,315163.6,chromobius,c33c0f3479e0b364716eef8f7251beef6ce0e99692b33ded6864c896dfc4c523,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":433,""r"":68}", + 100000000, 56, 0,313227.6,chromobius,17aff9b2aab08e533d4dd707335ac04af1e93f3ca8d03cd6ba3c77deff6be3be,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":433,""r"":68}", + 100000000, 94, 0,628391.2,chromobius,c33c0f3479e0b364716eef8f7251beef6ce0e99692b33ded6864c896dfc4c523*17aff9b2aab08e533d4dd707335ac04af1e93f3ca8d03cd6ba3c77deff6be3be,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":433,""r"":68}", + 100000000, 424, 0,466971.8,chromobius,8dd9cb34920090fb5c5ef57080658efbd9bb5bf19877fdb2c2d104533e1803b3,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":433,""r"":68}", + 100000000, 586, 0,466700.6,chromobius,1591185f18dceeee426dc4cb279f2d32d2e1110b48808493b074e3ee7b38bd0b,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":433,""r"":68}", + 100000000, 1010, 0,933672.4,chromobius,8dd9cb34920090fb5c5ef57080658efbd9bb5bf19877fdb2c2d104533e1803b3*1591185f18dceeee426dc4cb279f2d32d2e1110b48808493b074e3ee7b38bd0b,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":433,""r"":68}", + 15455740, 1015, 0,113353.4,chromobius,03fee2a311f9f121de441a6e60993c6dfa8327f3033aa9e74445acb6322534d5,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":433,""r"":68}", + 13814885, 1003, 0,100808.5,chromobius,b1589c13747aa4f9951c1416986532a21ef5e7725ff766e58ab5aed5f498dc41,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":433,""r"":68}", + 13814885, 1910, 0,214161.9,chromobius,b1589c13747aa4f9951c1416986532a21ef5e7725ff766e58ab5aed5f498dc41*03fee2a311f9f121de441a6e60993c6dfa8327f3033aa9e74445acb6322534d5,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":433,""r"":68}", + 75891, 1002, 0, 1375.3,chromobius,c5465ecf5df23395db13250c1add62ab1183fecafab907f8bb40c521633ec621,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":433,""r"":68}", + 76249, 1119, 0, 1325.9,chromobius,00d47168225a87322c13878b763dbc66273c8b5fe8a33203dc265720f7cac5e6,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":433,""r"":68}", + 75891, 2101, 0, 2701.2,chromobius,c5465ecf5df23395db13250c1add62ab1183fecafab907f8bb40c521633ec621*00d47168225a87322c13878b763dbc66273c8b5fe8a33203dc265720f7cac5e6,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":433,""r"":68}", + 4803, 1045, 0, 219.6,chromobius,4aafff1bd1fe6e06f0791b718a1b2a453f815bafa89c94bd6f340b57f8c80828,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":433,""r"":68}", + 4514, 1012, 0, 193.9,chromobius,2b2732610eb91c271e60564283e6fba443ee17fa70a0f05516ae812471bfc5b7,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":433,""r"":68}", + 4514, 1774, 0, 413.5,chromobius,2b2732610eb91c271e60564283e6fba443ee17fa70a0f05516ae812471bfc5b7*4aafff1bd1fe6e06f0791b718a1b2a453f815bafa89c94bd6f340b57f8c80828,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":433,""r"":68}", + 1975, 1014, 0, 305.6,chromobius,e89034a0a9408b7812d679fd0b7220b0b5fc54cce8549c7a4868c8e478354f96,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":433,""r"":68}", + 2130, 1006, 0, 295.8,chromobius,62f6a550afeda1291eee41c7cd15df0be0f68e77fee1b4e8802f2fd5d7aa4346,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":433,""r"":68}", + 1975, 1468, 0, 601.4,chromobius,e89034a0a9408b7812d679fd0b7220b0b5fc54cce8549c7a4868c8e478354f96*62f6a550afeda1291eee41c7cd15df0be0f68e77fee1b4e8802f2fd5d7aa4346,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":433,""r"":68}", + 2086, 1052, 0, 517.2,chromobius,8cbdcd38e93fc5ba97b8c0775c1604a527ae83f28ebb5f3804e6faa5ee51eacc,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":433,""r"":68}", + 1997, 1001, 0, 463.4,chromobius,c3764ca359ffdde285286aa8bf90155f8b320724c74861a6b121fd77c6215a57,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":433,""r"":68}", + 1997, 1503, 0, 980.6,chromobius,c3764ca359ffdde285286aa8bf90155f8b320724c74861a6b121fd77c6215a57*8cbdcd38e93fc5ba97b8c0775c1604a527ae83f28ebb5f3804e6faa5ee51eacc,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":433,""r"":68}", + 1946, 1002, 0, 595.3,chromobius,61d9f83c9efcb02f431cdaee51756b81fb81ab64eafd3858706effaacfc44c4d,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":433,""r"":68}", + 1963, 1019, 0, 525.8,chromobius,a30fda2cd795cd296a5c88725589491dad49ecd9499b2f088a196ff76b357fa0,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":433,""r"":68}", + 1946, 1492, 0, 1121.1,chromobius,61d9f83c9efcb02f431cdaee51756b81fb81ab64eafd3858706effaacfc44c4d*a30fda2cd795cd296a5c88725589491dad49ecd9499b2f088a196ff76b357fa0,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":433,""r"":68}", + 2119, 1053, 0, 750.0,chromobius,627854b994632eec182bc4b6de0e072f01e43c6d08ce3b21d0d0d116148c87c1,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":433,""r"":68}", + 2021, 1006, 0, 760.4,chromobius,d144196df21be4aaaeb80d9ba6ef0fab4a04bfd3a1b01faf60f116e4f8d6d27b,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":433,""r"":68}", + 2021, 1510, 0, 1510.4,chromobius,d144196df21be4aaaeb80d9ba6ef0fab4a04bfd3a1b01faf60f116e4f8d6d27b*627854b994632eec182bc4b6de0e072f01e43c6d08ce3b21d0d0d116148c87c1,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":433,""r"":68}", + 2017, 1004, 0, 1001.5,chromobius,3e9d56bc14ae5076ba4920d9c2ff9999971bbc988b78602bb611cf5e0676aeb7,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":433,""r"":68}", + 2023, 1013, 0, 1196.5,chromobius,9251a7a4ce5db9ebf310823c777190384b5855a55e9f6ae3da5b17bcdaca632e,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":433,""r"":68}", + 2017, 1511, 0, 2198.0,chromobius,3e9d56bc14ae5076ba4920d9c2ff9999971bbc988b78602bb611cf5e0676aeb7*9251a7a4ce5db9ebf310823c777190384b5855a55e9f6ae3da5b17bcdaca632e,"{""c"":""superdense_color_code_XZ"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":433,""r"":68}", + 100000000, 0, 0, 96257.3,chromobius,bc0512f55913508647d37b5e248940ddbee64109de43bcd87749867d88be3eb5,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":541,""r"":76}", + 100000000, 0, 0, 95749.1,chromobius,1d911ab31834b89f06f4860f48d34569dfec53617857a658d91242d28da6e582,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":541,""r"":76}", + 100000000, 0, 0,192006.4,chromobius,bc0512f55913508647d37b5e248940ddbee64109de43bcd87749867d88be3eb5*1d911ab31834b89f06f4860f48d34569dfec53617857a658d91242d28da6e582,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":541,""r"":76}", + 100000000, 0, 0,184039.1,chromobius,35041ba76918bbc7d576e1764345963414287476c64ce1d2ed293404706c2971,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":541,""r"":76}", + 100000000, 0, 0,183201.6,chromobius,f296ba1fa78002abbab29c8e8edcf0dde2a0958f7ae6d5e56633fc61966ac88b,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":541,""r"":76}", + 100000000, 0, 0,367240.7,chromobius,35041ba76918bbc7d576e1764345963414287476c64ce1d2ed293404706c2971*f296ba1fa78002abbab29c8e8edcf0dde2a0958f7ae6d5e56633fc61966ac88b,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":541,""r"":76}", + 100000000, 0, 0,279668.1,chromobius,bc0a62e6b3d0f3c363783e84835154ee53bd3a5715f03d4fa048889a540c245b,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":541,""r"":76}", + 100000000, 0, 0,277259.5,chromobius,df3b28e56018ccd96e423ccf45c65375c1311b0530f6c181e9734a6b4fa0a449,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":541,""r"":76}", + 100000000, 0, 0,556927.6,chromobius,bc0a62e6b3d0f3c363783e84835154ee53bd3a5715f03d4fa048889a540c245b*df3b28e56018ccd96e423ccf45c65375c1311b0530f6c181e9734a6b4fa0a449,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":541,""r"":76}", + 100000000, 11, 0,496936.4,chromobius,595277ca68e5d7b70660d60adceaf9ae7f0ce321ff9c310ba94910cb344bb7fe,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":541,""r"":76}", + 100000000, 10, 0,493444.7,chromobius,2653efb1cbb2c9c735c5364fe4ea2e336952ad4f007329a439748ca71b8e3737,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":541,""r"":76}", + 100000000, 21, 0,990381.1,chromobius,595277ca68e5d7b70660d60adceaf9ae7f0ce321ff9c310ba94910cb344bb7fe*2653efb1cbb2c9c735c5364fe4ea2e336952ad4f007329a439748ca71b8e3737,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":541,""r"":76}", + 100000000, 128, 0,754569.5,chromobius,257d1684eb1e14f36a00c32e5ad76722a2d289366b3eeae64b3020a7f5d429b6,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":541,""r"":76}", + 100000000, 131, 0,748853.5,chromobius,6f75b9ad97afd02299f25e0605e22e24567e16a2edea54a42475f3bf9e35eed1,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":541,""r"":76}", + 100000000, 259, 0,1503423.0,chromobius,257d1684eb1e14f36a00c32e5ad76722a2d289366b3eeae64b3020a7f5d429b6*6f75b9ad97afd02299f25e0605e22e24567e16a2edea54a42475f3bf9e35eed1,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":541,""r"":76}", + 50587181, 1002, 0,608899.5,chromobius,63c7a7c442f3a168c5fe47515adb6c1e3d514c921a6f51344e5bb92bd8f2617c,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":541,""r"":76}", + 44816945, 1011, 0,536932.5,chromobius,60026fec3c01ce9bb684cf3f73f5d350bccd41261548676d8d986a1f7ba3005e,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":541,""r"":76}", + 44816945, 1899, 0,1145832.0,chromobius,60026fec3c01ce9bb684cf3f73f5d350bccd41261548676d8d986a1f7ba3005e*63c7a7c442f3a168c5fe47515adb6c1e3d514c921a6f51344e5bb92bd8f2617c,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":541,""r"":76}", + 111849, 1016, 0, 3118.0,chromobius,fe5181b636f0920a695614b9b1367d999636efa63545bcad954eef94acd5b5c1,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":541,""r"":76}", + 102206, 1031, 0, 2781.5,chromobius,a09afc3f0563cf60e8064a42e0b00ba7d8ec5fe3229d7b2801d76e3cdd01ba78,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":541,""r"":76}", + 102206, 1950, 0, 5899.5,chromobius,a09afc3f0563cf60e8064a42e0b00ba7d8ec5fe3229d7b2801d76e3cdd01ba78*fe5181b636f0920a695614b9b1367d999636efa63545bcad954eef94acd5b5c1,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":541,""r"":76}", + 4956, 1010, 0, 324.3,chromobius,3992f7f96d0101e23d0f31d0ea252df75a2eb2a3ebe79c8b6299866f912a3d83,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":541,""r"":76}", + 4817, 1028, 0, 281.5,chromobius,79f8d1935c0713dcdd25f8e9d696fb45e4da22e3728ccfd3ddaca522c70a3801,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":541,""r"":76}", + 4817, 1800, 0, 605.8,chromobius,79f8d1935c0713dcdd25f8e9d696fb45e4da22e3728ccfd3ddaca522c70a3801*3992f7f96d0101e23d0f31d0ea252df75a2eb2a3ebe79c8b6299866f912a3d83,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":541,""r"":76}", + 2298, 1078, 0, 741.4,chromobius,1aa0a732ba837447dc05adc6c51ee92a118fc948c96630c57fe0d4d3acdbf737,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":541,""r"":76}", + 2023, 1014, 0, 696.2,chromobius,681e7cbe73c29a99820b332e39e4870eb538ffad920c427725fbe718a5186ce3,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":541,""r"":76}", + 2023, 1487, 0, 1437.6,chromobius,681e7cbe73c29a99820b332e39e4870eb538ffad920c427725fbe718a5186ce3*1aa0a732ba837447dc05adc6c51ee92a118fc948c96630c57fe0d4d3acdbf737,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":541,""r"":76}", + 2031, 1012, 0, 1017.8,chromobius,f0620cf85e9079fb287cae9c5ae7954b47e660009f2ae41a89b2807a5ab0788f,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":541,""r"":76}", + 2007, 1002, 0, 914.3,chromobius,9c50b6134a0764fffdbec8bece370c136bafb25ce9f54e1348f0d56581f29a26,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":541,""r"":76}", + 2007, 1503, 0, 1932.1,chromobius,9c50b6134a0764fffdbec8bece370c136bafb25ce9f54e1348f0d56581f29a26*f0620cf85e9079fb287cae9c5ae7954b47e660009f2ae41a89b2807a5ab0788f,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":541,""r"":76}", + 2003, 1004, 0, 1399.7,chromobius,27170755f4794baff4f866db6a5624f2b9d97b93f0ab470b88e72ac7c964d624,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":541,""r"":76}", + 2052, 1031, 0, 1403.3,chromobius,7eedaaa5d6703a6070a8f17af3220d476de23fa13e0169944e1f790e67e88d34,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":541,""r"":76}", + 2003, 1506, 0, 2803.0,chromobius,27170755f4794baff4f866db6a5624f2b9d97b93f0ab470b88e72ac7c964d624*7eedaaa5d6703a6070a8f17af3220d476de23fa13e0169944e1f790e67e88d34,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":541,""r"":76}", + 2173, 1093, 0, 1806.4,chromobius,50e763cde18ed4d10b24987e6e449053cfdf48e81c3a32bd89445e350379372f,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":541,""r"":76}", + 1969, 1011, 0, 1960.5,chromobius,6e94874e9e1e33a5952425024cd31c884e83f1916b3dce79e510cb405741d316,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":541,""r"":76}", + 1969, 1493, 0, 3766.9,chromobius,6e94874e9e1e33a5952425024cd31c884e83f1916b3dce79e510cb405741d316*50e763cde18ed4d10b24987e6e449053cfdf48e81c3a32bd89445e350379372f,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":541,""r"":76}", + 2150, 1044, 0, 2724.6,chromobius,fbe7d3bad5abd643d7899cc0a84a102ed5d674911280c1e9b07428802c660468,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":541,""r"":76}", + 2158, 1045, 0, 3395.6,chromobius,b3e87fdfb57f3522c535c98ec74f9f774518f1f150ea7310b8314dd9aa91f9f7,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":541,""r"":76}", + 2150, 1580, 0, 6120.2,chromobius,fbe7d3bad5abd643d7899cc0a84a102ed5d674911280c1e9b07428802c660468*b3e87fdfb57f3522c535c98ec74f9f774518f1f150ea7310b8314dd9aa91f9f7,"{""c"":""superdense_color_code_XZ"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":541,""r"":76}", + 153608, 1104, 0, 0.528,sparse_blossom_correlated,6a503e9c621b43c98050b74037f941d90456e4596621aa437f3819f48cff73e8,"{""c"":""surface_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 352602, 2065, 0, 1.05,sparse_blossom_correlated,83307e1500a1cd2c4929cbee230ccdc5f4768c680549daee951043bae40d7045,"{""c"":""surface_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 153608, 1997, 0, 1.58,sparse_blossom_correlated,6a503e9c621b43c98050b74037f941d90456e4596621aa437f3819f48cff73e8*83307e1500a1cd2c4929cbee230ccdc5f4768c680549daee951043bae40d7045,"{""c"":""surface_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 146231, 1034, 0, 1.50,pymatching,697c75b0fe8c8f0bb8854c043c8ddf1677b8c0679e42ce7f8a39c55f94a5ba5a,"{""c"":""surface_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 280637, 2017, 0, 2.39,pymatching,9455785765903a7c55e100a7dde446c56531158262f02c42823b1909a4d5fd08,"{""c"":""surface_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 146231, 2078, 0, 3.89,pymatching,697c75b0fe8c8f0bb8854c043c8ddf1677b8c0679e42ce7f8a39c55f94a5ba5a*9455785765903a7c55e100a7dde446c56531158262f02c42823b1909a4d5fd08,"{""c"":""surface_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 137757, 1001, 0, 0.989,chromobius,bec74326d3f3c88f0d987ca22c00851f9576f3a5274947c65e92c5335a3ed170,"{""c"":""surface_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 128658, 1025, 0, 0.689,chromobius,854f222596cb2f10b7bb1eb870a1a4e9ef30a6c6fc3842372683d78355473b81,"{""c"":""surface_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 128658, 1952, 0, 1.68,chromobius,854f222596cb2f10b7bb1eb870a1a4e9ef30a6c6fc3842372683d78355473b81*bec74326d3f3c88f0d987ca22c00851f9576f3a5274947c65e92c5335a3ed170,"{""c"":""surface_code_XZ"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 1253641, 1068, 0, 18.3,sparse_blossom_correlated,e0bc53ee7428f3d16a7595d83dd720f6cd6dc2230748eb413f02d7bd4d74dcbc,"{""c"":""surface_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 2512149, 2065, 0, 41.4,sparse_blossom_correlated,57846f538dc905e7864102720c00db0161114362d4c275790bbc53013fcfce3c,"{""c"":""surface_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 1253641, 2098, 0, 59.7,sparse_blossom_correlated,e0bc53ee7428f3d16a7595d83dd720f6cd6dc2230748eb413f02d7bd4d74dcbc*57846f538dc905e7864102720c00db0161114362d4c275790bbc53013fcfce3c,"{""c"":""surface_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 784961, 1005, 0, 5.96,pymatching,9693ad406199b4d3598217aaf5dec1d328d07d00832238a77229ae42a77f44fc,"{""c"":""surface_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 1377382, 2044, 0, 9.93,pymatching,2d467206ca6bcd2281618cb8731455e851c7b75277b62a22a365c8cf6923000d,"{""c"":""surface_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 784961, 2168, 0, 15.9,pymatching,9693ad406199b4d3598217aaf5dec1d328d07d00832238a77229ae42a77f44fc*2d467206ca6bcd2281618cb8731455e851c7b75277b62a22a365c8cf6923000d,"{""c"":""surface_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 660290, 1000, 0, 18.0,chromobius,e9e8bee0c9d8a26fe84c08dc449d7569cb532bab5f8efe24d1b5d572c6a990b9,"{""c"":""surface_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 654037, 1015, 0, 17.6,chromobius,77440067e6de31fd01c59d0c1ed2c4b6582c3cb2529e94492696fa26a2ea0031,"{""c"":""surface_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 654037, 2004, 0, 35.6,chromobius,77440067e6de31fd01c59d0c1ed2c4b6582c3cb2529e94492696fa26a2ea0031*e9e8bee0c9d8a26fe84c08dc449d7569cb532bab5f8efe24d1b5d572c6a990b9,"{""c"":""surface_code_XZ"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 8218476, 1880, 0, 155.0,pymatching,bc47816ee2851ac36ac17a54abd23bb54cb6496d4813674577fa2e159b11a597,"{""c"":""surface_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 9272439, 2140, 0, 174.1,pymatching,39892a5feda4ea15ed66b013f897982fdb52015d3820fe7b667316cccfc573e0,"{""c"":""surface_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 8218476, 3776, 0, 329.1,pymatching,bc47816ee2851ac36ac17a54abd23bb54cb6496d4813674577fa2e159b11a597*39892a5feda4ea15ed66b013f897982fdb52015d3820fe7b667316cccfc573e0,"{""c"":""surface_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 25221948, 1912, 0, 1334.2,sparse_blossom_correlated,b124075756aabdca1bf960ff7809884079c65a742dac2e99605a5d7bd652bdde,"{""c"":""surface_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 27367877, 2138, 0, 1461.4,sparse_blossom_correlated,9d1abed3b0e4e6af6c87bcbce8600d28dc233fde4435461e31c32d1ec0ed8f7d,"{""c"":""surface_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 25221948, 3882, 0, 2795.6,sparse_blossom_correlated,b124075756aabdca1bf960ff7809884079c65a742dac2e99605a5d7bd652bdde*9d1abed3b0e4e6af6c87bcbce8600d28dc233fde4435461e31c32d1ec0ed8f7d,"{""c"":""surface_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 3981680, 1040, 0, 467.8,chromobius,ebddac421f103f01175109db03401f2c75482a8b777a3b94e0494619f2f1aafc,"{""c"":""surface_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 4043037, 1062, 0, 432.7,chromobius,f46c8e39b28b055bc89408d066b7de236600bcd332ca93c303c26fcf333c80f0,"{""c"":""surface_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 3981680, 2086, 0, 900.5,chromobius,ebddac421f103f01175109db03401f2c75482a8b777a3b94e0494619f2f1aafc*f46c8e39b28b055bc89408d066b7de236600bcd332ca93c303c26fcf333c80f0,"{""c"":""surface_code_XZ"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 59718318, 1911, 0, 2614.8,pymatching,04c820ba3305bf235323259d7d84dab9f2534792e1a5352d9827e02c53899b57,"{""c"":""surface_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 63697703, 2090, 0, 2793.9,pymatching,03d0e75ec80a9b2c50dc77e3e46f314596cda25e65479c2343fbe0763c8c7749,"{""c"":""surface_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 59718318, 3870, 0, 5408.7,pymatching,04c820ba3305bf235323259d7d84dab9f2534792e1a5352d9827e02c53899b57*03d0e75ec80a9b2c50dc77e3e46f314596cda25e65479c2343fbe0763c8c7749,"{""c"":""surface_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 190000000, 1207, 0, 25104.3,sparse_blossom_correlated,06f8dd42d59cc3ebcb4dc484142820e31dd4f93386d09c9ae9e168e41a2c0522,"{""c"":""surface_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 200000000, 1377, 0, 26888.8,sparse_blossom_correlated,3cdd251def8b19af03a9128d9d9f62217f05ab0030bf11e53e54b2773c6f574c,"{""c"":""surface_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 190000000, 2515, 0, 51993.1,sparse_blossom_correlated,06f8dd42d59cc3ebcb4dc484142820e31dd4f93386d09c9ae9e168e41a2c0522*3cdd251def8b19af03a9128d9d9f62217f05ab0030bf11e53e54b2773c6f574c,"{""c"":""surface_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 28078633, 1046, 0, 9064.5,chromobius,a29886a7e1df23fbc1bbee2e6171a8833ffe72110d79e33a360414916a02e9a1,"{""c"":""surface_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 28399245, 1014, 0, 8360.7,chromobius,7ae59f1556315300007ec6f8c172a45f5987e4c430bb4c5c2ca9bf0794d7d771,"{""c"":""surface_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 28078633, 2049, 0, 17425.2,chromobius,a29886a7e1df23fbc1bbee2e6171a8833ffe72110d79e33a360414916a02e9a1*7ae59f1556315300007ec6f8c172a45f5987e4c430bb4c5c2ca9bf0794d7d771,"{""c"":""surface_code_XZ"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 190000000, 822, 0, 16652.8,pymatching,f6907102f2beab78ccae65ac21025cd436f657b998d6fa507a911f0a428ffd81,"{""c"":""surface_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 200000000, 882, 0, 17694.8,pymatching,08c5dd4220cb10eb91e15bb91a2b09c8517b68775748a468d3267ab46dc0cf81,"{""c"":""surface_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 190000000, 1660, 0, 34347.6,pymatching,f6907102f2beab78ccae65ac21025cd436f657b998d6fa507a911f0a428ffd81*08c5dd4220cb10eb91e15bb91a2b09c8517b68775748a468d3267ab46dc0cf81,"{""c"":""surface_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 190000000, 104, 0, 58193.1,sparse_blossom_correlated,418c5bdcf2fc4891e86debb75217b707bd699b0b76652f7fef25f235537f095c,"{""c"":""surface_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 200000000, 114, 0, 61385.1,sparse_blossom_correlated,ab3ce740be420fd9d0a0adb558a4c70d5f5d3efac11f7ae0ee5f809674601ad5,"{""c"":""surface_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 190000000, 212, 0,119578.2,sparse_blossom_correlated,418c5bdcf2fc4891e86debb75217b707bd699b0b76652f7fef25f235537f095c*ab3ce740be420fd9d0a0adb558a4c70d5f5d3efac11f7ae0ee5f809674601ad5,"{""c"":""surface_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 100000000, 499, 0, 66752.6,chromobius,2c4973abf8d0a4d64b8404b7f729fde73ab9c0b5a94230534bf3922835bd4802,"{""c"":""surface_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 100000000, 515, 0, 67266.1,chromobius,624669dc186ce48112eeda077d849157e06111c467e74e8e5febdc9cafa8caa9,"{""c"":""surface_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 100000000, 1014, 0,134018.7,chromobius,2c4973abf8d0a4d64b8404b7f729fde73ab9c0b5a94230534bf3922835bd4802*624669dc186ce48112eeda077d849157e06111c467e74e8e5febdc9cafa8caa9,"{""c"":""surface_code_XZ"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 200000000, 89, 0, 32760.0,pymatching,dbd37b4251fc121571f81d1d01f2654b70e6697365fa1eb5679231f432f21a9b,"{""c"":""surface_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 200000000, 107, 0, 33119.1,pymatching,4d8d103fb1ce5da21e08b89e35f2fbc9e8db43bbb844fbff4b96ec1e081b63b4,"{""c"":""surface_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 200000000, 196, 0, 65879.1,pymatching,dbd37b4251fc121571f81d1d01f2654b70e6697365fa1eb5679231f432f21a9b*4d8d103fb1ce5da21e08b89e35f2fbc9e8db43bbb844fbff4b96ec1e081b63b4,"{""c"":""surface_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 200000000, 8, 0,123514.8,sparse_blossom_correlated,19a56d2e5f0fb1d1873514a024ea745833e86894cd42a1890aae83063a5bba78,"{""c"":""surface_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 200000000, 5, 0,124137.0,sparse_blossom_correlated,b9dac8df5d51d2fd600e9c7d2ec1cdcc54aa2e52e8513c27306a043c724f68cf,"{""c"":""surface_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 200000000, 13, 0,247651.8,sparse_blossom_correlated,19a56d2e5f0fb1d1873514a024ea745833e86894cd42a1890aae83063a5bba78*b9dac8df5d51d2fd600e9c7d2ec1cdcc54aa2e52e8513c27306a043c724f68cf,"{""c"":""surface_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 100000000, 68, 0,125860.7,chromobius,4d787badac11c09ef4c051a852221c97b341183114bbcccfacf57da5cb46b313,"{""c"":""surface_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 100000000, 65, 0,125887.0,chromobius,614b9f479387aff09d2141b7a29f4bca39076df2c68fb54def75a8591fda8826,"{""c"":""surface_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 100000000, 133, 0,251747.7,chromobius,4d787badac11c09ef4c051a852221c97b341183114bbcccfacf57da5cb46b313*614b9f479387aff09d2141b7a29f4bca39076df2c68fb54def75a8591fda8826,"{""c"":""surface_code_XZ"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 100000000, 248, 0, 420.3,chromobius,d4a71418dfb8ba44e897ef05995ffaab6182c744e111e1042b3a605db1535331,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":92,""r"":1}", + 10110244, 1076, 0, 78.8,chromobius,9f82c54efc2259b1e27196f90765a3eade2ccdcb4774316cb5b95b2d23e77b4b,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":92,""r"":1}", + 1201031, 1083, 0, 13.9,chromobius,0f8c251c3ee3d69cc9210702a3f5ec27099b5ea2ad3a3542f7f38e9a1e680d2c,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":92,""r"":1}", + 322632, 1111, 0, 5.09,chromobius,daac099af17edf2be34a2efb9b3429188aff5cca3329345d40496743dbc3db2a,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":92,""r"":1}", + 100304, 1090, 0, 1.92,chromobius,b537dcee78a66952db6ba5dd41ce4c077129590972f8726cc5b3658250e899f4,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":92,""r"":1}", + 42051, 1073, 0, 0.960,chromobius,d006153fb065b4dd261a9bde47a0bb36781c21fe976c4d8cbdf63ba561fa4b74,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":92,""r"":1}", + 22397, 1092, 0, 0.635,chromobius,c28ece34904ec871104a15f74026c575bf550a1715e6a840383ee2ec90d1cb26,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":92,""r"":1}", + 13052, 1073, 0, 0.369,chromobius,000f4a11065ab155bc8c613f0361236c86ca8e5f901b8acd06b01635b0f5fb1a,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":92,""r"":1}", + 8580, 1001, 0, 0.297,chromobius,85c6ffc109edcdfd4da5d6b7e9867edef69e1147f9358c19e78228cb2abb9f76,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":92,""r"":1}", + 6546, 1108, 0, 0.278,chromobius,2b838c4372c81e03111e91f15b735a5219b3bd48560cf1efbe04c6539fca44a4,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":92,""r"":1}", + 100000000, 3, 0, 809.1,chromobius,0e085bb768a58041b03ee041b200ed664119145ba363d5f6e08af420f6632596,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":170,""r"":1}", + 100000000, 812, 0, 1528.6,chromobius,8128531c9100b503dd58af3d25f092c8d3b6ad82c503eb66a669f76fef6524f4,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":170,""r"":1}", + 6172512, 1000, 0, 140.1,chromobius,fdb0b46727af31d3271ba8eca27a908986accb5b4eba8b4e0b2f029d4e4de6e6,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":170,""r"":1}", + 909810, 1034, 0, 27.7,chromobius,d4d621afe1aeb8b09debb49a4b197ca527e033a06fc32a4cdecabd5333998c5a,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":170,""r"":1}", + 205234, 1052, 0, 8.20,chromobius,7b34af65e15ac329cf8f2fd7971211975b8e85b0fe67c2ba717510a119f22bb1,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":170,""r"":1}", + 60828, 1001, 0, 3.02,chromobius,533fcd0a01890c785fd211c777769df096db32b666417536f70ae275b5d3083f,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":170,""r"":1}", + 30274, 1077, 0, 1.80,chromobius,29c64f4d0ef7a3679bb14273c6b318e9ff96745a720773c30a3cb082362cb546,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":170,""r"":1}", + 14219, 1046, 0, 0.967,chromobius,c197e6ca718fbec4eb3548c5bb2045cfa27399bb80108db88c4f1b3409b040ae,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":170,""r"":1}", + 8520, 1010, 0, 0.684,chromobius,d3bf8eac1ed9b9ecafcee190960d56de0341edbccbd80ca64fadf1a1f0e11103,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":170,""r"":1}", + 6316, 1043, 0, 0.542,chromobius,87c67518518fb0fb2f7c1b626b81e71d6ccbf344ca1890426deeb8d2bba3475a,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":170,""r"":1}", + 100000000, 0, 0, 1330.8,chromobius,a68cd5375316f2f31714a16bf2dd9034c4b9610e5f9ff4d82a26012778f9275e,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":272,""r"":1}", + 100000000, 59, 0, 2521.8,chromobius,4fbc4a9882331c0561e1c34774b924574e0a8bc87cb87787c3ca6b0d7fb92a0c,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":272,""r"":1}", + 37739958, 1007, 0, 1436.5,chromobius,8db3db2ec5078dd19b28f43ddd07a4dac3775400e17181e998645e9b900fcc38,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":272,""r"":1}", + 2793296, 1010, 0, 142.5,chromobius,7df1bab624008fa773926222058036fbd3bf25b3d5d4ed4414277415045c4029,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":272,""r"":1}", + 431859, 1038, 0, 28.3,chromobius,98eb27949cfe815a9ab3770e0c8c224cc34b4d0ab38b36fa8f19306429de67d8,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":272,""r"":1}", + 103169, 1011, 0, 8.56,chromobius,ffb4b3b9f0187f0fab403baa4accb87b2358c28a60ecd050bb6c15cdad1b5a3a,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":272,""r"":1}", + 37086, 1002, 0, 3.83,chromobius,cab6041a80f90180ace3ed1a6d3e0b536cc9d9ea613ad83d81d4e538bcaf8471,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":272,""r"":1}", + 15951, 1002, 0, 1.99,chromobius,c8cbd6242d276dfc2e857e04bde68adebd48467c02037c791e0f56f5b37b114c,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":272,""r"":1}", + 8645, 1002, 0, 1.25,chromobius,83e445e72f679db26a360f5c384eaa347500375ef1509f4999f5322299897de2,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":272,""r"":1}", + 5306, 1008, 0, 0.884,chromobius,83a1e30546f611644a488eaa8c4c9394d3ac4e3faa21b1672b2ed92b775782b1,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":272,""r"":1}", + 100000000, 0, 0, 1981.8,chromobius,eaef0a5ffd759253cea3bee87b6b3d2edb1794294d5f00cd16d29ec7604e6adb,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":398,""r"":1}", + 100000000, 1, 0, 3777.6,chromobius,7dd80613aa4f2870c4b3be04a799d165f65ccdd060dd402aacaa05f4d58d4f29,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":398,""r"":1}", + 100000000, 440, 0, 5717.8,chromobius,e4e7f904c98dc5872afeabf4d01d89ee873a3988fb23a1b7b3f2f680835f861b,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":398,""r"":1}", + 9847638, 1092, 0, 766.1,chromobius,2925e42ca2eb5d9b38d55af0f4d562293b3b1740090414e28a03b759a8603e93,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":398,""r"":1}", + 875350, 1038, 0, 87.0,chromobius,9dceba08235b7895086cb92b47c4b8b46671fa5b7f0b53470b427fabe01ebac6,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":398,""r"":1}", + 174439, 1035, 0, 22.0,chromobius,1b9705ba82bbbf09046e763e6fb58e7087b4f33f004e2317276c880ae8ea6b29,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":398,""r"":1}", + 50400, 1120, 0, 7.95,chromobius,18a1426a5e85b77dcf892a6b8ae73d8032b4fa5969f6459dbe012787ff16d9bd,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":398,""r"":1}", + 18792, 1039, 0, 3.67,chromobius,9f1b5f4cfdeed7c9762526e0c983e0ab6f2086e2a780e485e78fc5bd2f53fe7d,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":398,""r"":1}", + 8355, 1001, 0, 1.97,chromobius,78f27d71f3dd4eb1a67b6281a6f91724b3c08c544a5a1ec202f50057894e0203,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":398,""r"":1}", + 5258, 1005, 0, 1.44,chromobius,8539e1e288569de509d42bf1d7a7a5b91e675ff33e3fbe32516f99316b2ca271,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":398,""r"":1}", + 100000000, 0, 0, 2782.1,chromobius,390b97bb4775ee4b30775be7ab252fd576a54aedbca47ebe6e99a09c1d5eb852,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":548,""r"":1}", + 100000000, 0, 0, 5301.9,chromobius,0afda8f09a9dc6a573aabda11f54b90e8cee72562803ec3666207249651220e8,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":548,""r"":1}", + 100000000, 85, 0, 8067.2,chromobius,c6cac227deae57b94c776010af4ec8611c47a4292d61428135d111079ece5b63,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":548,""r"":1}", + 30453744, 1033, 0, 3367.8,chromobius,12b2c265dec8616ebdacad5279bdba7b5651865a9b5b03f984f860abf5d0af39,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":548,""r"":1}", + 2158053, 1070, 0, 306.0,chromobius,153b89a8722cb44369822695f2dc9ffdafffba5db3de976765556140e8de7b4a,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":548,""r"":1}", + 281707, 1032, 0, 50.3,chromobius,9fb0b0a854e7ea50134107034e4e3dafb4faaca550aff6a3bb92caa0cd0dba40,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":548,""r"":1}", + 58714, 1003, 0, 13.2,chromobius,ee0d8eb1ad52099a6b6f113ffb66937ab387a98d157a06710a216771328eb5c6,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":548,""r"":1}", + 19996, 1108, 0, 5.53,chromobius,7a3258cc1f8c33e06fd6a1a8c507ccf3ddb5f9ea97be0781a556471b54c2539a,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":548,""r"":1}", + 8498, 1012, 0, 2.79,chromobius,76c03a2ad8c41bcac1870bbdb6b4bdd4e33307f4948d3dda45bb60dbebd2eacb,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":548,""r"":1}", + 5018, 1005, 0, 1.93,chromobius,5a3daef5692cf25cfc2498456cb7c72c7f95f0a6accd68c7d7e94042a1e9f437,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":548,""r"":1}", + 100000000, 0, 0, 3739.7,chromobius,a0ab1b00031fb52d44364d35b799ca1b8f9457c271bd1986ce1034a56003dc09,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":722,""r"":1}", + 100000000, 1, 0, 7164.1,chromobius,ec2b42cda8effd3114adf9992a3773ec64c40601bc8e787bf2ead6c258a3bed2,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":722,""r"":1}", + 100000000, 13, 0, 10834.6,chromobius,db8b54b82aa5ac0632fb5717d9962b0293fff60aac088fb342a96018401c2629,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":722,""r"":1}", + 100000000, 912, 0, 14705.0,chromobius,b26afac9aed873db86127ddf8cc0412a1729fa253e45da53732378196cfe91b9,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":722,""r"":1}", + 4444063, 1014, 0, 850.3,chromobius,bd8018eebde7be227813c18a1ca1776cb6ac89300c36898e155ad6a2cd9cd527,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":722,""r"":1}", + 436110, 1001, 0, 105.5,chromobius,baac476bafffdb2b430b393f8a79273d81a6dc6b5a376dd03f259bbf80ae5f2e,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":722,""r"":1}", + 83492, 1105, 0, 25.4,chromobius,6606a8146c07234564338a7262fa3b87471cc222d5fcfaa25df571f857f39fa5,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":722,""r"":1}", + 21162, 1002, 0, 8.02,chromobius,57d528f281f1415ac1f179914b24b67ada1b5bdf4f7d21d2eb7161860bde47a5,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":722,""r"":1}", + 8940, 1030, 0, 4.12,chromobius,559d2abf23921ecd09405d4b3db0f31c2b42499937a17634b1f1f0516d82ed37,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":722,""r"":1}", + 4837, 1037, 0, 2.65,chromobius,4b194c42e3073a19785c86de55ba1b1e71a0a444705fc106b631160e24d1d554,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":722,""r"":1}", diff --git a/assets/generated/superdense_error_X.png b/assets/generated/superdense_error_X.png new file mode 100644 index 0000000..4f2c6f7 Binary files /dev/null and b/assets/generated/superdense_error_X.png differ diff --git a/assets/generated/superdense_error_XZ.png b/assets/generated/superdense_error_XZ.png new file mode 100644 index 0000000..3594139 Binary files /dev/null and b/assets/generated/superdense_error_XZ.png differ diff --git a/assets/generated/superdense_error_Z.png b/assets/generated/superdense_error_Z.png new file mode 100644 index 0000000..5c0435b Binary files /dev/null and b/assets/generated/superdense_error_Z.png differ diff --git a/assets/generated/superdense_footprint_X.png b/assets/generated/superdense_footprint_X.png new file mode 100644 index 0000000..57693b0 Binary files /dev/null and b/assets/generated/superdense_footprint_X.png differ diff --git a/assets/generated/superdense_footprint_XZ.png b/assets/generated/superdense_footprint_XZ.png new file mode 100644 index 0000000..7ea20da Binary files /dev/null and b/assets/generated/superdense_footprint_XZ.png differ diff --git a/assets/generated/superdense_footprint_Z.png b/assets/generated/superdense_footprint_Z.png new file mode 100644 index 0000000..47e13b9 Binary files /dev/null and b/assets/generated/superdense_footprint_Z.png differ diff --git a/assets/generated/timing_d.png b/assets/generated/timing_d.png new file mode 100644 index 0000000..eb36532 Binary files /dev/null and b/assets/generated/timing_d.png differ diff --git a/assets/generated/timing_d_full.png b/assets/generated/timing_d_full.png new file mode 100644 index 0000000..262dfbc Binary files /dev/null and b/assets/generated/timing_d_full.png differ diff --git a/assets/generated/timing_r.png b/assets/generated/timing_r.png new file mode 100644 index 0000000..cb9cb6d Binary files /dev/null and b/assets/generated/timing_r.png differ diff --git a/assets/generated/timing_r_full.png b/assets/generated/timing_r_full.png new file mode 100644 index 0000000..25d69f8 Binary files /dev/null and b/assets/generated/timing_r_full.png differ diff --git a/assets/generated/timing_rq.png b/assets/generated/timing_rq.png new file mode 100644 index 0000000..a73db0c Binary files /dev/null and b/assets/generated/timing_rq.png differ diff --git a/assets/generated/timing_rq_full.png b/assets/generated/timing_rq_full.png new file mode 100644 index 0000000..12b53a0 Binary files /dev/null and b/assets/generated/timing_rq_full.png differ diff --git a/assets/generated/toric.png b/assets/generated/toric.png new file mode 100644 index 0000000..5e1526b Binary files /dev/null and b/assets/generated/toric.png differ diff --git a/assets/midout-detslice-cycle.png b/assets/midout-detslice-cycle.png new file mode 100644 index 0000000..195b81e Binary files /dev/null and b/assets/midout-detslice-cycle.png differ diff --git a/assets/midout-detslice-cycle.svg b/assets/midout-detslice-cycle.svg new file mode 100644 index 0000000..ec61bc5 --- /dev/null +++ b/assets/midout-detslice-cycle.svg @@ -0,0 +1,14293 @@ + + + +RXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRRRRRRRRRRRRRRRRRRRRRRRRMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMMMMMMMMMMMMMMMMMMMMMMMMMM diff --git a/assets/midout_detectors.svg b/assets/midout_detectors.svg new file mode 100644 index 0000000..094ee0d --- /dev/null +++ b/assets/midout_detectors.svg @@ -0,0 +1,4420 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + + + + + + + + + + + + + + + + + + + diff --git a/assets/midout_detectors_2.svg b/assets/midout_detectors_2.svg new file mode 100644 index 0000000..925f86f --- /dev/null +++ b/assets/midout_detectors_2.svg @@ -0,0 +1,8028 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + + + + + + + + + + + + + + + + + + + diff --git a/assets/multiplexing.png b/assets/multiplexing.png new file mode 100644 index 0000000..e39648c Binary files /dev/null and b/assets/multiplexing.png differ diff --git a/assets/perf.png b/assets/perf.png new file mode 100644 index 0000000..d9ce140 Binary files /dev/null and b/assets/perf.png differ diff --git a/assets/pyramid_code.png b/assets/pyramid_code.png new file mode 100644 index 0000000..4257501 Binary files /dev/null and b/assets/pyramid_code.png differ diff --git a/assets/pyramid_code.svg b/assets/pyramid_code.svg new file mode 100644 index 0000000..a475551 --- /dev/null +++ b/assets/pyramid_code.svg @@ -0,0 +1,9478 @@ + + + +all stabilizersX stabilizersZ stabilizers3-colored X stabilizers3-colored Z stabilizerslogical qubit #1logical qubit #2 diff --git a/assets/solved_euclidean_problem.png b/assets/solved_euclidean_problem.png new file mode 100644 index 0000000..88471c3 Binary files /dev/null and b/assets/solved_euclidean_problem.png differ diff --git a/assets/stats.csv b/assets/stats.csv new file mode 100644 index 0000000..be99d6a --- /dev/null +++ b/assets/stats.csv @@ -0,0 +1,635 @@ + shots, errors, discards, seconds,decoder,strong_id,json_metadata,custom_counts + 8053, 1006, 0, 0.131,chromobius,dc8a8b0b38a83885b96b6529a9f5f5dea87ed11e5e5890cb772ab86084758d92,"{""c"":""midout_color_code_488_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":9,""r"":12}", + 6936, 1017, 0, 0.734,chromobius,d857db1f0debac8705a37faf9ca51802434e633b05931b885d7bb4b5d6806348,"{""c"":""midout_color_code_488_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":21,""r"":20}", + 14735, 1113, 0, 1.77,chromobius,731c367d069afbafeff01aa21ddd44bdb90bd0df09f60b50c04ff778da7e5356,"{""c"":""midout_color_code_488_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":37,""r"":28}", + 8875, 1000, 0, 3.02,chromobius,870453b363ca6ebda36742c661a40d79fb8ba27a61940ed187b4da9d394a7e9d,"{""c"":""midout_color_code_488_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":57,""r"":36}", + 33386, 1038, 0, 15.9,chromobius,4edb9408d768deb425edec64ccd5d27be493eafa42a4ab0bc391af1a22e8eccd,"{""c"":""midout_color_code_488_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":81,""r"":44}", + 78076, 1079, 0, 55.2,chromobius,f234ea89f3e23b569626df94bb720fcb0264dcfb302846b03db2b92292f84eab,"{""c"":""midout_color_code_488_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":109,""r"":52}", + 105451, 1046, 0, 110.3,chromobius,3ec32b1797d0b0c61572ccf7e2257d8c9f31d1510c00c523b48f6c5fe8bba6f9,"{""c"":""midout_color_code_488_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":141,""r"":60}", + 211250, 1000, 0, 328.8,chromobius,f46495cdac49d51cac14c0644f4bea348c2e9a8459491e6b6070662aa128d586,"{""c"":""midout_color_code_488_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":177,""r"":68}", + 340314, 1057, 0, 740.8,chromobius,0c4ca6f70f7026078c65f91eb68dd55a3e913684ce58c785025684c8ff57efbd,"{""c"":""midout_color_code_488_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":217,""r"":76}", + 5802, 1019, 0, 0.068,chromobius,06ac46fd8ef9b844361b0a124023d7120d0c67ca82275995ddbf94ca8e468c8d,"{""c"":""midout_color_code_488_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":9,""r"":12}", + 10813, 1064, 0, 0.392,chromobius,26658b46f4d6a5781df30e418ab964678b33635e4e6cdde7d7c631edd3028139,"{""c"":""midout_color_code_488_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":21,""r"":20}", + 13426, 1032, 0, 1.44,chromobius,bba7a1eaa8e80184a2256ab3034a6f35c82f2beb9105984dcd00186efa04cd6b,"{""c"":""midout_color_code_488_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":37,""r"":28}", + 9200, 1002, 0, 3.35,chromobius,5dce626311a7429b8d8e5909ff8d311f581e4ad1e06a9b12f0c6dd947d8e0b8b,"{""c"":""midout_color_code_488_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":57,""r"":36}", + 33346, 1029, 0, 15.3,chromobius,48b3baae33e8d622401e5ab598e3cd2f3a77abad37a118134173092fa4403f1d,"{""c"":""midout_color_code_488_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":81,""r"":44}", + 77400, 1049, 0, 46.0,chromobius,9e014120f7100adf533620defd113a27f0792f943333f61dee82f59ce0aad258,"{""c"":""midout_color_code_488_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":109,""r"":52}", + 108873, 1042, 0, 120.5,chromobius,74f930788405cc1b93b97a80305b89e60db81ef0a05a0921d7d689be5b625a72,"{""c"":""midout_color_code_488_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":141,""r"":60}", + 203876, 1005, 0, 306.5,chromobius,4e944f1a5ca3ecf8871ac8c068b88d790dd01071a6273f01026c340c0c6de4af,"{""c"":""midout_color_code_488_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":177,""r"":68}", + 339552, 1028, 0, 734.3,chromobius,070e282476c30eae8caac1ef67b2169f9b84736ac614497489f7850f916fb1b3,"{""c"":""midout_color_code_488_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":217,""r"":76}", + 92986, 1098, 0, 0.189,chromobius,a83d902b1fb34dd83f53b20039159a7cc1c4a9b90803f58919022277490c1987,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":9,""r"":12}", + 41758, 1004, 0, 0.142,chromobius,d114b1ff54242d2c91e65f826b3a937921bbb2c5e00119c180785e3d399b096c,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":9,""r"":12}", + 27255, 1006, 0, 0.091,chromobius,e3f6114952b84b36ec43dea6cb8504e39752cf44c93637a4983dd32c04529707,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":9,""r"":12}", + 17030, 1004, 0, 0.154,chromobius,470f06088a6b23c02a6f1aa05e6724f110fedc8ae2dc504ec423ee68d18455ef,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":9,""r"":12}", + 13881, 1031, 0, 0.122,chromobius,cc266790d8c6a20df9e67a8cb9910cba4acf25656dec49cb8b78d2d895f35555,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":9,""r"":12}", + 9591, 1024, 0, 0.105,chromobius,e39a2c03a77d7757d2e9b0f20177e3531231aebc6e90c1930497a93c9bb69899,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":9,""r"":12}", + 5271, 1002, 0, 0.119,chromobius,a419b9fb39f6dc05e659db55f78428011e9145e1d8585e76d45be56c4bb386e2,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":9,""r"":12}", + 3881, 1010, 0, 0.073,chromobius,887bbd376d8dc741e6aa7ba44fd84445c58a5d5b77486236ebfe75824017f9fb,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":9,""r"":12}", + 2878, 1004, 0, 0.101,chromobius,58c9b9499b4cb90a1cfbcff6b39fc7e4e74401a360620e4e81250dfb06144364,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":9,""r"":12}", + 2586, 1004, 0, 0.086,chromobius,22e7bc2b90a911ea92dca32178980420d5d969c39e63dd75d7a611e0793d7016,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":9,""r"":12}", + 2367, 1012, 0, 0.081,chromobius,9b5b8c0ec1a9a225875ecef89f201c649a31070d105ddfd5809484aedf9478ec,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":9,""r"":12}", + 2450, 1080, 0, 0.085,chromobius,0f1ad12768f5423e4d61fc5ea03295959dee2efba5df4ad8037b6538d8b16825,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":9,""r"":12}", + 2184, 1026, 0, 0.075,chromobius,4d15f53ff5eaa8c73227a8d9d400a90c6b20dddcc95fe58bddfc2207c95eea9b,"{""c"":""midout_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":9,""r"":12}", + 4030141, 1027, 0, 14.3,chromobius,9d7b85be9c89548a8bc40425a81765b505aca08df6fc112bc2bdc641ee9ef5fb,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":23,""r"":20}", + 940376, 1005, 0, 5.63,chromobius,c512191047eabd479184058fc6663b9b1b86440f4abd36c5b499859239c30091,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":23,""r"":20}", + 429539, 1009, 0, 3.68,chromobius,5537f8fd764d00077ce5b8517403566b889b8cd0f3df2ee46432932612656bf1,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":23,""r"":20}", + 169589, 1071, 0, 2.19,chromobius,e957254e8e28f9336dac58ed6d5b08bee7b6f876502d577181325e3427706d53,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":23,""r"":20}", + 79740, 1000, 0, 1.60,chromobius,cd290599dc49b147ab7de68d0befb3d0778912a719c2e99f17a75662aef03db0,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":23,""r"":20}", + 40295, 1003, 0, 1.36,chromobius,e88b3d80fd9b7782f576bcbfde923642923c87cbd37d645a6ea81b3853cde112,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":23,""r"":20}", + 11880, 1061, 0, 0.859,chromobius,9959dfefdf9ac06118ed9d473d04e68d2535892ffe9cf806a8ce1ac96a1d3d79,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":23,""r"":20}", + 5730, 1002, 0, 0.876,chromobius,2c98713fc8824c3b9ea627047fd8110aa3b4bc01a3b9b8aedf1cb18b63a6d4b3,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":23,""r"":20}", + 3320, 1046, 0, 0.643,chromobius,c7b1dc694b0d3f4a770b7394da69619138f1badf5ab936a61f6ccc7649fa185c,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":23,""r"":20}", + 2719, 1026, 0, 0.638,chromobius,359ed3ae084a1a9c0a5709b98e4d4a1980418c666067a5ed49d57b020b2b5de2,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":23,""r"":20}", + 2480, 1028, 0, 0.488,chromobius,6fa52661d55b9e4904c29355acd4d7ec68c16f6d48f3b1f5687ed1e6acc44a8d,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":23,""r"":20}", + 2147, 1003, 0, 0.611,chromobius,5e6d75761dc17229f60b7bd5c31288cede1171268a0cbf08cd8b353765461eb6,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":23,""r"":20}", + 2222, 1067, 0, 0.638,chromobius,8647ed48a818af4c2d5e63bac9d0dc67069ad40fb8c5573d22ab203801109d48,"{""c"":""midout_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":23,""r"":20}", + 8241626, 1065, 0, 89.8,chromobius,fd24ac42f8bee7055b5fad9bc342875494f30e80a31cead70e7a64c0abe8a386,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":43,""r"":28}", + 1962098, 1106, 0, 32.9,chromobius,4c6419912d8b28adc7682dc160a598d77f9851f6b2598448739f7978277b0f61,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":43,""r"":28}", + 781943, 1000, 0, 19.5,chromobius,5b25f9723c1cade7bd157c9f3c8e1f5bb630aeecf408bca2449a6d810619775e,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":43,""r"":28}", + 256932, 1003, 0, 11.2,chromobius,b82d70742dcd813405d25a5fe00d833c72c7af03f5a5279564eb0cf92c8652f1,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":43,""r"":28}", + 128485, 1007, 0, 8.23,chromobius,bf3de27545df21f22ff51f031ac05358a583f9c03f9ff9a968b4b06251beab18,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":43,""r"":28}", + 60919, 1001, 0, 5.68,chromobius,648205c904ec814cf26bb8c196cb4a7227bc081fce4263ab2e297bff5731e0de,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":43,""r"":28}", + 13763, 1007, 0, 3.41,chromobius,9acfca7b3487f8af8b1f5c93c74fe224ce4ec2dc073a335cddc034b09810027e,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":43,""r"":28}", + 5924, 1023, 0, 2.68,chromobius,eb2567747028bef0e920db2b549ac9527dae7a28b474e25237b47d0688763047,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":43,""r"":28}", + 2742, 1011, 0, 2.29,chromobius,e9422e4ddafd68d42bd9c1691bd04ac345148e39cd3ac52fcfa5544c929281f7,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":43,""r"":28}", + 2411, 1009, 0, 2.08,chromobius,6745e0c1f44d4b7a4d0d19aacd07d2f861629086397bd84e38364a5aa4e26c45,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":43,""r"":28}", + 2163, 1003, 0, 2.29,chromobius,00ec1b9d9ef66426fce2cf0ae1623827c00cdc126c76ca20c77a3018bb0915a8,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":43,""r"":28}", + 2061, 1017, 0, 2.04,chromobius,ab1000960fd3c871c7f747bef4846e8404ab45b55427820b29e3424e7e33e280,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":43,""r"":28}", + 2128, 1060, 0, 2.51,chromobius,72c6d08ad07f310e87984d66317d97bc697a68f88b1d981d7c13febbe03e01e6,"{""c"":""midout_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":43,""r"":28}", + 100000000, 550, 0, 2403.8,chromobius,bbf98c90695da3335dfe603c15558da2865c7506a6d7dec669c6a079676300d8,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":69,""r"":36}", + 24940366, 1082, 0, 1008.5,chromobius,cff4285a8269f8561b8c28937789cf9401c06b00203d3090e05fab44da261538,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":69,""r"":36}", + 7381070, 1079, 0, 414.7,chromobius,832708356fb4153d02e7549bfe0b146ccdcb75eb8679373a55db38d31772fa56,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":69,""r"":36}", + 1642833, 1110, 0, 164.4,chromobius,d1a16f3772500b17092867a333019bd203af3309c8dcd69816f2a26e057a23a3,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":69,""r"":36}", + 553992, 1051, 0, 73.2,chromobius,ec2fb7c07a65e87c27018622cb3beb3261ad77bcd178411acc09d0f3b304d483,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":69,""r"":36}", + 172968, 1038, 0, 35.3,chromobius,ebf69f72191412c7503e6a9151f6c4c74264d8ae813afc4e37f674c3549063fc,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":69,""r"":36}", + 22951, 1042, 0, 13.4,chromobius,eab45abe94841c28571cbc7d38185c9030d125a68a9106880720b439d4478f40,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":69,""r"":36}", + 7538, 1036, 0, 7.55,chromobius,2294fe18333a4a23184930922d048d93d704257b07be917145032399ca7660b8,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":69,""r"":36}", + 2620, 1009, 0, 4.73,chromobius,8b9cf9938c9150d19d380ffaf8ba11ac342e1074a4b3655251652a7c7d120b34,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":69,""r"":36}", + 2230, 1002, 0, 5.57,chromobius,0ef29c8ba29ee44e888d931b389e4ff8172c4ec98590d10c36383c792db7d18d,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":69,""r"":36}", + 2104, 1010, 0, 5.95,chromobius,6d196bf7d99847b624e1b0764811327a695ac5bf83be72b5e6b16f3972b540f6,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":69,""r"":36}", + 2141, 1050, 0, 6.94,chromobius,87d057d7a1ec5f4df047c18cee480ec887895b7d6b762393b9e6e2bea3dc9c66,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":69,""r"":36}", + 2015, 1003, 0, 7.08,chromobius,d6f2a42c008a3177d61dbf61a9406220fa7c1b02bdb50f8da36d5525a0c4d7b3,"{""c"":""midout_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":69,""r"":36}", + 100000000, 88, 0, 4607.5,chromobius,12bc040914eb53018cadd462657c30700c527a7dc6e3794c821d2d5253755cf0,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":101,""r"":44}", + 100000000, 881, 0, 7743.7,chromobius,b6ec735825d9024f00a355bca449c93e508b6ee178f08fe0b12900fbd4f92293,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":101,""r"":44}", + 29929457, 1009, 0, 3336.6,chromobius,d0347ce5c9c430f969387bbb5560a97f8efea5b81bb3db6ffa22c321f3fee099,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":101,""r"":44}", + 5379538, 1010, 0, 1096.7,chromobius,fdd4a386ff5b731e4c48b9525ce95e37bb53fd8297ad82ec2f29f7c835d94a0c,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":101,""r"":44}", + 1669739, 1016, 0, 428.7,chromobius,1ec8ca10f186c49889e2ced35f42a129221df98c808a3b4cbd45dbe369b15547,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":101,""r"":44}", + 451602, 1002, 0, 198.1,chromobius,1ba5216e8f89b8f54853a30d741c1bbb4ddba70e6025fae47c5820ce1b4d8af6,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":101,""r"":44}", + 37175, 1012, 0, 39.7,chromobius,ef2dadee0ba4c48b27221b98a347f07f2a572ca1815485afa92e98858a46923d,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":101,""r"":44}", + 9184, 1005, 0, 21.0,chromobius,a3781ca09f34535e9235f79b4c31d03b09ce86cf1535614481374146810d0ccb,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":101,""r"":44}", + 2731, 1031, 0, 13.1,chromobius,4d3f1ec21ec40b790b036fe1b6bc02f088bdddced4798dd0922de60ce1b46111,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":101,""r"":44}", + 2168, 1016, 0, 10.6,chromobius,599dbd3df7f50b2f5ea9548fc9aea6c1b65292f6b84cbd0d765520464d2ed977,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":101,""r"":44}", + 2018, 1003, 0, 11.4,chromobius,3cd1cf70bf549ebcc63b7bd4071d780b7dd09bb1e9d43ed95ef173efaec65255,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":101,""r"":44}", + 2016, 1004, 0, 12.2,chromobius,01d7b59f7e77172fd38b89758f2f3a07d4447d5cf5854bba469c67996a622a79,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":101,""r"":44}", + 2064, 1027, 0, 18.5,chromobius,59e368c03ba6213e19fa7a396263dc8f0720729e6c9ea4775b0aedd88e7914c4,"{""c"":""midout_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":101,""r"":44}", + 100000000, 6, 0, 8303.5,chromobius,11fa4a8537525a6da132baf377d10c9fd1ecbfbae91b504e8607b1656f71826b,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":139,""r"":52}", + 100000000, 80, 0, 14694.5,chromobius,e951d5ab6226cb25c903beca8c50797d7c960ec135ab807c6a420003516b4627,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":139,""r"":52}", + 100000000, 458, 0, 21259.8,chromobius,b6364c6db7e6fe53373bd57c0c5e33dacd79208a409bcc4026ac179b5d6daafd,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":139,""r"":52}", + 24574786, 1024, 0, 8666.7,chromobius,b265bdbc5d8c55cf1c4278e8630d8d49525ad35967f71038fba9a2eaa7d4e2ff,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":139,""r"":52}", + 6013934, 1015, 0, 2951.9,chromobius,dca188490108986568e3c8c82348c043bef5fda9f2827c9f4e3cdda21b3efc7b,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":139,""r"":52}", + 1261889, 1003, 0, 979.6,chromobius,b0c43b360ff89f67458784e63908430a932f1ea716f4a9f82c1bad3f5e314525,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":139,""r"":52}", + 64006, 1012, 0, 113.7,chromobius,fcf3313594355c9bb31cf6830830bb4fe31c889f43e608a9e0a76835ab6d70d7,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":139,""r"":52}", + 11429, 1022, 0, 34.3,chromobius,e25addba3fb3092f5b48c0443d2f801bd015672a2a560af9ad4a46556a15c5ce,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":139,""r"":52}", + 2816, 1003, 0, 18.6,chromobius,92f7f4116b69e62a9db0c8a076cbd62406ac457668cc3a11b7378f5cda5eedb7,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":139,""r"":52}", + 2194, 1058, 0, 19.7,chromobius,c2a9a4e19345cf800842bf0049f78e731b2842e204c89d92d5004f11fb9ab536,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":139,""r"":52}", + 2054, 1032, 0, 21.6,chromobius,0a6752b0b4a169b2e997f8f14d30a413ae5d0fee818d3365107ad8c80d668bf6,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":139,""r"":52}", + 1923, 1014, 0, 23.1,chromobius,ba35b4175057a67b3fe82a0d80909bd15700aa44542f14f56402ce85df969b6a,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":139,""r"":52}", + 1939, 1006, 0, 33.1,chromobius,8876a62c36d5ec00f472c9adb6942754666ea9a3e64e57446ab4b1e6be681b83,"{""c"":""midout_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":139,""r"":52}", + 100000000, 1, 0, 14056.4,chromobius,39556819fc00137e901699d3985b77d46286134e3f35af8e563858b3386db766,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":183,""r"":60}", + 100000000, 14, 0, 24712.8,chromobius,31a512cef9e54722251a8eb03012a338ed41414c15552ae5e2be675fb35400a5,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":183,""r"":60}", + 100000000, 67, 0, 35127.1,chromobius,4098252749ac3fd4923d549cb3314252aec1112cb5354580dc3f436f381fd381,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":183,""r"":60}", + 100000000, 844, 0, 57426.8,chromobius,8d96d650475b66d3a12d8ddfd04d31a52db644d85662fd31378834b8c2693132,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":183,""r"":60}", + 23117529, 1003, 0, 18778.3,chromobius,f50511af55697152f8cb826aa88e6d9d0e73d6b15164d5df6785e92adb478172,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":183,""r"":60}", + 3632067, 1020, 0, 4422.7,chromobius,615553fb1cc726aaffa4806c65001b9a842390bf4a996f12ecc374267198da5a,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":183,""r"":60}", + 110523, 1023, 0, 291.1,chromobius,70e5d3802594a11364adea78d318e90135b539677db56f9213a56d4e54885f3e,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":183,""r"":60}", + 16182, 1053, 0, 75.6,chromobius,65ec72c03fcfaa971ce0a63dac5b9834f9762ad84a77a0db03e1135e7ead1cbc,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":183,""r"":60}", + 2598, 1038, 0, 29.4,chromobius,0b58068615ae919c0344fe2e80215c1d64def2b4c68bb872f073b5cd96294182,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":183,""r"":60}", + 2108, 1030, 0, 32.5,chromobius,c38e6664ad0398ba09748cb3e51d9040be0b5d916d38619d3aa939610943f003,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":183,""r"":60}", + 2114, 1036, 0, 41.1,chromobius,217458492d9501c4c5151188355214c31339b96c8919b165eae93f5b10f4ed97,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":183,""r"":60}", + 2057, 1023, 0, 44.1,chromobius,c56c94d8184b5944e85e62e8f37642aff7a88f89732d8c8e97f6ed8cf773c774,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":183,""r"":60}", + 2044, 1001, 0, 68.0,chromobius,2768359b047c748102e1734f35536abc163572ec01b3c1ab2980428d69e119d4,"{""c"":""midout_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":183,""r"":60}", + 100000000, 0, 0, 21348.6,chromobius,f1932f66daacfdf0f437d3eaa596f0d54d20c96bd3c5681540ae1db75f24886f,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":233,""r"":68}", + 100000000, 0, 0, 38095.6,chromobius,909a073d9c06855a675e2ffa33e72d04c633a095c30a36b3b312790af8ecd4a8,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":233,""r"":68}", + 100000000, 11, 0, 55371.9,chromobius,5698ab310881a3ae78bc702b93aedbce7c62ae22c5f9f61714a87286a051fca3,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":233,""r"":68}", + 100000000, 180, 0, 90265.3,chromobius,ced803f00600e88155a48a3a5539f16e66029dc36146cb21d4dc571bd2883df4,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":233,""r"":68}", + 95931055, 1006, 0,121319.4,chromobius,e2af04cb5c2636d6605cc26e36ef1ece7659188d3819e5f8c8528e98ab891cd2,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":233,""r"":68}", + 11217632, 1037, 0, 21032.3,chromobius,ca21e98a394fb28a987bbc3afe9e88fbf00980d5eb96e17014b1354b9c658747,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":233,""r"":68}", + 223055, 1073, 0, 923.1,chromobius,d49064829e951cdaa8d3342119739bfbe268ee585c4984f37371d9ef9bf2c2e4,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":233,""r"":68}", + 20202, 1016, 0, 178.2,chromobius,a003d3b9689527023865f526ab6f9e538a504b13fbc55cf5d5f5ede0f5689d2e,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":233,""r"":68}", + 2569, 1014, 0, 56.5,chromobius,da745027cfa33604f9b9cc66a9b59ca11b7435b7561f3747f994b4c3d11c26c8,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":233,""r"":68}", + 2071, 1003, 0, 66.2,chromobius,04e58068070f6e2fa7e0dc2de471b888fd3ff833e88956f56d02ce1f50ffc4e2,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":233,""r"":68}", + 2082, 1064, 0, 65.9,chromobius,47c0b93ff9c1133552c945b984465d6cae0db1f8edc149e1f9a7629a74e1f716,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":233,""r"":68}", + 2119, 1058, 0, 95.2,chromobius,3572192f6be7b89fd3e6b3fe95d121c784383278f797d936de05cf4a0999b586,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":233,""r"":68}", + 2028, 1003, 0, 128.4,chromobius,488ba7fd5d302034d99cf495aa170a647ad15061cc5e831df998c355cbd104b4,"{""c"":""midout_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":233,""r"":68}", + 100000000, 0, 0, 30983.7,chromobius,32d80cc4414c7209ac932c5862d5ac7e5631ca5923fbf859ed8ebf3e585684b0,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":289,""r"":76}", + 100000000, 0, 0, 55528.4,chromobius,36bfa56d1a4a18a17cc91bd813bf945d474465c33021f7c513620372bf53cb62,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":289,""r"":76}", + 100000000, 0, 0, 80836.6,chromobius,bde3ed8f8b6be584572bfa160ec0afe67013d3e5bd29cf360fce89438bc078c1,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":289,""r"":76}", + 100000000, 30, 0,132645.9,chromobius,fb13a064ae16fe72025ed7fdc403f7e386fc6f02f4bdc4cfb37aa2a6a594f6ec,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":289,""r"":76}", + 100000000, 292, 0,186061.4,chromobius,e2151757c6be0be74a0c33adfcb67172dd61e913c899bf8f4f9479306b9cbe1b,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":289,""r"":76}", + 35111265, 1010, 0, 96800.4,chromobius,1d3deb57b24a360ba5a9bb7c4a6814c1c810defcf24443f1b4eb40e04206d3e6,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":289,""r"":76}", + 369537, 1005, 0, 2415.3,chromobius,6f33555ca1ab8bba3643a57043b6a2a1eef8be48955be36d936255bc412488e3,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":289,""r"":76}", + 27038, 1011, 0, 317.4,chromobius,94dd0c2002241c6a4973439ddad20f2fee86e5b7f4c049db70622d4e589ef30b,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":289,""r"":76}", + 2714, 1065, 0, 73.7,chromobius,fb472158390e7f98c4853bb9a5ca88e35613b821241372afa3c9856ffc311336,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":289,""r"":76}", + 2112, 1032, 0, 89.0,chromobius,71f5657bb050049073567efc40e2fb2a37a23e0ecb775f838795034c8d436acd,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":289,""r"":76}", + 1972, 1009, 0, 111.5,chromobius,78b251c9f531274cdcbb59c2136f6d7c8f28a2e14bd3d649e06d7f182d1c75d9,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":289,""r"":76}", + 2004, 1017, 0, 161.6,chromobius,f643ac4da74c740126036e120c219164a9e9e041cb61990bdcb7e7417f154fe3,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":289,""r"":76}", + 1984, 1025, 0, 240.5,chromobius,3821cff04ba855b60a99ab611e8b86bb6600dbf1a49572fad705f8ca46ecfd16,"{""c"":""midout_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":289,""r"":76}", + 95444, 1129, 0, 0.156,chromobius,3a828d8b47b727807f8191dc6c7fd5bc91d3aeac44604a267f7c2309ccad7d04,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":9,""r"":12}", + 45638, 1000, 0, 0.106,chromobius,adb35de2faaaacfe7af5c31d74fbc08602044c7b6ba5fb8991e26e783625c1c5,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":9,""r"":12}", + 28534, 1041, 0, 0.087,chromobius,1d8e25a620b54ac781cda629d85303cb176e68d782dc1ce931d26a86603b1016,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":9,""r"":12}", + 18334, 1045, 0, 0.090,chromobius,8e3441d3af8a687a9bc4d9ac2f3312721e5bd3525064f12c302793de03659ac1,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":9,""r"":12}", + 12897, 1019, 0, 0.077,chromobius,2a30f1af908c5e87c6ef0237ade2876261a506f03fb26f7dade39c0667aa1bc1,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":9,""r"":12}", + 9371, 1005, 0, 0.107,chromobius,20bfda9a59c8fe51cdc7144a0b58ce299d1292b5641ff0e6652bc738bd23741d,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":9,""r"":12}", + 5423, 1023, 0, 0.073,chromobius,a262a58fe8efaff52a34706e534dcd43b437267ca6c45ca5a01b8f0486557e8e,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":9,""r"":12}", + 4114, 1037, 0, 0.059,chromobius,4086c7efe98e27d9021eba53933c266c2c6977c05efac3cd64d3e1f0a4661b52,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":9,""r"":12}", + 2765, 1002, 0, 0.083,chromobius,58e96c350b65d0d7d549592ae574121fbf2f847695e645b67ac2e27855b47e3a,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":9,""r"":12}", + 2790, 1093, 0, 0.071,chromobius,1b77ed7b89fd1e34b7ef91591ed7ab69215424a1960aa5d2d0e51fc314e995dc,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":9,""r"":12}", + 2422, 1023, 0, 0.107,chromobius,db90d8bfa43346872978ab1908ffa78dd97d795b83096702e514dd54031ef24c,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":9,""r"":12}", + 2428, 1017, 0, 0.087,chromobius,92c9ffaf578b92f51d8634d96087d3e8c9be00a22e38a5244f3d21316e9988a0,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":9,""r"":12}", + 2201, 1003, 0, 0.063,chromobius,90223c6c80b7df2e23c8f79fbbeacdb8d2c53e24b85a55ce03a191d1402ed7f9,"{""c"":""midout_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":9,""r"":12}", + 4009896, 1010, 0, 13.4,chromobius,c76b8229ef9547e49f7a3ac6b139911657d08078ce057a2a68642839f6ec5499,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":23,""r"":20}", + 964973, 1018, 0, 5.25,chromobius,1ee718955cb4c2fcd23d00a68ca4ad6f414b0bab77cd29a430437e71bfe4a9e5,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":23,""r"":20}", + 489605, 1068, 0, 3.83,chromobius,d24e75f3a803732c693e0bedf97f78d008a1ab7b8f9edc4f441d60254eec7b75,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":23,""r"":20}", + 163349, 1052, 0, 2.20,chromobius,8c65b4ae76b9154fd3e68c41f65215c017f4c87e18d28c9056e7b8be808cebfe,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":23,""r"":20}", + 86489, 1023, 0, 1.60,chromobius,908c7b8b1de0633d69cc0c74a1e71c27f9bcfbf33b20d79a8d121b16b3acb39e,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":23,""r"":20}", + 39539, 1021, 0, 1.19,chromobius,6850edc67fd4913b80008eab17244c03a5d925fdada129a2a861ff29e92a9c6e,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":23,""r"":20}", + 11705, 1052, 0, 0.737,chromobius,8d6cf338539da6e269d390cd45fa213a4ed7e1a9444d522313f76f42b9b7cdcb,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":23,""r"":20}", + 6370, 1045, 0, 0.700,chromobius,d44deffad33ee2a3fdf53a5b0ff6e51230feb5e29fa3b44519042d8c9beffa75,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":23,""r"":20}", + 3066, 1013, 0, 0.519,chromobius,4f6517cf99c0859288031a1fab3652de0f4eb81dfdfa36628cb6d3b7f4da606f,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":23,""r"":20}", + 2691, 1027, 0, 0.456,chromobius,d328073250400d6039e1c7f5515440471dfd7462c15277a8d8505dbbf30166bf,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":23,""r"":20}", + 2490, 1034, 0, 0.503,chromobius,85da861bec2aeedd15e1c0c80fb387453da97c5c39f842d9d1bc140a99a44889,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":23,""r"":20}", + 2093, 1003, 0, 0.533,chromobius,2335e0d7866e69bd39621acf939262e48fc31a06ed394f842769bd44385266db,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":23,""r"":20}", + 2095, 1003, 0, 0.628,chromobius,1878110a843d7b818608581b4fa452521835bd2895105bb09c0bd740e46b5fd4,"{""c"":""midout_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":23,""r"":20}", + 7453742, 1005, 0, 72.5,chromobius,6fcc1445ed71bc6f4617638017089992bea5519d0eb8c5223b06a0b4b9d6b2d4,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":43,""r"":28}", + 1900425, 1061, 0, 30.7,chromobius,a046dec633c85227a90558c95b189632057d9c32bfe97af5dd63e4da3a7dfebc,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":43,""r"":28}", + 885412, 1136, 0, 19.6,chromobius,de2363a10d1c4560731b4b8e0ea1ea7bdf1ad15e58a072fee85220acb7342d4a,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":43,""r"":28}", + 272378, 1046, 0, 10.5,chromobius,9d54e876a5b352e5889c82694d94c6c16bf4698ec921571ea174597e0da6208a,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":43,""r"":28}", + 128531, 1002, 0, 7.81,chromobius,7a01c78a73f313fb4e82b059c94c08707b86f3d25b3c9f5d6218e855704db617,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":43,""r"":28}", + 63910, 1046, 0, 5.75,chromobius,726fa2993b808b9cf22a216fe0e2c4110670d6962fd899db58bd3872bcd482df,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":43,""r"":28}", + 13297, 1003, 0, 3.19,chromobius,cf799aebbb44d078812d844f3c01cf14cf2645f1807aa5ab9145cdd516f51ef6,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":43,""r"":28}", + 5937, 1007, 0, 2.03,chromobius,093d2086d7d8e4f9bad675da4c0c7cf7fc420a9f25cf8d576d3e7d6a44a797c8,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":43,""r"":28}", + 2860, 1008, 0, 1.80,chromobius,b903cdffde92c0b9de53cbf72e420fdfa410cd2b19ea0708a421b4a7f12d6230,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":43,""r"":28}", + 2543, 1055, 0, 1.72,chromobius,4124a85625d303c95b625279bbe620aef0ef19b51f26693a602dbd3a632ef8c6,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":43,""r"":28}", + 2135, 1003, 0, 1.85,chromobius,89d0051da1112b9069c48d40eff00e5500c47c5b82b805cd2b368b2c25fe5f1b,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":43,""r"":28}", + 2150, 1023, 0, 2.32,chromobius,0e75071a2ef118d245a2ba9796571d044ac4b4e0e40a0c76cf52a1130d5498f0,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":43,""r"":28}", + 2036, 1019, 0, 2.46,chromobius,3dc224b2ea79a39a3f0db648544cd9c976b01ed0b144daf3a3a2ce9ab96d5ee8,"{""c"":""midout_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":43,""r"":28}", + 100000000, 521, 0, 2336.0,chromobius,1e16179d44e84f6644d62ed1e28aa345b0170773c68def4956b4317b4c1f3f2a,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":69,""r"":36}", + 23863356, 1023, 0, 930.4,chromobius,81598eb134b09bd0635e120bfb4cbcaf28713261f9b45d79c68dbe09e5a7b4ca,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":69,""r"":36}", + 7159030, 1006, 0, 371.6,chromobius,571a22a65a65c2c9c42787f4aa695071d8c744da166563f16112e53de64417b6,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":69,""r"":36}", + 1444696, 1000, 0, 120.9,chromobius,998d59d45a3aa1f1108fbbdb0f350e34e7357f66044f6db6361452c53493f394,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":69,""r"":36}", + 554037, 1007, 0, 70.3,chromobius,94f2b410a7377fbea18180e40ff90354d2a2321e48b3681848e8e0ed715d573e,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":69,""r"":36}", + 170496, 1021, 0, 32.2,chromobius,ad2a0d50f03a3eaa7b58d04a8dce438bd8b63b804b158b13434be2bbb1fc8e25,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":69,""r"":36}", + 23268, 1059, 0, 10.0,chromobius,536f02600480e97b48d1633236d3bd8b031baecb387b4f62f6b61d4e7892595a,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":69,""r"":36}", + 7384, 1004, 0, 7.77,chromobius,984049ff45a88deb6f7eae76ae148fbd7745127483de0b457f3e10380eb16725,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":69,""r"":36}", + 2705, 1004, 0, 4.34,chromobius,519f5ff738cbd6e95e1167423039c663226cd0646cd3039804324f7e790222e5,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":69,""r"":36}", + 2324, 1029, 0, 4.29,chromobius,f29c0d2a490973d36d88447b68e24369e8d32f4ff3aaf561ec80054517a31d15,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":69,""r"":36}", + 2100, 1036, 0, 3.91,chromobius,ba499811af13ffbff91925c9ceb87ba0a828141dc9e0c90d91a4bb27e38f9a6e,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":69,""r"":36}", + 2099, 1028, 0, 4.72,chromobius,dd052a01a9c542b7d99ba0fa55e05400279f5e72c317fb0cd42ab775d2356913,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":69,""r"":36}", + 2000, 1059, 0, 5.54,chromobius,eb2d184f273940c20d3d087392d73f092c4cd53ac44ea88a902d72487e116c6c,"{""c"":""midout_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":69,""r"":36}", + 100000000, 119, 0, 4693.5,chromobius,36b644790d6be3a8dd8e767eb96ee025fe8b181afbdc473c5f3544837c0336d6,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":101,""r"":44}", + 100000000, 908, 0, 7949.6,chromobius,d10eac5ef4d914ca8c233a985aa16df4afd8aeae6bbb50d1416ac9042c239731,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":101,""r"":44}", + 31106755, 1027, 0, 3484.1,chromobius,ab8b6c5731519fc146e8c715cf59028db954dca568f67ead1e411adb6175908b,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":101,""r"":44}", + 5179230, 1006, 0, 928.5,chromobius,4a3e55f1fe85ce18b75ef1be5934d5f0cac0494929aa8059eed5810a54b365af,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":101,""r"":44}", + 1659890, 1002, 0, 423.0,chromobius,42064af0eced562a5d9ed93675d4b604a0d7db6c8c1d79ad787717a3447ff0a8,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":101,""r"":44}", + 459136, 1006, 0, 172.2,chromobius,ebcb27e4ecd2ac20dee1a8a7705a6367855de8db2dcdb558283c16b4cc2cc585,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":101,""r"":44}", + 37919, 1061, 0, 36.1,chromobius,e52ddd722302518c00683a7db04ff39ce689459d33fbf88376460a9ab9b0f4ea,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":101,""r"":44}", + 9749, 1107, 0, 16.6,chromobius,58707a48ea5f0044b7fc1e5d0c5f6e95d205fd8d0818245825a152de6c58a94b,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":101,""r"":44}", + 2730, 1030, 0, 8.96,chromobius,04cbe46ba6b8e031d718ede7223df56c8eca44001d5e698fdd19907435322b1b,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":101,""r"":44}", + 2191, 1028, 0, 9.40,chromobius,8c44fdc0851edcc42f2879b1106e32bbc783eb5d5c4e82182f094d44f6739162,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":101,""r"":44}", + 2033, 1003, 0, 10.9,chromobius,d95a1131c0284f88092ef645aa5d4076ba96ed72fab36b77cb3152e18b62fe53,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":101,""r"":44}", + 2056, 1009, 0, 11.9,chromobius,3ebb9c0eb724371fb8a379925f7ab85ee91dbde8265f90673fa11a3a83a2c5a3,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":101,""r"":44}", + 2072, 1015, 0, 14.3,chromobius,0ab6b34b3a6846a7bc42c2f439636e5b9e1b09e429a0b9abd9c9d3aff135dd93,"{""c"":""midout_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":101,""r"":44}", + 100000000, 1, 0, 8502.6,chromobius,c71e5cee0af61de4c37c0ef0a6ca8ef9bf95f1149777300c7f10e5b4778587fb,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":139,""r"":52}", + 100000000, 90, 0, 14715.0,chromobius,8df23a1ea7715bf2eb92557fe887529a00f35e0cde526cc0a5fed9c8ca2ec446,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":139,""r"":52}", + 100000000, 447, 0, 21017.9,chromobius,5868471e5431445e739606bcac17e2094204e1c83421bcb4ee791251290eee0a,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":139,""r"":52}", + 26491594, 1068, 0, 9292.3,chromobius,4560e7c7629ae1fb8872c64ba12c27aba9c5aa03d57cbf00865b8afd0d198f1e,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":139,""r"":52}", + 5814578, 1003, 0, 2870.2,chromobius,e56f4b4e9588ed64dd9b587094ddb31942ad0b1d53c5f903a465dd5ef4a944e7,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":139,""r"":52}", + 1265099, 1006, 0, 915.0,chromobius,419d81247cd8c0fa2da8762d2e82b8acd51963dec4b231a78c5b55cec8060913,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":139,""r"":52}", + 64481, 1087, 0, 103.2,chromobius,3b7a395fef8f5e479b4f01cf116340e7a1472f784c9949db17d23f419055cb8d,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":139,""r"":52}", + 11888, 1006, 0, 36.4,chromobius,3de7b34325d0f8f5df393b684e08edf86e8031fdd3b13f0e70e8f4794834687e,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":139,""r"":52}", + 2618, 1044, 0, 17.3,chromobius,fe81bec1a770a2ebaac7f955f29d9cf6c4ab5c10c82891f6c7373647bd7c404b,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":139,""r"":52}", + 2296, 1079, 0, 19.8,chromobius,047b46d596270ba09adb22e96c4af5e922b8527d97d14e8cc280a4739661d19a,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":139,""r"":52}", + 2208, 1077, 0, 21.8,chromobius,e0d118dd3bdff5492c0fb09c33550056c575d2b984ba11be4732fc0da919828e,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":139,""r"":52}", + 2016, 1009, 0, 23.3,chromobius,1afa6226f411c0fc796b51f5db1e5011131a86aa50d4b02f82959849acf8b477,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":139,""r"":52}", + 2054, 1001, 0, 36.3,chromobius,fc3fe81e7c32721af0ed853be3b632741bf3a99de470d6e1da6af7ffb4f611cc,"{""c"":""midout_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":139,""r"":52}", + 100000000, 1, 0, 13903.4,chromobius,df2bcb2be2b781d8e4a110373648b17c815973f46c7bccd33d0f1a71d3bbca32,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":183,""r"":60}", + 100000000, 13, 0, 24255.1,chromobius,7c43faf77d331d47b0a672e07640a6855e076f3521a939c2ca1d383e706b9601,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":183,""r"":60}", + 100000000, 91, 0, 34941.2,chromobius,1ec5148c23c8a066fc6bd90c8ae56fbdf476f064cb2d23a84ce637d25395a41c,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":183,""r"":60}", + 100000000, 874, 0, 57273.7,chromobius,d37641f493952b9aaacf8d514e76f881f5973f6ff5802d468a1cbf2267463e74,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":183,""r"":60}", + 23574688, 1008, 0, 19218.4,chromobius,98cccaa1719a9b6d85fac16484fdcf7a4587fda2839e0ac50de4d2da0c5a3570,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":183,""r"":60}", + 3984997, 1063, 0, 4761.8,chromobius,58c11737a48e068b5f5bfe2bf303562dd966efe466f1ee195531bbc9dfed2c50,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":183,""r"":60}", + 117238, 1039, 0, 314.6,chromobius,4d2b9359950dcb933959257cd7ba970acc3910f760ac385ff330e62ec2885f52,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":183,""r"":60}", + 14920, 1005, 0, 75.5,chromobius,bb850c01a65229a3dc37ef41e7c055dbc3829e608ac466fb49d058f5c6985b89,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":183,""r"":60}", + 2615, 1004, 0, 30.9,chromobius,90748bb150920b4a5bfbd3d8c9e227cda1bd256a1876b509c678c95029799b07,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":183,""r"":60}", + 2077, 1004, 0, 53.2,chromobius,3a7b8f4c234bd427a4cdb30fda08421db09b0924ae2293e13a85c4ab51a34643,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":183,""r"":60}", + 2225, 1056, 0, 44.4,chromobius,bcc96e6bf15d7917420df77c5b13cd8c7d6e09cf618eee4e4a5f2877e3b66c8c,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":183,""r"":60}", + 2008, 1004, 0, 50.4,chromobius,8c77ddf8fc046b147682ab3e9702c6d33e181cbccb42e3ff89f6974a14f4ec5e,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":183,""r"":60}", + 1987, 1002, 0, 64.2,chromobius,2074e18793f5aafa004cf694e6ada8118f01f259ffb9ca70945d4329ff0ad938,"{""c"":""midout_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":183,""r"":60}", + 100000000, 0, 0, 21272.4,chromobius,49f66d7b12a5055bb90d125396da32f8db4320fafa6c94c0bfe9367e14d98506,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":233,""r"":68}", + 100000000, 0, 0, 37855.6,chromobius,c8935abf8066b3c5990626155aa4d58bd29b678fb1a460914cf96d6e000e6e2d,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":233,""r"":68}", + 100000000, 9, 0, 54949.7,chromobius,9d8fbd9e2542ae95f69df924cdece55442a4b5102768d6826a645daa1bbd5052,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":233,""r"":68}", + 100000000, 151, 0, 90198.9,chromobius,8657121ea124e822254de16d73f5ac79a6b2c95cd86741544815c5cafb44c03a,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":233,""r"":68}", + 85023316, 1003, 0,106732.3,chromobius,590e12cfbbb071d53b860967e02a50d8c6fa2ff478d8a4313366eab92365a8d6,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":233,""r"":68}", + 11931380, 1021, 0, 21888.7,chromobius,301fa3d415e89fbe6a70b1b57357b43dd0893e350953807c54f46ffb4c35c848,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":233,""r"":68}", + 234924, 1166, 0, 953.5,chromobius,31ddbf0445e7aa707fa45753afe4761f367ead319827839324b252c217efc94a,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":233,""r"":68}", + 22289, 1111, 0, 183.7,chromobius,36b17b581d019ee020a258284668a1fa0576a310d88df350641585756b000d69,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":233,""r"":68}", + 2587, 1050, 0, 49.3,chromobius,42cf88c8a26adaded845264c1514f0f8a4482eec9bb642a8286aa4abada5fbf8,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":233,""r"":68}", + 2075, 1000, 0, 59.5,chromobius,6095a8064503dd0a69fda86b9db7ba5d2cd5dc715e3f355fc14d76a51bcdd3e8,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":233,""r"":68}", + 1947, 1003, 0, 72.5,chromobius,45c52b49f246785963bf0bc51703595cbe26f74c0ec8ab55573012ce90608745,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":233,""r"":68}", + 2026, 1001, 0, 90.6,chromobius,522a38c7b17326ee9083ee135caf7fa31e0250e8c7433b3d4c94e1b4c7c6237b,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":233,""r"":68}", + 1926, 1000, 0, 124.1,chromobius,15d912bfa4a732d3c87d935f6c276293fae9a304f84f811899dbf6eebf280470,"{""c"":""midout_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":233,""r"":68}", + 100000000, 0, 0, 30885.5,chromobius,97414b9215d1039fa5955adbbbda3abf4ce8aaceefe12b14581ca281cfeed3b9,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":289,""r"":76}", + 100000000, 0, 0, 55454.1,chromobius,a2aff099e95945aa9650d28175e9c69620d4a1c0d64006cb4fb422efbcac5ec0,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":289,""r"":76}", + 100000000, 2, 0, 80358.2,chromobius,5a36c176b76624a079e7bbac6ffc36deb1a50e1a24cafa4119666afc91876965,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":289,""r"":76}", + 100000000, 33, 0,132351.5,chromobius,5461a505614679663f5052118742c1c6963842add67a26d893114184ec2df66c,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":289,""r"":76}", + 100000000, 272, 0,185662.2,chromobius,4982268e5441ae58b455230cee8751d3e9c3668d8a297557ebdefa8f1a759d06,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":289,""r"":76}", + 36660419, 1006, 0,102573.0,chromobius,6891aef6a2ccee349fdac760af57bf65cc327caa26975388f44a5506b4fe8198,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":289,""r"":76}", + 369977, 1006, 0, 2473.1,chromobius,328da22d9deabea21019862d6539230c135368f9572d278f937eb63dca6f657a,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":289,""r"":76}", + 27297, 1001, 0, 330.3,chromobius,b75cb954a450fc5814b8d24bc7931d66b90d18050dffbe6d12a04a8b9dbb3cca,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":289,""r"":76}", + 2499, 1001, 0, 84.9,chromobius,b7f4f2dd98d820c1ddb6481f7b2bb7fc20020cb425fed8084bbd3ecd40a0aa05,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":289,""r"":76}", + 2057, 1013, 0, 82.4,chromobius,bc99608cbdd629c14615232210d691c8c28ec1cf92837209cbbf7de45c872f21,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":289,""r"":76}", + 2063, 1005, 0, 126.6,chromobius,6556dd4a490023e9be0721a8400617d26a00a44aeda75cd14507880cfdc80b39,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":289,""r"":76}", + 2052, 1042, 0, 168.6,chromobius,1d6fe30332fa61d8004172d4a10bbbfc4023bf1f4f8bb164fdb031da9280039a,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":289,""r"":76}", + 2002, 1006, 0, 246.9,chromobius,711398443a4e6a9016bcfd08e0394f1a1c8ae46159dc4aaa878c390733fbba82,"{""c"":""midout_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":289,""r"":76}", + 7395, 1089, 0, 0.544,chromobius,e6f3dd22aea879bafba98cec8388fa26f78b0274228bb31a438e812dc724277d,"{""c"":""phenom_ablated_toric_color_code"",""d"":6,""gates"":""all"",""h"":8,""noise"":""uniform"",""p"":0.01,""q"":26,""r"":24,""w"":6}", + 6669, 1009, 0, 2.32,pymatching,a0af8a28acf30b6909239b98bab00f6e62dd86dff6a48ba56925177bc5660c65,"{""c"":""phenom_ablated_toric_color_code"",""d"":6,""gates"":""all"",""h"":8,""noise"":""uniform"",""p"":0.01,""q"":26,""r"":24,""w"":6}", + 11921, 1046, 0, 0.241,sparse_blossom_correlated,0d6cfc60ac79f1010a30191366fdb2316c1a7125f78a0a89e5fc7ff741f6ed75,"{""c"":""phenom_ablated_toric_color_code"",""d"":6,""gates"":""all"",""h"":8,""noise"":""uniform"",""p"":0.01,""q"":26,""r"":24,""w"":6}", + 196957, 1062, 0, 81.2,chromobius,e06c3f3938044d1a06c52666730a3c848a255df51940355c80283f47916942da,"{""c"":""phenom_ablated_toric_color_code"",""d"":12,""gates"":""all"",""h"":16,""noise"":""uniform"",""p"":0.01,""q"":98,""r"":48,""w"":12}", + 741679, 1028, 0, 188.9,sparse_blossom_correlated,9fc258ad5c64d1b1c4f4e41658dac6712cbd989e3f345d87fdf9a15c6c70ca2c,"{""c"":""phenom_ablated_toric_color_code"",""d"":12,""gates"":""all"",""h"":16,""noise"":""uniform"",""p"":0.01,""q"":98,""r"":48,""w"":12}", + 195381, 1053, 0, 15.6,pymatching,6b4ecbe56bc6ab854635c3d2932cae179399acca908d9f3150e634ff1604ed8f,"{""c"":""phenom_ablated_toric_color_code"",""d"":12,""gates"":""all"",""h"":16,""noise"":""uniform"",""p"":0.01,""q"":98,""r"":48,""w"":12}", + 5654490, 1003, 0, 21175.4,chromobius,141985ce6e186d020a31a428e88af3a288236b21436b351f21353f3aea0ecbd5,"{""c"":""phenom_ablated_toric_color_code"",""d"":18,""gates"":""all"",""h"":24,""noise"":""uniform"",""p"":0.01,""q"":218,""r"":72,""w"":18}", + 40555658, 1040, 0, 56305.7,sparse_blossom_correlated,7ee784bcb009e303f394594943fa171fcd7d6691f240716ff7118685f1e72497,"{""c"":""phenom_ablated_toric_color_code"",""d"":18,""gates"":""all"",""h"":24,""noise"":""uniform"",""p"":0.01,""q"":218,""r"":72,""w"":18}", + 6204179, 1041, 0, 2865.0,pymatching,a478bc1fbfc1b0e8cdc7881590fa35eebdc01956900c9a21dc50d3a660efa32c,"{""c"":""phenom_ablated_toric_color_code"",""d"":18,""gates"":""all"",""h"":24,""noise"":""uniform"",""p"":0.01,""q"":218,""r"":72,""w"":18}", + 100000000, 598, 0,1337580.6,chromobius,e88e022e4b1c0cb1829fa2ce462673861fe566fd765cdbe7236af4e2d31ab1a9,"{""c"":""phenom_ablated_toric_color_code"",""d"":24,""gates"":""all"",""h"":32,""noise"":""uniform"",""p"":0.01,""q"":386,""r"":96,""w"":24}", + 187826556, 1090, 0,285682.2,pymatching,2d8e96cb0d4906505408bfba30d3bddb08d14f3072afd13e6eba0e299402dc92,"{""c"":""phenom_ablated_toric_color_code"",""d"":24,""gates"":""all"",""h"":32,""noise"":""uniform"",""p"":0.01,""q"":386,""r"":96,""w"":24}", + 190000000, 94, 0,848107.1,sparse_blossom_correlated,9288726df7daad1b521ed5a50ffeb9f5cd3b07b38e0860c144b6fdd73c858b2b,"{""c"":""phenom_ablated_toric_color_code"",""d"":24,""gates"":""all"",""h"":32,""noise"":""uniform"",""p"":0.01,""q"":386,""r"":96,""w"":24}", + 20099, 1021, 0, 0.296,chromobius,5468219ffcc3e1e2f7800b147b90f2970fef91dd458987e3bd5688158737477c,"{""c"":""phenom_color2surface_code"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":14,""r"":12}", + 46955, 1003, 0, 4.68,chromobius,e0d78b7c3a2fa1a95ce0588a056b669903a060d2f32b21c16a5d48ec8694fe88,"{""c"":""phenom_color2surface_code"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":40,""r"":20}", + 210782, 1004, 0, 87.9,chromobius,5bc1a599ea2e3e536dfce09171c7eacccde1e5aae36a6df53c34d599fe2b9470,"{""c"":""phenom_color2surface_code"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":80,""r"":28}", + 1002828, 1017, 0, 1234.8,chromobius,345d252c3591300403f6e8792ed7227f4828a6e264b8cd30ab996fd85fd35087,"{""c"":""phenom_color2surface_code"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":134,""r"":36}", + 4846447, 1019, 0, 13438.3,chromobius,9638589908b2d352a4fcd003701625d75a06f4b9560afd847e3a1b08ec2cec81,"{""c"":""phenom_color2surface_code"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":202,""r"":44}", + 26415021, 1022, 0,152591.8,chromobius,c34a0e155635bf29fb141b31d0076fc8ff80697272a025adf97eae07f4789a86,"{""c"":""phenom_color2surface_code"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":284,""r"":52}", + 21275, 1003, 0, 0.164,chromobius,bd7af6a64ac435454412bc8c6f56fe57c2749d08f5390d80225c265860170652,"{""c"":""phenom_color_code"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":8,""r"":12}", + 65246, 1011, 0, 2.86,chromobius,c99d466b6bf2d8ed205aefc02de44033fda35d4af7eabadd0c77e00f136ae334,"{""c"":""phenom_color_code"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":20,""r"":20}", + 256394, 1043, 0, 40.1,chromobius,458e8aea04ece5bb19d190c4e0e6bdad422f6fde099003277243145611ec7211,"{""c"":""phenom_color_code"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":38,""r"":28}", + 1190358, 1031, 0, 578.5,chromobius,30d8bc6eb1affc68fad0c6ef68b8626b2ce9f66f0740a87bdb450361198268cc,"{""c"":""phenom_color_code"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":62,""r"":36}", + 6412349, 1041, 0, 7582.2,chromobius,1776006a4e7ad668d389d9c1e7512b5595357a95b796435afbdcf3b2671bd2a2,"{""c"":""phenom_color_code"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":92,""r"":44}", + 38234182, 1001, 0, 82436.8,chromobius,d702e9e630a2da41abcf403e35cef91364504d7b3ab23fcf75912f3eb574ecb1,"{""c"":""phenom_color_code"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":128,""r"":52}", + 23295, 1052, 0, 0.175,chromobius,352303b98ec7090ba90aa2d76e0a1590c34101588b3abe5e9994e88d41e1ebbe,"{""c"":""phenom_color_code_488"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":8,""r"":12}", + 29179, 1001, 0, 1.10,chromobius,68feb4d486a390cda06afb9d994dcc0502e865068eb9de8fca63cc5a24d5492e,"{""c"":""phenom_color_code_488"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":18,""r"":20}", + 140914, 1083, 0, 16.4,chromobius,0f23a8be9dfe7ace9bd72c8b1b52ea33aee17004342fc6568541927033c8ca85,"{""c"":""phenom_color_code_488"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":32,""r"":28}", + 440090, 1078, 0, 148.1,chromobius,e77c322b2cf7846d14ec0754e821c06b8b682e8518618c8d31cd1f4e1461da56,"{""c"":""phenom_color_code_488"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":50,""r"":36}", + 1497416, 1001, 0, 1182.7,chromobius,5e67ee0269793a346584aea15ece33c998762e7e999639d522ac7fa1b5d8b763,"{""c"":""phenom_color_code_488"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":72,""r"":44}", + 5699028, 1024, 0, 8636.1,chromobius,7a2147b25a57e12cd49f9ca09bcc17811b92180318c0ed110b2bb3a51a35351c,"{""c"":""phenom_color_code_488"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":98,""r"":52}", + 14135, 1045, 0, 0.535,chromobius,84181b485b8844c764e3946f3055b6a9a7bef5e719cfadc8e0da5a515bd93736,"{""c"":""phenom_pyramid_code"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":27,""r"":12}", + 86527, 1000, 0, 19.8,chromobius,0955db26b8369c4ec7e88a72d522a440c529a5a46bf3a20aac8310d7bc555c06,"{""c"":""phenom_pyramid_code"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":74,""r"":20}", + 744760, 1004, 0, 763.9,chromobius,658410e042c82ab969a393133192cf22fe0e73c6ce06b56cd1495c0856a5f97f,"{""c"":""phenom_pyramid_code"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":145,""r"":28}", + 7450640, 1012, 0, 20457.4,chromobius,1f0b0e4bbddbc773bf0b238358f037ba63ad214f2f54deb1eb71b99c64daf74b,"{""c"":""phenom_pyramid_code"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":240,""r"":36}", + 78087738, 1005, 0,516404.7,chromobius,704005592d0a81d82c63ad687e0a43fad7aec6d6ff68a202b47c69aa0663b2b5,"{""c"":""phenom_pyramid_code"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":359,""r"":44}", + 100000000, 125, 0,1287790.6,chromobius,f64da85d926cbf268b82f5b86011285d435b705f41a3b609acc0757e30469d0d,"{""c"":""phenom_pyramid_code"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":502,""r"":52}", + 256953, 1139, 0, 0.406,chromobius,60ec60fa63625819240e2bddb9872fdad644ae002ef6c503122d2ec9257ae5b9,"{""c"":""phenom_rep_code"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":3,""r"":12}", + 3074955, 1009, 0, 13.5,chromobius,8550e7160bbfddf995d015df544201791971f687a297e20e34d60e376fbccb3a,"{""c"":""phenom_rep_code"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":5,""r"":20}", + 59276185, 1046, 0, 502.0,chromobius,c56db3abf48531871ae7c00c907f819861273ac23f83650a768c157237be0c7a,"{""c"":""phenom_rep_code"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":7,""r"":28}", + 100000000, 101, 0, 1423.4,chromobius,1b91727ac018ccf3bdd3eb75edcd3f3635c52d9a580221f68c183b6f44b1f068,"{""c"":""phenom_rep_code"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":9,""r"":36}", + 100000000, 8, 0, 2283.4,chromobius,c087af4982632309dee968c89b6f538abb45f0733c6d52da791447de05935f22,"{""c"":""phenom_rep_code"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":11,""r"":44}", + 100000000, 0, 0, 3423.9,chromobius,366ec1e5ea56951bd1e70d0dbe2451dcdb81e65ef1e02a37857e70c6ab876645,"{""c"":""phenom_rep_code"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":13,""r"":52}", + 20577, 1058, 0, 0.129,chromobius,c5ed4c0d3170a74ad2842b24b95325dd2fe7a17c7ef675cf434eebbfa7a83cc4,"{""c"":""phenom_surface_code"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":10,""r"":12}", + 63336, 1035, 0, 2.68,chromobius,a5c9ee3b7b59ac026e81462847a9e38310d51ddbcfdf55203e68832a0fb4125a,"{""c"":""phenom_surface_code"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":26,""r"":20}", + 260760, 1002, 0, 42.7,chromobius,20ec79518766327f0c282a0605d0604bd3d2eb43ecb4212ee2c28f99b107508c,"{""c"":""phenom_surface_code"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":50,""r"":28}", + 1133661, 1020, 0, 613.0,chromobius,6dc0e981506d0981900e5982bae9310bb80ffe7de184543c199e2390f91518f0,"{""c"":""phenom_surface_code"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":82,""r"":36}", + 6034821, 1007, 0, 7819.5,chromobius,f9585af86752bdf84e9cf0afb084852a9212a5770f1ad976e8e6b4451628417e,"{""c"":""phenom_surface_code"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":122,""r"":44}", + 29077030, 1028, 0, 67614.2,chromobius,ba983ff731fce222fd2e9438820b02d294afd0064d75d9bcfc07aa0e296ac02a,"{""c"":""phenom_surface_code"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":170,""r"":52}", + 1478, 1025, 0, 0.566,chromobius,3ef26d111ee6dc4973333560f8dd7c90acfa103c13cb674a51f3ca7e4c6849f5,"{""c"":""phenom_toric_color_code"",""d"":6,""gates"":""all"",""h"":8,""noise"":""uniform"",""p"":0.01,""q"":26,""r"":24,""w"":6}", + 157849, 1003, 0, 115.4,chromobius,47f6c88ac7f532d7c5c18f9e750859d961460c3371e83b0a16bb6f7c0a0664a4,"{""c"":""phenom_toric_color_code"",""d"":12,""gates"":""all"",""h"":16,""noise"":""uniform"",""p"":0.01,""q"":98,""r"":48,""w"":12}", + 4620356, 1007, 0, 33758.0,chromobius,be93b7ab968c5c8797048ef8b119739c175fc3fde451a708a93ccf25d5aa394d,"{""c"":""phenom_toric_color_code"",""d"":18,""gates"":""all"",""h"":24,""noise"":""uniform"",""p"":0.01,""q"":218,""r"":72,""w"":18}", + 100000000, 817, 0,2255896.3,chromobius,eb9ca535552405cd2164db403e3843517b9bd0b37abfb8374363fa18d652c38f,"{""c"":""phenom_toric_color_code"",""d"":24,""gates"":""all"",""h"":32,""noise"":""uniform"",""p"":0.01,""q"":386,""r"":96,""w"":24}", + 445797, 1089, 0, 0.809,chromobius,3cb8293fbf05882b24eb9666bdcac3ea190f9e76e1368a1b0526f55d719d31f4,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":13,""r"":12}", + 201949, 1067, 0, 0.658,chromobius,d7e1ff504da4effe50c5e3a4aa6942b48322b23f3daffea1c053ad1e3ec9afb9,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":13,""r"":12}", + 121171, 1004, 0, 0.530,chromobius,730c75ea6e8fd8f683a21967161f7fb9d833d1561eb86442d22f04f70a0fb076,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":13,""r"":12}", + 58605, 1003, 0, 0.499,chromobius,0b1cedf14d5c56ffd26dca82912875871fd4e7cf07d4b596fcf04b3606d99044,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":13,""r"":12}", + 37569, 1021, 0, 0.347,chromobius,93591c8c2534ebb52cd0424c72b485b0abc8e26924145015ec25f58a9cf12b39,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":13,""r"":12}", + 23816, 1008, 0, 0.511,chromobius,34e5b69ad805fa8b424b41f6de8cd829e9e5673f72b9db6a69d4db6613eaa0d1,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":13,""r"":12}", + 8331, 1002, 0, 0.226,chromobius,ad3ce10010630d2a249f5b790a66d382e82c15b97b0b144a3e200087916e06b2,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":13,""r"":12}", + 5169, 1009, 0, 0.196,chromobius,ba42dbb8d880b69efcf977be780786b60e9c5dad4aa92c791b0c5667e8cd0e3f,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":13,""r"":12}", + 3124, 1038, 0, 0.173,chromobius,1b43b35b6de1748a2e3a2fd1187e1e3b339e4745fbb838fb55dc63c5d692fde3,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":13,""r"":12}", + 2740, 1023, 0, 0.162,chromobius,4a6a12530a363d0179c3b35c8aa4757be1195d1b02a3a279d2ae92a84e7c67ea,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":13,""r"":12}", + 2450, 1020, 0, 0.197,chromobius,565e2656b08dfacdeb7f8588146f297e1983a7219e10232915a88d6de1c971cb,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":13,""r"":12}", + 2379, 1067, 0, 0.180,chromobius,c9c5dc02fa8e97c94ec49b93c8118eab1c780cae88eb34a5049ccbfdb734bf0c,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":13,""r"":12}", + 2132, 1001, 0, 0.201,chromobius,3e23d3db21a9340c137829777ee4e40bf23e5ff88ccceea537d3fd9d80aded8f,"{""c"":""superdense_color_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":13,""r"":12}", + 948263, 1008, 0, 9.79,chromobius,18957294fc92650542fe0cf2408ebbdd03235f5a5c92e49fc2f0833deb0db806,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":37,""r"":20}", + 370027, 1030, 0, 7.37,chromobius,a9e57855c634570c13ca6fca8719873d524ac871a61a55e6f3b56a9f82558d26,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":37,""r"":20}", + 219893, 1067, 0, 6.14,chromobius,7230a7f8f260d951151e137708172c275163ac186f238812fb1ef03b4fa4a617,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":37,""r"":20}", + 94974, 1009, 0, 4.41,chromobius,b3725c34a958912514a80a3a470008b8ded4976f05222d7e1de1e328f0c16536,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":37,""r"":20}", + 54623, 1016, 0, 4.00,chromobius,ce4fb708dbcd85a59aba8c1da5f13a039e1099892080c65d8ddcb27ea6bdb0ee,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":37,""r"":20}", + 28865, 1031, 0, 2.81,chromobius,24ba7a6e14a5ce45744fbec429c6aa30a9832e5c4e41c37a37c6ec9c00ddc02b,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":37,""r"":20}", + 7613, 1010, 0, 2.39,chromobius,c0b9a46adec914027aecd1629935f3e66afe71c6dfb70f7a97917a8417227fa8,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":37,""r"":20}", + 3987, 1005, 0, 1.73,chromobius,08e89afb3339ac3a06ae198180af2c48bcc947f5d33f6493fcd42a27abcf6bcd,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":37,""r"":20}", + 2522, 1103, 0, 1.24,chromobius,ce8ed65f5c1096a8f26fed647bd6c2f06ab7dacf36ea09993a724ace77d126cc,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":37,""r"":20}", + 2146, 1004, 0, 1.53,chromobius,afc517f5ab67b8c94f3999eedee786c187d26aab668075423cccdc404da2b860,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":37,""r"":20}", + 2266, 1093, 0, 1.85,chromobius,43a6367d7bc5598520e0a71a9c4ba7be31fca9eefcc4ef07d6604ed0f668fccf,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":37,""r"":20}", + 2104, 1058, 0, 2.31,chromobius,1d788f548df37c0981735fb974dbb77680ed8221d4c52c8118e8f1a88cde2b4b,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":37,""r"":20}", + 2105, 1063, 0, 2.05,chromobius,2164a57a3d6647fa154debc7be07e2f5e0cfb7b92a98b4eba05d55b4f64bcb01,"{""c"":""superdense_color_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":37,""r"":20}", + 64699027, 1029, 0, 1626.5,chromobius,89277409cd7cec0a9bf25f73d8d39da8511264c1be22f0d9bdf1aa75b4080063,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":73,""r"":28}", + 10357677, 1020, 0, 463.3,chromobius,2082d5afc1a2b9719f068ab17c45c05b87cc185abad5b1dac110ec17c2f5669f,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":73,""r"":28}", + 3341054, 1008, 0, 205.3,chromobius,13bc8373d6c5e2f504c24b3096b33a6280f0dcbff7d73af3300873da099dda9b,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":73,""r"":28}", + 752902, 1098, 0, 77.3,chromobius,36508f6a4d46f56802b7d7cef6ce4238662701ea1348a7086708e9fbed273f19,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":73,""r"":28}", + 256557, 1002, 0, 44.1,chromobius,c1c37b9d2a2bcb59284d1075c4dbfac4757ae0d0155d59be8fd361f3ab4f957a,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":73,""r"":28}", + 91127, 1004, 0, 24.1,chromobius,c001b906f818624c84b44392c40b14558cdfc7a9303a2349c565d1ea9ded0593,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":73,""r"":28}", + 11841, 1020, 0, 9.57,chromobius,23b8ad6738bde90a72ec17c4759a0de08feff9104cb52106ae2a04597089a6fe,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":73,""r"":28}", + 4366, 1026, 0, 6.32,chromobius,f9c42519b3342ae7c8aa5f87fad4ac88c906fff52366f8ce72e37c8b0321e995,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":73,""r"":28}", + 2219, 1026, 0, 6.05,chromobius,ad2a72b8db91f51ce3c3c209db21ef6bd9e8fb89c9e0f9862e86cfd35d2546c8,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":73,""r"":28}", + 2137, 1012, 0, 6.09,chromobius,d98cbf98f68f25427dd88de6efcda5bccbff9b82b90d380d6ba4af2169daaaca,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":73,""r"":28}", + 2057, 1007, 0, 6.55,chromobius,8d51eba1654da0d4c605f0a0e649cab222fdd18c95beb4ca993b2fc2b669af4b,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":73,""r"":28}", + 2209, 1086, 0, 7.48,chromobius,527e19b8ac2abaf356883b99cf6f45681d60f56fcb5862bb79fbc05834c3b4b6,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":73,""r"":28}", + 2105, 1055, 0, 8.43,chromobius,a19eb793340e6e42ceda8c8d210465ed8ed964b9d59e548e50a88a31e4432e5e,"{""c"":""superdense_color_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":73,""r"":28}", + 100000000, 127, 0, 6072.8,chromobius,c89ab8cb65f525e854839a5814842c64e601ec879a376836e0d5376562f3ba6e,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":121,""r"":36}", + 91279513, 1022, 0, 10000.3,chromobius,15696dab5a6ebb6461a2bcaec00059596c95ce29cd5f64cc3fbdf7f494006324,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":121,""r"":36}", + 20677132, 1010, 0, 3317.3,chromobius,9feec3558818b971b4fe8317c6bb1b141dd18baab19e15508ccad1755ed97b28,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":121,""r"":36}", + 3429146, 1008, 0, 880.3,chromobius,862aef8592d489176187404e6b51143fd8e0df71f6f960da0f91f389aa55a1a7,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":121,""r"":36}", + 928504, 1039, 0, 339.3,chromobius,a7e9abfe57c5448242f232af0faeebccdef7bb2ee20058e903daff385a44b20c,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":121,""r"":36}", + 233926, 1007, 0, 169.1,chromobius,f56b2a40f28f510719f821a52f1aea00ea860d4c2c1ec095828388c2c32ecb48,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":121,""r"":36}", + 15061, 1003, 0, 30.4,chromobius,06c720e7d28d0b69972c0e8e590b5687fb0b34085c25e5c8512c54bae0a123f0,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":121,""r"":36}", + 4137, 1002, 0, 15.8,chromobius,755f1161287d6f6dc55f1500fb3b628a60ed20908bb06e9247bdffcf12ff7a31,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":121,""r"":36}", + 2160, 1042, 0, 12.6,chromobius,b9be4999727871c4a9389edf6a3a85865791b51b848248eceb2ee4f62d3cdc62,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":121,""r"":36}", + 2059, 1042, 0, 17.2,chromobius,a2c7eb4be6dd1c6e8fb2c1cd265b4859cae7b1da83d2eb9a070ac2dd6f425ac5,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":121,""r"":36}", + 2043, 1012, 0, 18.4,chromobius,7a31020df01a08cc496af8c3301bc80b3b90beae1694f65de7b10bbc6d9428c7,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":121,""r"":36}", + 1956, 1004, 0, 23.1,chromobius,81237f807cb60ad8682cc5465e0f12c21b87520cfd8e3fa163935f9b719e5963,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":121,""r"":36}", + 1980, 1008, 0, 26.1,chromobius,6da1b0dedb1968a34abbb744d0b4683bb23d887ea9cd9964c33bc8f4c99692a1,"{""c"":""superdense_color_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":121,""r"":36}", + 100000000, 10, 0, 13180.1,chromobius,ff06046e6e57e2f716d9a619c0d1074b81cb91291d318bdc4aba33a632091971,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":181,""r"":44}", + 100000000, 137, 0, 24470.0,chromobius,b3ed0cba8fae18ceb952059053042fb87498595bde01facb44276382ba32c3bd,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":181,""r"":44}", + 100000000, 714, 0, 35496.4,chromobius,896a3396cc5a4c42dec0ff1b3de7720ceabfd79b6cc4aefe412bab31233b5475,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":181,""r"":44}", + 14894279, 1020, 0, 8776.5,chromobius,fbe7fcc2bb5da441862b8095564d8273ed5e8e307fdded24ad797b3052f34aeb,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":181,""r"":44}", + 3582114, 1006, 0, 3010.0,chromobius,2a99b84586fc4829d3299880e8d1cc6f64057db65da7916cd4188e0a11f42ae0,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":181,""r"":44}", + 609438, 1008, 0, 877.2,chromobius,795697a98d07be74a3fe080e2afbc77455d8aec74ca5ced27710e60f880d7419,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":181,""r"":44}", + 23420, 1077, 0, 82.7,chromobius,eda2b9e3a65dfc9d9435b0318f6253eb5d41f8c5421430a100038f6e552e3cbb,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":181,""r"":44}", + 4350, 1005, 0, 36.5,chromobius,b95c900d0f7376f55353c8e2cc16f785ff3541c9c12223e459322e0acc2cf941,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":181,""r"":44}", + 2035, 1006, 0, 32.0,chromobius,f4f052634915bf9fa74a7da756c86d2ce5ea74433043766b434e95bc949127d7,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":181,""r"":44}", + 1913, 1005, 0, 40.1,chromobius,8c183827e9da4aca2814c26eff3dfafbc08cb4f6fca73a86ae95ebdc80b0c5d2,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":181,""r"":44}", + 2116, 1033, 0, 50.0,chromobius,9fdaca6204b04259cc3114fa5fb9496f3bec2e1afbf362c6274379f61fd740cf,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":181,""r"":44}", + 2110, 1037, 0, 57.3,chromobius,1909e4dae8d04cd68c4b6825d70333e7c20c2bc08dd5491f4834443567f7b902,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":181,""r"":44}", + 2073, 1017, 0, 66.6,chromobius,5979684819b2793353200e3c46e440ec5cd2393f2b713a4a0f741602313f472f,"{""c"":""superdense_color_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":181,""r"":44}", + 100000000, 0, 0, 24234.6,chromobius,a7395cf7d73fc18d3870c25f6d86d1db547e86fe007aeb6608519e74ece42a89,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":253,""r"":52}", + 100000000, 5, 0, 45113.5,chromobius,ae6b166b191da8b266454299c210e5bc9b7d0164ce6df6d8278eee0dbbd56a13,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":253,""r"":52}", + 100000000, 87, 0, 67423.9,chromobius,bd52be51fce85190559efed72efc5c96624de9e60704654946aba772c1bb6a2c,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":253,""r"":52}", + 81606681, 1009, 0, 92659.5,chromobius,a24f1490a62b0a07bc9b00f2d6707bd121ecb53aa89a52b895434b0030025025,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":253,""r"":52}", + 14222469, 1098, 0, 22967.3,chromobius,cf9a1d401926db9ab35862fd9ebd76ce0aa4af11635c02d0d4ea76976cf65db9,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":253,""r"":52}", + 1718448, 1016, 0, 4181.7,chromobius,41bd64e523ed2e27776695032df2da8cc0ce5fb0163a2358fcb266e9ea83cd76,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":253,""r"":52}", + 32753, 1010, 0, 212.3,chromobius,921cbdfc27fb7a943a19f4edf74783e88e35fa798d1f438ccb315853dfaab108,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":253,""r"":52}", + 4498, 1030, 0, 64.5,chromobius,fb21d1820c423b4c4b11c16a8f0be0756e4d3ad9e5898bc82a8b9d2518a1f325,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":253,""r"":52}", + 2160, 1034, 0, 63.2,chromobius,d9d97be50b8063aaadebc4ee10b22e928f3a9c4053df97746d58692ac4c86252,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":253,""r"":52}", + 1932, 1002, 0, 85.7,chromobius,8d8801cf0b263e4285a1191d201ed058be56f3368476c4711e89714e2944e928,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":253,""r"":52}", + 1999, 1003, 0, 109.7,chromobius,a604b3d971bec7274bbf8452b055ee339015bd41c8c1f70dd269f170c6e92e54,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":253,""r"":52}", + 2077, 1004, 0, 131.8,chromobius,402724225f89645c4445094713de6a7435ac9010cf7b1acbf3a0cb3d79a22d62,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":253,""r"":52}", + 2094, 1014, 0, 173.2,chromobius,ae02429d4f0126dcd50b4a10a5a3b282dbca4453b9930333c9f25ea5c96a378c,"{""c"":""superdense_color_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":253,""r"":52}", + 100000000, 0, 0, 40574.5,chromobius,2d2f521ca7494989c67fdf1a86164ca6ece8baaeabdbcfb0d3108a61ee970aae,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":337,""r"":60}", + 100000000, 3, 0, 75810.9,chromobius,436022c91c976baaf82ca6a50df305e4675845c67906f25af08eb3ea0669c50b,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":337,""r"":60}", + 100000000, 11, 0,112160.7,chromobius,4871f48916d71a11804458f45a04b418f784c24d4fbbd20e144b3a0e4ce34c06,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":337,""r"":60}", + 100000000, 232, 0,189243.5,chromobius,c8c14249d8fee0cce3a6b1049dd2a79c1f3bfbffd5191b0667a0b0bef6b21220,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":337,""r"":60}", + 51160355, 1020, 0,139779.7,chromobius,d7f3a442f53773f10a9cd4909af2d771c22ca3ed0b6790735470d26fd1d7d0d0,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":337,""r"":60}", + 5059342, 1002, 0, 21850.1,chromobius,835bccb6454c5b0d19f244551b3afa80e1ccb466a49c97f711cd4ef3955263c0,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":60}", + 50995, 1014, 0, 562.1,chromobius,d68a9c28a16b07b4b6ebbc0420feb53707c7cfbfd7f1f3135a37118bbcd3d88b,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":337,""r"":60}", + 4531, 1008, 0, 112.0,chromobius,83918a24650b3e68305bc2473cb05baa8c95ddc15d6fa9a9b58feb41c3d86dbe,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":337,""r"":60}", + 2041, 1038, 0, 124.7,chromobius,fa7faf8a5cdbb3a83596152325d8425f2c9b2413da91f356319d7df452c6735f,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":337,""r"":60}", + 2005, 1020, 0, 195.8,chromobius,e5dff405d05889d8e7d5d234db2dd81ca1531561ae5cbf761ce03fcef1b78d74,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":337,""r"":60}", + 2150, 1096, 0, 272.2,chromobius,cc6cc09e5b77bd38bd1841135dbed7940a21841ca70312976743b5112c4dfafe,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":337,""r"":60}", + 2101, 1008, 0, 345.9,chromobius,bbf77b3b8f78205839d7584bae45ff29e00963972fcb13384b05f3913af14d3a,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":337,""r"":60}", + 2050, 1006, 0, 434.2,chromobius,e41d8413ca85be607f9cfc948e64426ffe248b7a28d556839fcaafab8dc242a2,"{""c"":""superdense_color_code_X"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":337,""r"":60}", + 100000000, 0, 0, 63965.9,chromobius,7a0ba4621a055bc19544f8973656d86fe8b9f9ac38c9a41c66ec13f2624636dd,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":433,""r"":68}", + 100000000, 0, 0,121328.0,chromobius,d0adc4b92c7edd74bbe8fe7c43b03c9f14e7b3c294e2291d63b35a67826c10c1,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":433,""r"":68}", + 100000000, 1, 0,181912.7,chromobius,0f5fb94bd0cc99af0046da808acc8a5c9d17015981d960b8b1b47df4109a847b,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":433,""r"":68}", + 100000000, 38, 0,315163.6,chromobius,c33c0f3479e0b364716eef8f7251beef6ce0e99692b33ded6864c896dfc4c523,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":433,""r"":68}", + 100000000, 424, 0,466971.8,chromobius,8dd9cb34920090fb5c5ef57080658efbd9bb5bf19877fdb2c2d104533e1803b3,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":433,""r"":68}", + 15455740, 1015, 0,113353.4,chromobius,03fee2a311f9f121de441a6e60993c6dfa8327f3033aa9e74445acb6322534d5,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":433,""r"":68}", + 75891, 1002, 0, 1375.3,chromobius,c5465ecf5df23395db13250c1add62ab1183fecafab907f8bb40c521633ec621,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":433,""r"":68}", + 4803, 1045, 0, 219.6,chromobius,4aafff1bd1fe6e06f0791b718a1b2a453f815bafa89c94bd6f340b57f8c80828,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":433,""r"":68}", + 1975, 1014, 0, 305.6,chromobius,e89034a0a9408b7812d679fd0b7220b0b5fc54cce8549c7a4868c8e478354f96,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":433,""r"":68}", + 2086, 1052, 0, 517.2,chromobius,8cbdcd38e93fc5ba97b8c0775c1604a527ae83f28ebb5f3804e6faa5ee51eacc,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":433,""r"":68}", + 1946, 1002, 0, 595.3,chromobius,61d9f83c9efcb02f431cdaee51756b81fb81ab64eafd3858706effaacfc44c4d,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":433,""r"":68}", + 2119, 1053, 0, 750.0,chromobius,627854b994632eec182bc4b6de0e072f01e43c6d08ce3b21d0d0d116148c87c1,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":433,""r"":68}", + 2017, 1004, 0, 1001.5,chromobius,3e9d56bc14ae5076ba4920d9c2ff9999971bbc988b78602bb611cf5e0676aeb7,"{""c"":""superdense_color_code_X"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":433,""r"":68}", + 100000000, 0, 0, 96257.3,chromobius,bc0512f55913508647d37b5e248940ddbee64109de43bcd87749867d88be3eb5,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":541,""r"":76}", + 100000000, 0, 0,184039.1,chromobius,35041ba76918bbc7d576e1764345963414287476c64ce1d2ed293404706c2971,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":541,""r"":76}", + 100000000, 0, 0,279668.1,chromobius,bc0a62e6b3d0f3c363783e84835154ee53bd3a5715f03d4fa048889a540c245b,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":541,""r"":76}", + 100000000, 11, 0,496936.4,chromobius,595277ca68e5d7b70660d60adceaf9ae7f0ce321ff9c310ba94910cb344bb7fe,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":541,""r"":76}", + 100000000, 128, 0,754569.5,chromobius,257d1684eb1e14f36a00c32e5ad76722a2d289366b3eeae64b3020a7f5d429b6,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":541,""r"":76}", + 50587181, 1002, 0,608899.5,chromobius,63c7a7c442f3a168c5fe47515adb6c1e3d514c921a6f51344e5bb92bd8f2617c,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":541,""r"":76}", + 111849, 1016, 0, 3118.0,chromobius,fe5181b636f0920a695614b9b1367d999636efa63545bcad954eef94acd5b5c1,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":541,""r"":76}", + 4956, 1010, 0, 324.3,chromobius,3992f7f96d0101e23d0f31d0ea252df75a2eb2a3ebe79c8b6299866f912a3d83,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":541,""r"":76}", + 2298, 1078, 0, 741.4,chromobius,1aa0a732ba837447dc05adc6c51ee92a118fc948c96630c57fe0d4d3acdbf737,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":541,""r"":76}", + 2031, 1012, 0, 1017.8,chromobius,f0620cf85e9079fb287cae9c5ae7954b47e660009f2ae41a89b2807a5ab0788f,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":541,""r"":76}", + 2003, 1004, 0, 1399.7,chromobius,27170755f4794baff4f866db6a5624f2b9d97b93f0ab470b88e72ac7c964d624,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":541,""r"":76}", + 2173, 1093, 0, 1806.4,chromobius,50e763cde18ed4d10b24987e6e449053cfdf48e81c3a32bd89445e350379372f,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":541,""r"":76}", + 2150, 1044, 0, 2724.6,chromobius,fbe7d3bad5abd643d7899cc0a84a102ed5d674911280c1e9b07428802c660468,"{""c"":""superdense_color_code_X"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":541,""r"":76}", + 3094975, 1035, 0, 4.24,chromobius,88832e31a429e45f383dac2f931722fef7e1a9f72dd771f4716fdc630c5c1375,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":13,""r"":12}", + 782280, 1003, 0, 1.66,chromobius,b766e84e3482cc03342901cb43ee52d90964d214f0494ad31c196b22c398a1be,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":13,""r"":12}", + 382263, 1076, 0, 1.15,chromobius,c99ea53c84fc848d344d6fffe2faad5a421e1102cfc150b59ce8182654644d20,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":13,""r"":12}", + 130606, 1004, 0, 0.688,chromobius,62af4df25f2c451513345430484daefef0c073c12bb28d33bef5f513ffc667d9,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":13,""r"":12}", + 74968, 1051, 0, 0.509,chromobius,d0fe62c6a1ff493f85824466e4b93a7bac451db49c8e5d66eb00b394ef852607,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":13,""r"":12}", + 37244, 1001, 0, 0.377,chromobius,8698aabc9d9aba0562bed0ea6dc79f37b8449ebb7f0153d66fab61afab8ae02a,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":13,""r"":12}", + 10847, 1022, 0, 0.216,chromobius,454955023e4643a33586e0d9c448f069571640f577e127ee57943c6c9c1fdada,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":13,""r"":12}", + 5882, 1050, 0, 0.207,chromobius,2de2e0cb71525f405ddf0ce532024490c8754d97c2ff3e54f5c694e5bc293bec,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":13,""r"":12}", + 3078, 1008, 0, 0.177,chromobius,0ae0b2a36962f40ca9db53aa38eedc7ce500b0ca185460728ceba30df7cafeba,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":13,""r"":12}", + 3044, 1125, 0, 0.175,chromobius,16f53429d5ba424bc870902e2d1a09879430abd810491ac68f11ebfa0b31aed5,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":13,""r"":12}", + 2422, 1013, 0, 0.192,chromobius,fee33cca71e88cc2b6e42878c8a76cb543a4ed83a688b833cbbd7e3beadda70c,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":13,""r"":12}", + 2259, 1030, 0, 0.188,chromobius,474c43dd88ee2113d303a89683c23ea9ab3f40078332f8d92c31fb63b8c64bfc,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":13,""r"":12}", + 2128, 1004, 0, 0.220,chromobius,2bbca0f72410ca58a6f44d96ddbd936d9b3a29038583fcac8797174ab57354b0,"{""c"":""superdense_color_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":13,""r"":12}", + 4148584, 1024, 0, 31.0,chromobius,c5895a225ce3dc417544d484dd35e83072dcc2a557e7b4b641a27003aff19a57,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":37,""r"":20}", + 910691, 1004, 0, 13.7,chromobius,96081e23f1bd9f0e75db6d02f1c14d694e82711d8e69fe5c74221d1c44f42898,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":37,""r"":20}", + 437748, 1045, 0, 9.40,chromobius,37a7205f0bee6d43857f6c9ab34779615608c2eb9d159e0d40875385c75ab6f7,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":37,""r"":20}", + 137404, 1014, 0, 5.71,chromobius,c17104be12bcb3fafc2c9e78882a460efa2a560bf5314ca1d25188979dcdfd29,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":37,""r"":20}", + 71683, 1019, 0, 4.69,chromobius,8b25767f24964ce527cfb5d4982a53b8989e86e258945deb7788560cecbb7fda,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":37,""r"":20}", + 34731, 1021, 0, 3.53,chromobius,8a26aee338843f084b465c3cbf42ead4332ce873e564e8e9dab4a83a445484b6,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":37,""r"":20}", + 8277, 1002, 0, 1.86,chromobius,7e985255732f231907a79781cad7ea9ce3cd3fee71142068a1256ea653e9b05e,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":37,""r"":20}", + 4089, 1006, 0, 1.71,chromobius,97f5c8c1ee5368003b7d957b4e9262e2b3d81158d3e8ee099c25cd24e604dff7,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":37,""r"":20}", + 2371, 1021, 0, 1.31,chromobius,cebe983d7948c63daa04f8f9593a829855617165c4d77d1add2490a0d09b4639,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":37,""r"":20}", + 2129, 1003, 0, 1.71,chromobius,9df54b1f4d2a967dc8e2d0fb675fd055067d3ffbaee7e536909906f89ad20494,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":37,""r"":20}", + 2128, 1018, 0, 1.57,chromobius,23a2066e28a44833f0079541c04356330dd621210989706b6e77f7419f02d17c,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":37,""r"":20}", + 2021, 1043, 0, 1.79,chromobius,6af088e129b82072cd538052d9f89815e220b2c994ba747ae78cfebeaed276fa,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":37,""r"":20}", + 1868, 1003, 0, 1.97,chromobius,346455e30704879a1ab17867ac7df2ea4f6c6babfc6be84a45b15aa5a3117c93,"{""c"":""superdense_color_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":37,""r"":20}", + 45161211, 1080, 0, 1152.6,chromobius,1f650be6c78ab04948dbba538dfd72cf2dd21090381ebe79dfbe725a28495d13,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":73,""r"":28}", + 7855039, 1028, 0, 354.1,chromobius,322971036dd99575b01a69b6eabad93c95e0014e62772e2d14a7459aa37f04a9,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":73,""r"":28}", + 2508345, 1020, 0, 158.6,chromobius,2d69ff1f8f6e006500450f344f67c7ed0f0c5b2eaa7a755c7cdd5dfbd01068d3,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":73,""r"":28}", + 669260, 1089, 0, 70.9,chromobius,c0d76f1b77ac9c0832c21b751d531725e1acdd7a9381e0749374636b7c5e3c08,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":73,""r"":28}", + 240911, 1080, 0, 38.0,chromobius,a9333a680371ae24ff8d55ecc7a10c6c57ec06045f34faafb3cb55364c07f8d9,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":73,""r"":28}", + 88071, 1038, 0, 22.7,chromobius,bf719f8bd31a9f1549fdaeda59c56df7e433eb5eccebaf94bbfd3c73b29aca0d,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":73,""r"":28}", + 10493, 1010, 0, 10.2,chromobius,3281a16faff043438caebd93acf6e5cf90ebb7128a87f515f1153cffcb3c7201,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":73,""r"":28}", + 4218, 1037, 0, 6.14,chromobius,56e1a19886a89105851298468f432ddb532e0d438ad55c00f663f37492b77dce,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":73,""r"":28}", + 2176, 1024, 0, 5.30,chromobius,1c700d922a2ff09f94800c4926d22ea5bd42e47b31730f246c562910a7aaa1ca,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":73,""r"":28}", + 2083, 1027, 0, 6.01,chromobius,9490637e5c0b3b7b77086b55e893bc06570c4bd7ff51435bcebca53ad40ac54c,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":73,""r"":28}", + 2197, 1056, 0, 6.59,chromobius,091f9d1f805f77f1c88c44e9f4c2024dd17866b2e7c52515f2b67e20e5cc9f8e,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":73,""r"":28}", + 2073, 1059, 0, 6.95,chromobius,d120ada7f5a9a0daeb0c3cdfb17c95c794de20df716fb09b968601b780c9e84a,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":73,""r"":28}", + 2011, 1018, 0, 8.18,chromobius,eb457293a45db4ec6d601d7d6b485468e9643fadeaf9570bdc889a582c763fd9,"{""c"":""superdense_color_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":73,""r"":28}", + 100000000, 138, 0, 6060.8,chromobius,08599e733ed4ebc5fbb607d389da549a48f3c9e1a43b9c78761533487670b83b,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":121,""r"":36}", + 70946651, 1043, 0, 7770.5,chromobius,f85efbca7118dddcf6f43b536b4fca2a1646fdaf1321080936f0875fcb16f662,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":121,""r"":36}", + 18976865, 1082, 0, 3025.8,chromobius,ac45a53c82c54bd2807181e3abcebed06b1793b6ee80c1468300487db6c7c03b,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":121,""r"":36}", + 2809938, 1004, 0, 720.8,chromobius,18ffab646e51e1004090f4f40448fada3e716366f5602b1fdfd3f928ea5b4e15,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":121,""r"":36}", + 855898, 1071, 0, 310.4,chromobius,97cecf7888461a962bb2c61ca31ad556729cd1f33961a78ab4f9f0a1da9eaf88,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":121,""r"":36}", + 217741, 1029, 0, 126.1,chromobius,e3fb53d2fc02a48db6ddf23900904c7509f0ee87cf5981bbdc6e91df39f7092f,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":121,""r"":36}", + 14805, 1014, 0, 26.8,chromobius,26a11a0b4e7be68ecb719b76a2e4417d74edc2d325c7157e096962be3c8a6f25,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":121,""r"":36}", + 4114, 1047, 0, 12.6,chromobius,ee4c4adbbb2f2d5db6fb6fe69985660ea08f53320939493d6060c11d545cabe7,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":121,""r"":36}", + 2091, 1034, 0, 12.2,chromobius,da640a3e0e33444bc4465aa4da6663d883809ab807343f592726d3152e509f6f,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":121,""r"":36}", + 2038, 1019, 0, 16.2,chromobius,b1e80a3099ed33a9f5895311e4f87caa064c7df4dd767079fb978e77cc090309,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":121,""r"":36}", + 2041, 1012, 0, 19.0,chromobius,c0dc91f72ba63cd52dc3bb7172ac431b43d33217b3b809b58e14bd892d554b24,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":121,""r"":36}", + 2059, 1005, 0, 20.9,chromobius,0c6ca24073511e4dbd5f6815221ffcd0dd278dbbac5b2c2a1631f0e0b3b45b7a,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":121,""r"":36}", + 2057, 1006, 0, 25.8,chromobius,eedcba2f6b067417cc1d554e13b033abba4688855c70b7b030311877cc0910a6,"{""c"":""superdense_color_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":121,""r"":36}", + 100000000, 12, 0, 13103.7,chromobius,271295a338ceed2a0c0305a620eef84c5724fbdcedaabbfb5f1a1ea789c5dde0,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":181,""r"":44}", + 100000000, 160, 0, 24173.4,chromobius,7f278b57cf9910a08b651e8cb2ba4912860c7308c25b00e2350ae587271c2939,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":181,""r"":44}", + 100000000, 810, 0, 35187.7,chromobius,dc0155d9a2e0c3e9b8f9fab50e58af4115c53678d3e68e95fe497f5e32533ac1,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":181,""r"":44}", + 14520107, 1120, 0, 8493.5,chromobius,87e73866065e3696de0dfc481550691e70cdc6939e7a73563fe7016116120fc5,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":181,""r"":44}", + 2932395, 1003, 0, 2396.7,chromobius,2bddac2a6b995842cf20a38c71a092109f0a4fa60756ae4935fdfa4f9db7d1a3,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":181,""r"":44}", + 593559, 1040, 0, 725.5,chromobius,820d55ffc284bba038b5569beb94eac3f2deee22636843831f068f2d7feb5c47,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":181,""r"":44}", + 21600, 1025, 0, 74.9,chromobius,d30b5b3a5c055da3059bebb4308ac2b586508594bf3fd4a008f333cceb6e5791,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":181,""r"":44}", + 4067, 1014, 0, 30.1,chromobius,c7b0ea550484a65d8548bfc607a6b9444a0013ebb8ef10b3ad8d1f732d296496,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":181,""r"":44}", + 2043, 1021, 0, 30.7,chromobius,a2fd96600e4d1c5d64de59b8c0799c99c483fb61b21f42d43df9ea2939dca927,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":181,""r"":44}", + 2128, 1066, 0, 37.1,chromobius,28caf91dd8ee1dfc66aab99d707db88f034b940474d6ef057d49be54a0be4a91,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":181,""r"":44}", + 1926, 1002, 0, 47.2,chromobius,3ef2169f582111f55d7eb5a75ac619e2e4b9b813774d9c258df04686d0e8bbad,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":181,""r"":44}", + 2110, 1026, 0, 57.9,chromobius,9eeb59f99c8ddfcb2d834a7904a09cfafec148d89b33e34a438297b0e6209ccc,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":181,""r"":44}", + 1958, 1002, 0, 66.8,chromobius,7a3715d81fb32a1fe065579f499515a2a0f1d05e0f688b2ec06c8f761a0fa21f,"{""c"":""superdense_color_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":181,""r"":44}", + 100000000, 1, 0, 24191.5,chromobius,e5d96a3e515bd3b8a35a66fe7bfb714d813fcce54e3a4b51897beab020d1b8e8,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":253,""r"":52}", + 100000000, 12, 0, 44958.4,chromobius,33bfcbde87af0c052135e2097b36cc5cad7b5628c041e7146b51cf451b0cf5ac,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":253,""r"":52}", + 100000000, 127, 0, 66639.2,chromobius,49debdb393eee866ce42aac229a829e1e502b31d6cc7f7589a236b402d96234b,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":253,""r"":52}", + 65198143, 1006, 0, 73559.0,chromobius,374dd862709b283ca3ce85a19084732fe825c8c1eba2e3406b35b39890d40e44,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":253,""r"":52}", + 11614335, 1008, 0, 18873.5,chromobius,e6d4c1d4f991bdf9e26463bc01ac402492e675060c5b681f96740d6b27636a07,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":253,""r"":52}", + 1586943, 1000, 0, 3775.6,chromobius,ac6593c1b0be522cea595258816c07d82de05693722b751e75e702fe6f4a1134,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":253,""r"":52}", + 30333, 1005, 0, 197.6,chromobius,5e86c2ad0076fd8794517f197d7b65c5fa47ca160aa8223a476a812f6e948bbd,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":253,""r"":52}", + 4422, 1037, 0, 57.8,chromobius,3059c12ca410c6861526550a9d717274a5cf2ddfbb489f8a2155ac8ccec64d43,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":253,""r"":52}", + 2098, 1010, 0, 66.1,chromobius,59d00eb457d77e11eb732beaf2a061702ed3bff9e74f12956334b787cb6a1711,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":253,""r"":52}", + 2058, 1038, 0, 89.0,chromobius,a3d4a72f42df3ced5d81954e4a4671ba9e33cc96661d1f9a0635accbde29c494,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":253,""r"":52}", + 2008, 1007, 0, 111.9,chromobius,7a8d7259fb59414cd58651662cd2a538e423e523b8d6dbbe436a213669f6675f,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":253,""r"":52}", + 2037, 1006, 0, 135.4,chromobius,e93edeccbfba2753a37c56469416d571192bc1d58dab878fd65b914d872fb52f,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":253,""r"":52}", + 1978, 1006, 0, 178.4,chromobius,ea642fe3810fddddf114a67a3b0b77a878333774797a0acbebb62de91274e889,"{""c"":""superdense_color_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":253,""r"":52}", + 100000000, 0, 0, 40170.8,chromobius,dab60785de03bc0705ea232412a6ead462390967d9b03c9579b0f7ee5b6681ad,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":337,""r"":60}", + 100000000, 2, 0, 75219.7,chromobius,c971660856541f6a70992f979cb5e8f066a6095978bb045bdcebba75e7e71640,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":337,""r"":60}", + 100000000, 15, 0,111557.6,chromobius,da5564a0397279bfd5028f6565e55e014a141baf7b012d61b6a24d682343fdcf,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":337,""r"":60}", + 100000000, 314, 0,187880.5,chromobius,d0624d6bafa55a5f3176f3e719f4597780fd8a23c0f7d4565c3ec08b605a339d,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":337,""r"":60}", + 45514960, 1007, 0,123330.3,chromobius,b36a6d71a729954ec7c074c0914c25f92027120fcc52bc7131ca3ba1bad5cd50,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":337,""r"":60}", + 4667459, 1023, 0, 19031.8,chromobius,89ec710e7d4b71a21e6cf2e66e53a005a63b3339fc5e768da8bd652bbf4978cc,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":60}", + 47956, 1141, 0, 539.4,chromobius,bd6f5ff7061222689309674ef4ac59f8dccf7dc721477fec322aaba19cbd906e,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":337,""r"":60}", + 4412, 1038, 0, 102.3,chromobius,e1b2ca77f1071861586550a15bcb38daa6a0b3b02ff2a97121f59bed7a7269cf,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":337,""r"":60}", + 1946, 1031, 0, 122.9,chromobius,d79dd0967f410404a41937f04df1ab999c1af795be0dd732ba25884514048514,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":337,""r"":60}", + 2379, 1127, 0, 217.8,chromobius,c3619da456ce38806f683b1fce10304aeb4db39b62364e21d293cb106f70b70b,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":337,""r"":60}", + 2139, 1069, 0, 255.0,chromobius,931560f5ffa673a27396dfd75ac16c33942a823fd50bee3d569a57888882fcb5,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":337,""r"":60}", + 1991, 1025, 0, 328.2,chromobius,e51fc1bb588cc698d711ffc6ac452aaa314b4ec9ce39af814dd0b28adb2d8199,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":337,""r"":60}", + 2002, 1029, 0, 455.5,chromobius,92463c3bd843325a55c0566732934205672ec9e18889b36c99360de0f71f4c83,"{""c"":""superdense_color_code_Z"",""d"":15,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":337,""r"":60}", + 100000000, 0, 0, 63726.5,chromobius,1186e769a66c49a4e6baa53f663073ecff6a420349fda34498298d72966fc059,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":433,""r"":68}", + 100000000, 2, 0,120714.6,chromobius,a62cd9e63fb0b9d8289b61b64ba66af6fedffc9e8a9e7466fed99ce8dbd2f7ed,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":433,""r"":68}", + 100000000, 3, 0,180642.6,chromobius,3f4dad285ef0876bf40c9358118d483336e4d92e5ffcb21b9962db07f594b0b0,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":433,""r"":68}", + 100000000, 56, 0,313227.6,chromobius,17aff9b2aab08e533d4dd707335ac04af1e93f3ca8d03cd6ba3c77deff6be3be,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":433,""r"":68}", + 100000000, 586, 0,466700.6,chromobius,1591185f18dceeee426dc4cb279f2d32d2e1110b48808493b074e3ee7b38bd0b,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":433,""r"":68}", + 13814885, 1003, 0,100808.5,chromobius,b1589c13747aa4f9951c1416986532a21ef5e7725ff766e58ab5aed5f498dc41,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":433,""r"":68}", + 76249, 1119, 0, 1325.9,chromobius,00d47168225a87322c13878b763dbc66273c8b5fe8a33203dc265720f7cac5e6,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":433,""r"":68}", + 4514, 1012, 0, 193.9,chromobius,2b2732610eb91c271e60564283e6fba443ee17fa70a0f05516ae812471bfc5b7,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":433,""r"":68}", + 2130, 1006, 0, 295.8,chromobius,62f6a550afeda1291eee41c7cd15df0be0f68e77fee1b4e8802f2fd5d7aa4346,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":433,""r"":68}", + 1997, 1001, 0, 463.4,chromobius,c3764ca359ffdde285286aa8bf90155f8b320724c74861a6b121fd77c6215a57,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":433,""r"":68}", + 1963, 1019, 0, 525.8,chromobius,a30fda2cd795cd296a5c88725589491dad49ecd9499b2f088a196ff76b357fa0,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":433,""r"":68}", + 2021, 1006, 0, 760.4,chromobius,d144196df21be4aaaeb80d9ba6ef0fab4a04bfd3a1b01faf60f116e4f8d6d27b,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":433,""r"":68}", + 2023, 1013, 0, 1196.5,chromobius,9251a7a4ce5db9ebf310823c777190384b5855a55e9f6ae3da5b17bcdaca632e,"{""c"":""superdense_color_code_Z"",""d"":17,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":433,""r"":68}", + 100000000, 0, 0, 95749.1,chromobius,1d911ab31834b89f06f4860f48d34569dfec53617857a658d91242d28da6e582,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0001,""q"":541,""r"":76}", + 100000000, 0, 0,183201.6,chromobius,f296ba1fa78002abbab29c8e8edcf0dde2a0958f7ae6d5e56633fc61966ac88b,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0002,""q"":541,""r"":76}", + 100000000, 0, 0,277259.5,chromobius,df3b28e56018ccd96e423ccf45c65375c1311b0530f6c181e9734a6b4fa0a449,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0003,""q"":541,""r"":76}", + 100000000, 10, 0,493444.7,chromobius,2653efb1cbb2c9c735c5364fe4ea2e336952ad4f007329a439748ca71b8e3737,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0005,""q"":541,""r"":76}", + 100000000, 131, 0,748853.5,chromobius,6f75b9ad97afd02299f25e0605e22e24567e16a2edea54a42475f3bf9e35eed1,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.0007,""q"":541,""r"":76}", + 44816945, 1011, 0,536932.5,chromobius,60026fec3c01ce9bb684cf3f73f5d350bccd41261548676d8d986a1f7ba3005e,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":541,""r"":76}", + 102206, 1031, 0, 2781.5,chromobius,a09afc3f0563cf60e8064a42e0b00ba7d8ec5fe3229d7b2801d76e3cdd01ba78,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.002,""q"":541,""r"":76}", + 4817, 1028, 0, 281.5,chromobius,79f8d1935c0713dcdd25f8e9d696fb45e4da22e3728ccfd3ddaca522c70a3801,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.003,""q"":541,""r"":76}", + 2023, 1014, 0, 696.2,chromobius,681e7cbe73c29a99820b332e39e4870eb538ffad920c427725fbe718a5186ce3,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.005,""q"":541,""r"":76}", + 2007, 1002, 0, 914.3,chromobius,9c50b6134a0764fffdbec8bece370c136bafb25ce9f54e1348f0d56581f29a26,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.006,""q"":541,""r"":76}", + 2052, 1031, 0, 1403.3,chromobius,7eedaaa5d6703a6070a8f17af3220d476de23fa13e0169944e1f790e67e88d34,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.007,""q"":541,""r"":76}", + 1969, 1011, 0, 1960.5,chromobius,6e94874e9e1e33a5952425024cd31c884e83f1916b3dce79e510cb405741d316,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.008,""q"":541,""r"":76}", + 2158, 1045, 0, 3395.6,chromobius,b3e87fdfb57f3522c535c98ec74f9f774518f1f150ea7310b8314dd9aa91f9f7,"{""c"":""superdense_color_code_Z"",""d"":19,""gates"":""all"",""noise"":""uniform"",""p"":0.01,""q"":541,""r"":76}", + 153608, 1104, 0, 0.528,sparse_blossom_correlated,6a503e9c621b43c98050b74037f941d90456e4596621aa437f3819f48cff73e8,"{""c"":""surface_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 146231, 1034, 0, 1.50,pymatching,697c75b0fe8c8f0bb8854c043c8ddf1677b8c0679e42ce7f8a39c55f94a5ba5a,"{""c"":""surface_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 137757, 1001, 0, 0.989,chromobius,bec74326d3f3c88f0d987ca22c00851f9576f3a5274947c65e92c5335a3ed170,"{""c"":""surface_code_X"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 1253641, 1068, 0, 18.3,sparse_blossom_correlated,e0bc53ee7428f3d16a7595d83dd720f6cd6dc2230748eb413f02d7bd4d74dcbc,"{""c"":""surface_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 784961, 1005, 0, 5.96,pymatching,9693ad406199b4d3598217aaf5dec1d328d07d00832238a77229ae42a77f44fc,"{""c"":""surface_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 660290, 1000, 0, 18.0,chromobius,e9e8bee0c9d8a26fe84c08dc449d7569cb532bab5f8efe24d1b5d572c6a990b9,"{""c"":""surface_code_X"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 8218476, 1880, 0, 155.0,pymatching,bc47816ee2851ac36ac17a54abd23bb54cb6496d4813674577fa2e159b11a597,"{""c"":""surface_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 25221948, 1912, 0, 1334.2,sparse_blossom_correlated,b124075756aabdca1bf960ff7809884079c65a742dac2e99605a5d7bd652bdde,"{""c"":""surface_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 3981680, 1040, 0, 467.8,chromobius,ebddac421f103f01175109db03401f2c75482a8b777a3b94e0494619f2f1aafc,"{""c"":""surface_code_X"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 59718318, 1911, 0, 2614.8,pymatching,04c820ba3305bf235323259d7d84dab9f2534792e1a5352d9827e02c53899b57,"{""c"":""surface_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 190000000, 1207, 0, 25104.3,sparse_blossom_correlated,06f8dd42d59cc3ebcb4dc484142820e31dd4f93386d09c9ae9e168e41a2c0522,"{""c"":""surface_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 28078633, 1046, 0, 9064.5,chromobius,a29886a7e1df23fbc1bbee2e6171a8833ffe72110d79e33a360414916a02e9a1,"{""c"":""surface_code_X"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 190000000, 822, 0, 16652.8,pymatching,f6907102f2beab78ccae65ac21025cd436f657b998d6fa507a911f0a428ffd81,"{""c"":""surface_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 190000000, 104, 0, 58193.1,sparse_blossom_correlated,418c5bdcf2fc4891e86debb75217b707bd699b0b76652f7fef25f235537f095c,"{""c"":""surface_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 100000000, 499, 0, 66752.6,chromobius,2c4973abf8d0a4d64b8404b7f729fde73ab9c0b5a94230534bf3922835bd4802,"{""c"":""surface_code_X"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 200000000, 89, 0, 32760.0,pymatching,dbd37b4251fc121571f81d1d01f2654b70e6697365fa1eb5679231f432f21a9b,"{""c"":""surface_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 200000000, 8, 0,123514.8,sparse_blossom_correlated,19a56d2e5f0fb1d1873514a024ea745833e86894cd42a1890aae83063a5bba78,"{""c"":""surface_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 100000000, 68, 0,125860.7,chromobius,4d787badac11c09ef4c051a852221c97b341183114bbcccfacf57da5cb46b313,"{""c"":""surface_code_X"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 352602, 2065, 0, 1.05,sparse_blossom_correlated,83307e1500a1cd2c4929cbee230ccdc5f4768c680549daee951043bae40d7045,"{""c"":""surface_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 280637, 2017, 0, 2.39,pymatching,9455785765903a7c55e100a7dde446c56531158262f02c42823b1909a4d5fd08,"{""c"":""surface_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 128658, 1025, 0, 0.689,chromobius,854f222596cb2f10b7bb1eb870a1a4e9ef30a6c6fc3842372683d78355473b81,"{""c"":""surface_code_Z"",""d"":3,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}", + 2512149, 2065, 0, 41.4,sparse_blossom_correlated,57846f538dc905e7864102720c00db0161114362d4c275790bbc53013fcfce3c,"{""c"":""surface_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 1377382, 2044, 0, 9.93,pymatching,2d467206ca6bcd2281618cb8731455e851c7b75277b62a22a365c8cf6923000d,"{""c"":""surface_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 654037, 1015, 0, 17.6,chromobius,77440067e6de31fd01c59d0c1ed2c4b6582c3cb2529e94492696fa26a2ea0031,"{""c"":""surface_code_Z"",""d"":5,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}", + 27367877, 2138, 0, 1461.4,sparse_blossom_correlated,9d1abed3b0e4e6af6c87bcbce8600d28dc233fde4435461e31c32d1ec0ed8f7d,"{""c"":""surface_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 9272439, 2140, 0, 174.1,pymatching,39892a5feda4ea15ed66b013f897982fdb52015d3820fe7b667316cccfc573e0,"{""c"":""surface_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 4043037, 1062, 0, 432.7,chromobius,f46c8e39b28b055bc89408d066b7de236600bcd332ca93c303c26fcf333c80f0,"{""c"":""surface_code_Z"",""d"":7,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}", + 200000000, 1377, 0, 26888.8,sparse_blossom_correlated,3cdd251def8b19af03a9128d9d9f62217f05ab0030bf11e53e54b2773c6f574c,"{""c"":""surface_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 63697703, 2090, 0, 2793.9,pymatching,03d0e75ec80a9b2c50dc77e3e46f314596cda25e65479c2343fbe0763c8c7749,"{""c"":""surface_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 28399245, 1014, 0, 8360.7,chromobius,7ae59f1556315300007ec6f8c172a45f5987e4c430bb4c5c2ca9bf0794d7d771,"{""c"":""surface_code_Z"",""d"":9,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}", + 200000000, 882, 0, 17694.8,pymatching,08c5dd4220cb10eb91e15bb91a2b09c8517b68775748a468d3267ab46dc0cf81,"{""c"":""surface_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 200000000, 114, 0, 61385.1,sparse_blossom_correlated,ab3ce740be420fd9d0a0adb558a4c70d5f5d3efac11f7ae0ee5f809674601ad5,"{""c"":""surface_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 100000000, 515, 0, 67266.1,chromobius,624669dc186ce48112eeda077d849157e06111c467e74e8e5febdc9cafa8caa9,"{""c"":""surface_code_Z"",""d"":11,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}", + 200000000, 107, 0, 33119.1,pymatching,4d8d103fb1ce5da21e08b89e35f2fbc9e8db43bbb844fbff4b96ec1e081b63b4,"{""c"":""surface_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 200000000, 5, 0,124137.0,sparse_blossom_correlated,b9dac8df5d51d2fd600e9c7d2ec1cdcc54aa2e52e8513c27306a043c724f68cf,"{""c"":""surface_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 100000000, 65, 0,125887.0,chromobius,614b9f479387aff09d2141b7a29f4bca39076df2c68fb54def75a8591fda8826,"{""c"":""surface_code_Z"",""d"":13,""gates"":""all"",""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}", + 100000000, 248, 0, 420.3,chromobius,d4a71418dfb8ba44e897ef05995ffaab6182c744e111e1042b3a605db1535331,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":92,""r"":1}", + 10110244, 1076, 0, 78.8,chromobius,9f82c54efc2259b1e27196f90765a3eade2ccdcb4774316cb5b95b2d23e77b4b,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":92,""r"":1}", + 1201031, 1083, 0, 13.9,chromobius,0f8c251c3ee3d69cc9210702a3f5ec27099b5ea2ad3a3542f7f38e9a1e680d2c,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":92,""r"":1}", + 322632, 1111, 0, 5.09,chromobius,daac099af17edf2be34a2efb9b3429188aff5cca3329345d40496743dbc3db2a,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":92,""r"":1}", + 100304, 1090, 0, 1.92,chromobius,b537dcee78a66952db6ba5dd41ce4c077129590972f8726cc5b3658250e899f4,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":92,""r"":1}", + 42051, 1073, 0, 0.960,chromobius,d006153fb065b4dd261a9bde47a0bb36781c21fe976c4d8cbdf63ba561fa4b74,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":92,""r"":1}", + 22397, 1092, 0, 0.635,chromobius,c28ece34904ec871104a15f74026c575bf550a1715e6a840383ee2ec90d1cb26,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":92,""r"":1}", + 13052, 1073, 0, 0.369,chromobius,000f4a11065ab155bc8c613f0361236c86ca8e5f901b8acd06b01635b0f5fb1a,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":92,""r"":1}", + 8580, 1001, 0, 0.297,chromobius,85c6ffc109edcdfd4da5d6b7e9867edef69e1147f9358c19e78228cb2abb9f76,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":92,""r"":1}", + 6546, 1108, 0, 0.278,chromobius,2b838c4372c81e03111e91f15b735a5219b3bd48560cf1efbe04c6539fca44a4,"{""c"":""transit_color_code"",""d"":11,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":92,""r"":1}", + 100000000, 3, 0, 809.1,chromobius,0e085bb768a58041b03ee041b200ed664119145ba363d5f6e08af420f6632596,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":170,""r"":1}", + 100000000, 812, 0, 1528.6,chromobius,8128531c9100b503dd58af3d25f092c8d3b6ad82c503eb66a669f76fef6524f4,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":170,""r"":1}", + 6172512, 1000, 0, 140.1,chromobius,fdb0b46727af31d3271ba8eca27a908986accb5b4eba8b4e0b2f029d4e4de6e6,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":170,""r"":1}", + 909810, 1034, 0, 27.7,chromobius,d4d621afe1aeb8b09debb49a4b197ca527e033a06fc32a4cdecabd5333998c5a,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":170,""r"":1}", + 205234, 1052, 0, 8.20,chromobius,7b34af65e15ac329cf8f2fd7971211975b8e85b0fe67c2ba717510a119f22bb1,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":170,""r"":1}", + 60828, 1001, 0, 3.02,chromobius,533fcd0a01890c785fd211c777769df096db32b666417536f70ae275b5d3083f,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":170,""r"":1}", + 30274, 1077, 0, 1.80,chromobius,29c64f4d0ef7a3679bb14273c6b318e9ff96745a720773c30a3cb082362cb546,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":170,""r"":1}", + 14219, 1046, 0, 0.967,chromobius,c197e6ca718fbec4eb3548c5bb2045cfa27399bb80108db88c4f1b3409b040ae,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":170,""r"":1}", + 8520, 1010, 0, 0.684,chromobius,d3bf8eac1ed9b9ecafcee190960d56de0341edbccbd80ca64fadf1a1f0e11103,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":170,""r"":1}", + 6316, 1043, 0, 0.542,chromobius,87c67518518fb0fb2f7c1b626b81e71d6ccbf344ca1890426deeb8d2bba3475a,"{""c"":""transit_color_code"",""d"":15,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":170,""r"":1}", + 100000000, 0, 0, 1330.8,chromobius,a68cd5375316f2f31714a16bf2dd9034c4b9610e5f9ff4d82a26012778f9275e,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":272,""r"":1}", + 100000000, 59, 0, 2521.8,chromobius,4fbc4a9882331c0561e1c34774b924574e0a8bc87cb87787c3ca6b0d7fb92a0c,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":272,""r"":1}", + 37739958, 1007, 0, 1436.5,chromobius,8db3db2ec5078dd19b28f43ddd07a4dac3775400e17181e998645e9b900fcc38,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":272,""r"":1}", + 2793296, 1010, 0, 142.5,chromobius,7df1bab624008fa773926222058036fbd3bf25b3d5d4ed4414277415045c4029,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":272,""r"":1}", + 431859, 1038, 0, 28.3,chromobius,98eb27949cfe815a9ab3770e0c8c224cc34b4d0ab38b36fa8f19306429de67d8,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":272,""r"":1}", + 103169, 1011, 0, 8.56,chromobius,ffb4b3b9f0187f0fab403baa4accb87b2358c28a60ecd050bb6c15cdad1b5a3a,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":272,""r"":1}", + 37086, 1002, 0, 3.83,chromobius,cab6041a80f90180ace3ed1a6d3e0b536cc9d9ea613ad83d81d4e538bcaf8471,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":272,""r"":1}", + 15951, 1002, 0, 1.99,chromobius,c8cbd6242d276dfc2e857e04bde68adebd48467c02037c791e0f56f5b37b114c,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":272,""r"":1}", + 8645, 1002, 0, 1.25,chromobius,83e445e72f679db26a360f5c384eaa347500375ef1509f4999f5322299897de2,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":272,""r"":1}", + 5306, 1008, 0, 0.884,chromobius,83a1e30546f611644a488eaa8c4c9394d3ac4e3faa21b1672b2ed92b775782b1,"{""c"":""transit_color_code"",""d"":19,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":272,""r"":1}", + 100000000, 0, 0, 1981.8,chromobius,eaef0a5ffd759253cea3bee87b6b3d2edb1794294d5f00cd16d29ec7604e6adb,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":398,""r"":1}", + 100000000, 1, 0, 3777.6,chromobius,7dd80613aa4f2870c4b3be04a799d165f65ccdd060dd402aacaa05f4d58d4f29,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":398,""r"":1}", + 100000000, 440, 0, 5717.8,chromobius,e4e7f904c98dc5872afeabf4d01d89ee873a3988fb23a1b7b3f2f680835f861b,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":398,""r"":1}", + 9847638, 1092, 0, 766.1,chromobius,2925e42ca2eb5d9b38d55af0f4d562293b3b1740090414e28a03b759a8603e93,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":398,""r"":1}", + 875350, 1038, 0, 87.0,chromobius,9dceba08235b7895086cb92b47c4b8b46671fa5b7f0b53470b427fabe01ebac6,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":398,""r"":1}", + 174439, 1035, 0, 22.0,chromobius,1b9705ba82bbbf09046e763e6fb58e7087b4f33f004e2317276c880ae8ea6b29,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":398,""r"":1}", + 50400, 1120, 0, 7.95,chromobius,18a1426a5e85b77dcf892a6b8ae73d8032b4fa5969f6459dbe012787ff16d9bd,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":398,""r"":1}", + 18792, 1039, 0, 3.67,chromobius,9f1b5f4cfdeed7c9762526e0c983e0ab6f2086e2a780e485e78fc5bd2f53fe7d,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":398,""r"":1}", + 8355, 1001, 0, 1.97,chromobius,78f27d71f3dd4eb1a67b6281a6f91724b3c08c544a5a1ec202f50057894e0203,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":398,""r"":1}", + 5258, 1005, 0, 1.44,chromobius,8539e1e288569de509d42bf1d7a7a5b91e675ff33e3fbe32516f99316b2ca271,"{""c"":""transit_color_code"",""d"":23,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":398,""r"":1}", + 100000000, 0, 0, 2782.1,chromobius,390b97bb4775ee4b30775be7ab252fd576a54aedbca47ebe6e99a09c1d5eb852,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":548,""r"":1}", + 100000000, 0, 0, 5301.9,chromobius,0afda8f09a9dc6a573aabda11f54b90e8cee72562803ec3666207249651220e8,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":548,""r"":1}", + 100000000, 85, 0, 8067.2,chromobius,c6cac227deae57b94c776010af4ec8611c47a4292d61428135d111079ece5b63,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":548,""r"":1}", + 30453744, 1033, 0, 3367.8,chromobius,12b2c265dec8616ebdacad5279bdba7b5651865a9b5b03f984f860abf5d0af39,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":548,""r"":1}", + 2158053, 1070, 0, 306.0,chromobius,153b89a8722cb44369822695f2dc9ffdafffba5db3de976765556140e8de7b4a,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":548,""r"":1}", + 281707, 1032, 0, 50.3,chromobius,9fb0b0a854e7ea50134107034e4e3dafb4faaca550aff6a3bb92caa0cd0dba40,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":548,""r"":1}", + 58714, 1003, 0, 13.2,chromobius,ee0d8eb1ad52099a6b6f113ffb66937ab387a98d157a06710a216771328eb5c6,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":548,""r"":1}", + 19996, 1108, 0, 5.53,chromobius,7a3258cc1f8c33e06fd6a1a8c507ccf3ddb5f9ea97be0781a556471b54c2539a,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":548,""r"":1}", + 8498, 1012, 0, 2.79,chromobius,76c03a2ad8c41bcac1870bbdb6b4bdd4e33307f4948d3dda45bb60dbebd2eacb,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":548,""r"":1}", + 5018, 1005, 0, 1.93,chromobius,5a3daef5692cf25cfc2498456cb7c72c7f95f0a6accd68c7d7e94042a1e9f437,"{""c"":""transit_color_code"",""d"":27,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":548,""r"":1}", + 100000000, 0, 0, 3739.7,chromobius,a0ab1b00031fb52d44364d35b799ca1b8f9457c271bd1986ce1034a56003dc09,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.01,""q"":722,""r"":1}", + 100000000, 1, 0, 7164.1,chromobius,ec2b42cda8effd3114adf9992a3773ec64c40601bc8e787bf2ead6c258a3bed2,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.02,""q"":722,""r"":1}", + 100000000, 13, 0, 10834.6,chromobius,db8b54b82aa5ac0632fb5717d9962b0293fff60aac088fb342a96018401c2629,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.03,""q"":722,""r"":1}", + 100000000, 912, 0, 14705.0,chromobius,b26afac9aed873db86127ddf8cc0412a1729fa253e45da53732378196cfe91b9,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.04,""q"":722,""r"":1}", + 4444063, 1014, 0, 850.3,chromobius,bd8018eebde7be227813c18a1ca1776cb6ac89300c36898e155ad6a2cd9cd527,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.05,""q"":722,""r"":1}", + 436110, 1001, 0, 105.5,chromobius,baac476bafffdb2b430b393f8a79273d81a6dc6b5a376dd03f259bbf80ae5f2e,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.06,""q"":722,""r"":1}", + 83492, 1105, 0, 25.4,chromobius,6606a8146c07234564338a7262fa3b87471cc222d5fcfaa25df571f857f39fa5,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.07,""q"":722,""r"":1}", + 21162, 1002, 0, 8.02,chromobius,57d528f281f1415ac1f179914b24b67ada1b5bdf4f7d21d2eb7161860bde47a5,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.08,""q"":722,""r"":1}", + 8940, 1030, 0, 4.12,chromobius,559d2abf23921ecd09405d4b3db0f31c2b42499937a17634b1f1f0516d82ed37,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.09,""q"":722,""r"":1}", + 4837, 1037, 0, 2.65,chromobius,4b194c42e3073a19785c86de55ba1b1e71a0a444705fc106b631160e24d1d554,"{""c"":""transit_color_code"",""d"":31,""gates"":""all"",""noise"":""bitflip"",""p"":0.1,""q"":722,""r"":1}", diff --git a/assets/superdense-detslice-cycle.png b/assets/superdense-detslice-cycle.png new file mode 100644 index 0000000..b6073ff Binary files /dev/null and b/assets/superdense-detslice-cycle.png differ diff --git a/assets/superdense-detslice-cycle.svg b/assets/superdense-detslice-cycle.svg new file mode 100644 index 0000000..b735195 --- /dev/null +++ b/assets/superdense-detslice-cycle.svg @@ -0,0 +1,31652 @@ + + + +RXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRXRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM diff --git a/assets/superdense_detectors.svg b/assets/superdense_detectors.svg new file mode 100644 index 0000000..33e70c6 --- /dev/null +++ b/assets/superdense_detectors.svg @@ -0,0 +1,9078 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/superdense_detectors_2.svg b/assets/superdense_detectors_2.svg new file mode 100644 index 0000000..a2e6775 --- /dev/null +++ b/assets/superdense_detectors_2.svg @@ -0,0 +1,15766 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +RX + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + +R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +MX + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + +M + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/timing_stats.csv b/assets/timing_stats.csv new file mode 100644 index 0000000..f9b7df6 --- /dev/null +++ b/assets/timing_stats.csv @@ -0,0 +1,331 @@ + shots, errors, discards, seconds,decoder,strong_id,json_metadata,custom_counts + 7995885, 94709, 0, 1.00,chromobius,af36d35ccbe0e5837ccccbde00140466e0f1becf556f561eb60b2e1da82c1918,"{""c"":""midout_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0001,""q"":9,""r"":12}","{""detection_events"":898089}" + 4529752, 106136, 0, 1.00,chromobius,5d6e70e95a38c9fd54f242b8f4c560de4acdb8b240dd5603576c4a070081a121,"{""c"":""midout_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0002,""q"":9,""r"":12}","{""detection_events"":1015781}" + 3231013, 112601, 0, 1.00,chromobius,696dfa9a175eb1493f0b74d9d6b85731bacc82ad9dd5f024882cbffdaa821f9b,"{""c"":""midout_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0003,""q"":9,""r"":12}","{""detection_events"":1084999}" + 2012061, 113866, 0, 1.00,chromobius,e9f0f33a439dcd2b53a6f83726e8b4a43d68dc6ff7c58319f8ece54e1374a476,"{""c"":""midout_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0005,""q"":9,""r"":12}","{""detection_events"":1121147}" + 1427997, 110781, 0, 1.00,chromobius,693561707dc8983e9efd58bfe211f571225893675d49ec3907a72b4febd047b0,"{""c"":""midout_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0007,""q"":9,""r"":12}","{""detection_events"":1108553}" + 1011219, 108764, 0, 1.00,chromobius,5941daa39769602f58e8a5a26db1483c02f9f0eb60657e92dfc6a04a5f7bca1c,"{""c"":""midout_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.001,""q"":9,""r"":12}","{""detection_events"":1116497}" + 508437, 98393, 0, 1.00,chromobius,9dac657bb25516d2de894296a8ae0ebed72ed270d5c3201aec39c532d379902f,"{""c"":""midout_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.002,""q"":9,""r"":12}","{""detection_events"":1093797}" + 346643, 90492, 0, 1.00,chromobius,9bac7b9b0eda977c9fe796c5d4c24a7e02989572e16ee37942a6d551e920f147,"{""c"":""midout_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.003,""q"":9,""r"":12}","{""detection_events"":1087980}" + 210224, 75952, 0, 1.00,chromobius,38461602ef05b83e72d1b72885adc03c933cbe7398f60e4f8d231e390ee3ee70,"{""c"":""midout_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.005,""q"":9,""r"":12}","{""detection_events"":1047855}" + 153197, 63975, 0, 1.00,chromobius,53617749c1c839b22e1885431076f0ce528eceea27167918ef58e4aa49af3194,"{""c"":""midout_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.007,""q"":9,""r"":12}","{""detection_events"":1022101}" + 107381, 49928, 0, 1.00,chromobius,d6334bf471a995dffe4cecbe2ce3fe4f501fd212030c1c2b15fa6cd275728781,"{""c"":""midout_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.01,""q"":9,""r"":12}","{""detection_events"":957569}" + 970235, 247, 0, 1.00,chromobius,be5f4c62c5875c6a2d328d8a9f4cdc0aab77e8bc6378576ce92086c69038c56e,"{""c"":""midout_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0001,""q"":23,""r"":20}","{""detection_events"":589907}" + 503948, 520, 0, 1.00,chromobius,099019e5ead9ff279160d781bd385aa023e4a75e78e97c5593c3f94abfc1af30,"{""c"":""midout_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0002,""q"":23,""r"":20}","{""detection_events"":609607}" + 329811, 770, 0, 1.00,chromobius,79a18889c43c971dce2d0133b36ea001daf151825510f320e9517f9d7b1bab09,"{""c"":""midout_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0003,""q"":23,""r"":20}","{""detection_events"":597646}" + 195326, 1238, 0, 1.00,chromobius,ab1e15c14892bfb374ff97b15ff8647bd2507df3aa5116d63402765ca44c7435,"{""c"":""midout_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0005,""q"":23,""r"":20}","{""detection_events"":588111}" + 138992, 1719, 0, 1.00,chromobius,b024405c77f6c81714df8e1c0c407ddd87b69b335a87c8b23e96ef29351d4433,"{""c"":""midout_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0007,""q"":23,""r"":20}","{""detection_events"":580219}" + 96340, 2316, 0, 1.00,chromobius,e79f1016bc2e92f8ab2276b1931c4c5aaad31c52443d5db3750293f3a5105bf1,"{""c"":""midout_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.001,""q"":23,""r"":20}","{""detection_events"":571454}" + 46148, 3983, 0, 1.00,chromobius,cd832936d53fe50d8bdcf04344b731768ef2be1358133d7a534a25001212d24f,"{""c"":""midout_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.002,""q"":23,""r"":20}","{""detection_events"":532431}" + 29838, 5119, 0, 1.00,chromobius,bcc5a04c61b5ebcd5d80923a46a0024d894dcc7b9633062eaa4f9c6c4e68f9ae,"{""c"":""midout_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.003,""q"":23,""r"":20}","{""detection_events"":503445}" + 17176, 5568, 0, 1.01,chromobius,5179e3ae74bfeeef8b848db4584dff4a6a716fe287c16c79c52fb7a6f4ea5277,"{""c"":""midout_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.005,""q"":23,""r"":20}","{""detection_events"":455312}" + 12307, 5133, 0, 1.00,chromobius,69ddb3bbb41b36853279cf810bd2a77055d7f25b34593da9b18f676df632a9c3,"{""c"":""midout_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.007,""q"":23,""r"":20}","{""detection_events"":434851}" + 8542, 4148, 0, 1.00,chromobius,8821209dc9286890dcc5d74fd42f816399a53bf329ca0553848aebd396fee483,"{""c"":""midout_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.01,""q"":23,""r"":20}","{""detection_events"":398350}" + 355184, 62, 0, 1.00,chromobius,c8e8fa7abb7d900d3bdb74d2d33b79621693bdcbc63085b2caab4dc7c17a995e,"{""c"":""midout_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0001,""q"":43,""r"":28}","{""detection_events"":599387}" + 175078, 99, 0, 1.00,chromobius,66bf1c5e6b6b87fff6271ef17741abd6a51271437dd33b48766d00f7cb6847dc,"{""c"":""midout_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0002,""q"":43,""r"":28}","{""detection_events"":589632}" + 116758, 136, 0, 1.00,chromobius,3acf3862a9a22522af398cdecbc789d21936c66d4ff5d343b7c4c4d4c3545acf,"{""c"":""midout_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0003,""q"":43,""r"":28}","{""detection_events"":587524}" + 69426, 249, 0, 1.00,chromobius,3a56bbfd4d35f1e93cc30825a540152cca408404e6a5e7162d7352d915beea2e,"{""c"":""midout_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0005,""q"":43,""r"":28}","{""detection_events"":580572}" + 48912, 389, 0, 1.00,chromobius,b376e4432a0f87699222448ef583731c6cdc270e684c385643db9854b3180750,"{""c"":""midout_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0007,""q"":43,""r"":28}","{""detection_events"":568617}" + 33124, 588, 0, 1.00,chromobius,de6bb0caa40e381edf526c9a058224baffee4dac64056f0ef4b8ef980cb9846d,"{""c"":""midout_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.001,""q"":43,""r"":28}","{""detection_events"":545629}" + 15548, 1193, 0, 1.02,chromobius,3e05c1ade98764c62bd0dc5233d5ad2258c267ebd5f585d8f21dc56d83cbdf24,"{""c"":""midout_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.002,""q"":43,""r"":28}","{""detection_events"":495318}" + 9848, 1686, 0, 1.02,chromobius,1fee345526867e79c8c57234d4b56406143cec1dbb93205c7a6c7c990b2617d5,"{""c"":""midout_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.003,""q"":43,""r"":28}","{""detection_events"":460973}" + 5474, 1998, 0, 1.02,chromobius,1768676ec211bae4240436470d4af097c4eea93d62f04c071f8e2ede0997d93c,"{""c"":""midout_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.005,""q"":43,""r"":28}","{""detection_events"":401878}" + 3962, 1841, 0, 1.07,chromobius,87a64f235f6323a8e02d90067b432fef0cbcf6a6bd726cd069236e50eee57e31,"{""c"":""midout_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.007,""q"":43,""r"":28}","{""detection_events"":383982}" + 2800, 1387, 0, 1.14,chromobius,6351d32ce60f9b6b6102bd69a7dc06870c38800e6cebdeba5f9b32e05089ec97,"{""c"":""midout_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.01,""q"":43,""r"":28}","{""detection_events"":358208}" + 155231, 1, 0, 1.00,chromobius,45d76a3020abee42e7832378e366501719f5e5447e67971f65e791970acceb67,"{""c"":""midout_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0001,""q"":69,""r"":36}","{""detection_events"":569187}" + 77285, 1, 0, 1.01,chromobius,231a2de2a7f098c3999800a2bb6675506b9facb904f8430601905fbbea4ecc4f,"{""c"":""midout_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0002,""q"":69,""r"":36}","{""detection_events"":565424}" + 52404, 6, 0, 1.01,chromobius,d4c9182f7abf431d80e0e903a18f1fb84f308e729b38e7de4c62c539d4655008,"{""c"":""midout_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0003,""q"":69,""r"":36}","{""detection_events"":573238}" + 30508, 22, 0, 1.00,chromobius,7b2ca34cce2d44207fb296a521a56fd1b86a9b41ebaae792c37168773cfa473f,"{""c"":""midout_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0005,""q"":69,""r"":36}","{""detection_events"":550900}" + 21233, 52, 0, 1.00,chromobius,a91586645a16bc68fb0d0b39ee797edbfbc0ce6b6670838cd3ee9f760c3aa533,"{""c"":""midout_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0007,""q"":69,""r"":36}","{""detection_events"":534913}" + 14847, 89, 0, 1.02,chromobius,f51768c7fd344fd83aa79dbbcf54d27fe07eef29fae0636154308ee6c2fe54e5,"{""c"":""midout_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.001,""q"":69,""r"":36}","{""detection_events"":528001}" + 6866, 283, 0, 1.04,chromobius,4f263dd6a6767124ceec72f251b19490310c7c5b47323bc27efd646023dd06df,"{""c"":""midout_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.002,""q"":69,""r"":36}","{""detection_events"":475146}" + 4096, 559, 0, 1.00,chromobius,34130a250f2c440b4cc06c9018a816a247814535522a75a55aa5eaa6358f776f,"{""c"":""midout_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.003,""q"":69,""r"":36}","{""detection_events"":412392}" + 2424, 912, 0, 1.11,chromobius,87e78f9c11a029320907b8b8e83a7a66331c661bbd37156ff9bd069fdde19537,"{""c"":""midout_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.005,""q"":69,""r"":36}","{""detection_events"":383980}" + 1507, 758, 0, 1.06,chromobius,8c08afb808b6ce0ea14704e7524b1b3176cbac39315e96086563cc5acd1162ea,"{""c"":""midout_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.007,""q"":69,""r"":36}","{""detection_events"":314815}" + 974, 492, 0, 1.11,chromobius,f1321fa54edfc3a5e747feb34765a93ba0e505d6c12b5ccd9f253cc2765515d0,"{""c"":""midout_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.01,""q"":69,""r"":36}","{""detection_events"":268029}" + 81417, 0, 0, 1.00,chromobius,dca5c011ec73000ac7d840843c4fd7c8b9c675e39c78b25db7cfe222584c1925,"{""c"":""midout_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0001,""q"":101,""r"":44}","{""detection_events"":546293}" + 41201, 0, 0, 1.00,chromobius,d325b52547943ceca3c34348b25e840185aefec627c7944e6358d87f2e749ab7,"{""c"":""midout_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0002,""q"":101,""r"":44}","{""detection_events"":551247}" + 27565, 1, 0, 1.00,chromobius,7d09400c6bb8fa0b634a14a670e184167109dc7a8eb8c5a90d0649616646301c,"{""c"":""midout_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0003,""q"":101,""r"":44}","{""detection_events"":552040}" + 16384, 2, 0, 1.01,chromobius,488f1504bafc5660816674fde088d8f1892d3e505fc8eccc5f2c1b40de88c0d0,"{""c"":""midout_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0005,""q"":101,""r"":44}","{""detection_events"":542618}" + 11646, 8, 0, 1.03,chromobius,77ac6ffd84a8f1c9bce95058042d915a3941aa74b8801f15ca89b008756ae4c8,"{""c"":""midout_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0007,""q"":101,""r"":44}","{""detection_events"":536689}" + 8041, 17, 0, 1.04,chromobius,c23de7d8cd984e0e112b317d419d6e2baceabd2000de0776e5c6401569a68606,"{""c"":""midout_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.001,""q"":101,""r"":44}","{""detection_events"":524054}" + 3876, 107, 0, 1.15,chromobius,1b75708cc13672ba2c2339c91c0b694fadf79246de0e11d98854f21018fa17ea,"{""c"":""midout_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.002,""q"":101,""r"":44}","{""detection_events"":489611}" + 2183, 253, 0, 1.03,chromobius,67d3612fd43bff457b144bc41eb1882c26952c8f1431841d7ef2111cfcb74790,"{""c"":""midout_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.003,""q"":101,""r"":44}","{""detection_events"":402267}" + 1158, 444, 0, 1.07,chromobius,2ccbf642837d1cc2d3d4ce839d04956dcd5383ed4e6bf58346cdf3b54f8f08ae,"{""c"":""midout_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.005,""q"":101,""r"":44}","{""detection_events"":334337}" + 723, 347, 0, 1.08,chromobius,57fa33ad902a94df5d23c43db5c9bcbf9f27cca55564c43285dbcf22050c9399,"{""c"":""midout_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.007,""q"":101,""r"":44}","{""detection_events"":276463}" + 423, 200, 0, 1.11,chromobius,aec3bd99945c893459f8ea319ea52011a63968bcd2462372b6cf1350cacefd5a,"{""c"":""midout_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.01,""q"":101,""r"":44}","{""detection_events"":211640}" + 45703, 0, 0, 1.00,chromobius,7e7076905d611bccd7056159614ebcb16e43c02dd0983778d812490ed553db8d,"{""c"":""midout_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0001,""q"":139,""r"":52}","{""detection_events"":506613}" + 24248, 0, 0, 1.00,chromobius,ed8b15f298e58f38232ea03b14c569670723218198956c9f78664ad330ce86be,"{""c"":""midout_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0002,""q"":139,""r"":52}","{""detection_events"":538021}" + 16040, 0, 0, 1.03,chromobius,77b3fa04626a61ffa4fa0eeda0785d06e72060887f1e6136447d70224555ec28,"{""c"":""midout_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0003,""q"":139,""r"":52}","{""detection_events"":531954}" + 9384, 0, 0, 1.01,chromobius,4c5090bf1b2717f6de24516c870915e4ac909e3357597ea801ef734868e45619,"{""c"":""midout_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0005,""q"":139,""r"":52}","{""detection_events"":515854}" + 6952, 4, 0, 1.06,chromobius,3ac3ae0f04d3d26c732053a766dc4bcc014e10c349331e776a7a11cd849fb154,"{""c"":""midout_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0007,""q"":139,""r"":52}","{""detection_events"":532178}" + 4463, 6, 0, 1.01,chromobius,00a4a22ecc0c749206ca4856645ab2a3eecb7a4c0b4d75e6cba4795c35147ee1,"{""c"":""midout_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.001,""q"":139,""r"":52}","{""detection_events"":483605}" + 2230, 34, 0, 1.08,chromobius,f4dca551fa8bdfa91ee676da958f5a3ce213aa13d413b7906a5019d742ce3bfe,"{""c"":""midout_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.002,""q"":139,""r"":52}","{""detection_events"":467900}" + 1339, 107, 0, 1.07,chromobius,334d4ffb5beb53e64f2f8d299d44e92542257e2ceccca749e075fbb5431c5c41,"{""c"":""midout_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.003,""q"":139,""r"":52}","{""detection_events"":407047}" + 630, 242, 0, 1.08,chromobius,fcaf7bb2f58166165f924192f490c6e7c00be12df46aaebce1441a83e66b3731,"{""c"":""midout_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.005,""q"":139,""r"":52}","{""detection_events"":300093}" + 339, 163, 0, 1.06,chromobius,9b074d6b7055d9df1177430c10484b58da5caac7d29c09bdc297d8dcee7d3c4a,"{""c"":""midout_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.007,""q"":139,""r"":52}","{""detection_events"":214861}" + 204, 92, 0, 1.14,chromobius,e529559b29078e13e73fcf8ef392592ca301d2dc82a53dbc22db6e9cc1f9a9be,"{""c"":""midout_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.01,""q"":139,""r"":52}","{""detection_events"":169541}" + 14717613, 87, 0, 1.00,chromobius,c1ca7568fa9d4a0e505009c369e9dc1e2a0af6bfc7354ac8298c94ceafbbdb3d,"{""c"":""phenom_color_code"",""d"":3,""noise"":""uniform"",""p"":0.0001,""q"":8,""r"":12}","{""detection_events"":494753}" + 9663742, 196, 0, 1.00,chromobius,182943fa6fb8378bffce82d77daf2929e02982f51cd2138943a9bd8e73d8e372,"{""c"":""phenom_color_code"",""d"":3,""noise"":""uniform"",""p"":0.0002,""q"":8,""r"":12}","{""detection_events"":647556}" + 7229440, 355, 0, 1.00,chromobius,e7982efc9caecb89c84e2ef852b4cd418f1a8334f28114f58c26026618ac7bb9,"{""c"":""phenom_color_code"",""d"":3,""noise"":""uniform"",""p"":0.0003,""q"":8,""r"":12}","{""detection_events"":729706}" + 4847586, 630, 0, 1.00,chromobius,5d4833f915f29c2b568c00ea008afff51b4566028395a3c5edeafdd904756132,"{""c"":""phenom_color_code"",""d"":3,""noise"":""uniform"",""p"":0.0005,""q"":8,""r"":12}","{""detection_events"":812446}" + 3610610, 894, 0, 1.00,chromobius,c25cce5ed8f0615c8debff44badf1456bd4da79b4515b3a05e3d218b6fa04ab5,"{""c"":""phenom_color_code"",""d"":3,""noise"":""uniform"",""p"":0.0007,""q"":8,""r"":12}","{""detection_events"":847455}" + 2635496, 1429, 0, 1.00,chromobius,e1dfea538e0438192772c30ca7563455ab870a8306bdee05b55e4af731cc467b,"{""c"":""phenom_color_code"",""d"":3,""noise"":""uniform"",""p"":0.001,""q"":8,""r"":12}","{""detection_events"":884223}" + 1354103, 2913, 0, 1.00,chromobius,875dfa0cab934fac2831e2fea32081108f36a2bf65e62bd3ba11a971d652b7cc,"{""c"":""phenom_color_code"",""d"":3,""noise"":""uniform"",""p"":0.002,""q"":8,""r"":12}","{""detection_events"":905525}" + 917089, 4276, 0, 1.00,chromobius,bd9d3004902813a3f321ad36b91d9d2ff6edc7098ef0f78fceddd0fbcd32f390,"{""c"":""phenom_color_code"",""d"":3,""noise"":""uniform"",""p"":0.003,""q"":8,""r"":12}","{""detection_events"":915754}" + 535394, 6732, 0, 1.00,chromobius,5c6825465ee1e76dfe78db2397500b2e9af088e31d209eb262a12e33007e1067,"{""c"":""phenom_color_code"",""d"":3,""noise"":""uniform"",""p"":0.005,""q"":8,""r"":12}","{""detection_events"":883297}" + 381244, 9150, 0, 1.00,chromobius,9f8907d7a36f7874603bddda2b2bc4649b0a3d68835cd709aa2769b53ff75b99,"{""c"":""phenom_color_code"",""d"":3,""noise"":""uniform"",""p"":0.007,""q"":8,""r"":12}","{""detection_events"":875494}" + 266996, 12475, 0, 1.00,chromobius,cf51842cd3defdd79db9d012c667d3734e3b74094bd168e7fc62adba41459626,"{""c"":""phenom_color_code"",""d"":3,""noise"":""uniform"",""p"":0.01,""q"":8,""r"":12}","{""detection_events"":864170}" + 3938648, 0, 0, 1.00,chromobius,1f154bdbf7f77d84ddcb3e0cd02ca9b7368c71474bc960488b753850e75e2cb8,"{""c"":""phenom_color_code"",""d"":5,""noise"":""uniform"",""p"":0.0001,""q"":20,""r"":20}","{""detection_events"":725300}" + 2240129, 0, 0, 1.00,chromobius,ef6e24a6c03f84381c540c623a85c3bc6238b0c0f7f56c6804d9c0dd7ed201ee,"{""c"":""phenom_color_code"",""d"":5,""noise"":""uniform"",""p"":0.0002,""q"":20,""r"":20}","{""detection_events"":824948}" + 1564058, 0, 0, 1.00,chromobius,5dc5062a8c2459a43791fda9b7dedd140a963b65aba163c40b5c22ceaf7d0c74,"{""c"":""phenom_color_code"",""d"":5,""noise"":""uniform"",""p"":0.0003,""q"":20,""r"":20}","{""detection_events"":862906}" + 965333, 3, 0, 1.00,chromobius,6de5fc0a8ec3bb37c3025f1c686d60b08055d2cf7c1568c7448be1dc6bed9329,"{""c"":""phenom_color_code"",""d"":5,""noise"":""uniform"",""p"":0.0005,""q"":20,""r"":20}","{""detection_events"":886694}" + 701448, 1, 0, 1.00,chromobius,3eeb13974db010f0704fce6cb5a92f6d24cf086c361a2a00c451a53cb344ec4b,"{""c"":""phenom_color_code"",""d"":5,""noise"":""uniform"",""p"":0.0007,""q"":20,""r"":20}","{""detection_events"":898860}" + 495201, 7, 0, 1.00,chromobius,d7d7ac54b3c29dbc763eaa13bf632c1d0fee58d5ab7d104069129c6b5c8b7981,"{""c"":""phenom_color_code"",""d"":5,""noise"":""uniform"",""p"":0.001,""q"":20,""r"":20}","{""detection_events"":907585}" + 247549, 31, 0, 1.00,chromobius,21bf5b2d09a5e51325b0c4eb81b3a0956748541d8b1933e28bf3823ddda8a7ee,"{""c"":""phenom_color_code"",""d"":5,""noise"":""uniform"",""p"":0.002,""q"":20,""r"":20}","{""detection_events"":903097}" + 163063, 74, 0, 1.00,chromobius,f438d6b2f28f85f565cf0dbdd15c732342fd5957e7edec2b19379ae90ec8fa0b,"{""c"":""phenom_color_code"",""d"":5,""noise"":""uniform"",""p"":0.003,""q"":20,""r"":20}","{""detection_events"":891361}" + 96850, 201, 0, 1.00,chromobius,e7bca189a05503c762a3362118e6a3f686b6eb31cd57fcfc6f50aa4e12a69c0b,"{""c"":""phenom_color_code"",""d"":5,""noise"":""uniform"",""p"":0.005,""q"":20,""r"":20}","{""detection_events"":874210}" + 68143, 359, 0, 1.00,chromobius,755c25b792c8199aa1a2a1f7d348d39919f802e6f5f2c05bc0ea83c91a2168b1,"{""c"":""phenom_color_code"",""d"":5,""noise"":""uniform"",""p"":0.007,""q"":20,""r"":20}","{""detection_events"":851661}" + 46921, 747, 0, 1.01,chromobius,57051ec092d944a1e38eda4d5edaf1ceb5071f61b18e8be216a6d15c432448b1,"{""c"":""phenom_color_code"",""d"":5,""noise"":""uniform"",""p"":0.01,""q"":20,""r"":20}","{""detection_events"":827069}" + 1410295, 0, 0, 1.00,chromobius,74233dfac3223be48b6bc3c806977c857ad109f5a315a7a75858d9a8aa531cbf,"{""c"":""phenom_color_code"",""d"":7,""noise"":""uniform"",""p"":0.0001,""q"":38,""r"":28}","{""detection_events"":760337}" + 786813, 0, 0, 1.00,chromobius,5ea89f6e84fe674a94860ec0f345e27f65db01364329cf1944342a74fc1734ae,"{""c"":""phenom_color_code"",""d"":7,""noise"":""uniform"",""p"":0.0002,""q"":38,""r"":28}","{""detection_events"":845820}" + 539303, 0, 0, 1.00,chromobius,e49ad70c479c8f02c77594cbaaebfb59a63f067858593f714ff2a34bb1f6b32f,"{""c"":""phenom_color_code"",""d"":7,""noise"":""uniform"",""p"":0.0003,""q"":38,""r"":28}","{""detection_events"":868517}" + 331172, 0, 0, 1.00,chromobius,5324235c5373520a246d45231848bfb726b45165708204ffb0aea711cad4e053,"{""c"":""phenom_color_code"",""d"":7,""noise"":""uniform"",""p"":0.0005,""q"":38,""r"":28}","{""detection_events"":886938}" + 235471, 0, 0, 1.00,chromobius,a228869cc01c3ef50465a7a10b2c6d7dbecad32e84d0bdaed4db07e83794cf28,"{""c"":""phenom_color_code"",""d"":7,""noise"":""uniform"",""p"":0.0007,""q"":38,""r"":28}","{""detection_events"":883962}" + 167462, 0, 0, 1.00,chromobius,8844d396ec62451a36e1828f56cba471e386d9ca54dc42749b9d9ab2a41968de,"{""c"":""phenom_color_code"",""d"":7,""noise"":""uniform"",""p"":0.001,""q"":38,""r"":28}","{""detection_events"":897048}" + 84121, 0, 0, 1.00,chromobius,e288c5afe5b3f6a7645352a48c3f4f18595a0177ac1998fd42a8559709c8c269,"{""c"":""phenom_color_code"",""d"":7,""noise"":""uniform"",""p"":0.002,""q"":38,""r"":28}","{""detection_events"":898569}" + 56051, 0, 0, 1.00,chromobius,346112bd893eb0b9530af80a644d273f7cbd1ce3f7fa5f33aaa65a159c200c29,"{""c"":""phenom_color_code"",""d"":7,""noise"":""uniform"",""p"":0.003,""q"":38,""r"":28}","{""detection_events"":891161}" + 32768, 8, 0, 1.01,chromobius,3a20d044a00aef37a405cb50877d41a58e3adf4a80a40c2a544f59aac4e9f709,"{""c"":""phenom_color_code"",""d"":7,""noise"":""uniform"",""p"":0.005,""q"":38,""r"":28}","{""detection_events"":860799}" + 23016, 22, 0, 1.01,chromobius,df0593f67464b458bcba40ccfced5d0ee7129c13d2a28582d4c6838f8d7961aa,"{""c"":""phenom_color_code"",""d"":7,""noise"":""uniform"",""p"":0.007,""q"":38,""r"":28}","{""detection_events"":838153}" + 15625, 73, 0, 1.02,chromobius,f6bef0b45e593196fcb843fc38317b8b19a653cabd531184dea94b4169ca7498,"{""c"":""phenom_color_code"",""d"":7,""noise"":""uniform"",""p"":0.01,""q"":38,""r"":28}","{""detection_events"":801358}" + 624539, 0, 0, 1.00,chromobius,2899b13b18071e59be823b6247c51a1a258cffaeb5c5ba9f5afbf4d7fda635b4,"{""c"":""phenom_color_code"",""d"":9,""noise"":""uniform"",""p"":0.0001,""q"":62,""r"":36}","{""detection_events"":736558}" + 342228, 0, 0, 1.00,chromobius,5c555cfa6f085b5aa69365a129e9b712e08a51b3d0a00482b21d2b4954045476,"{""c"":""phenom_color_code"",""d"":9,""noise"":""uniform"",""p"":0.0002,""q"":62,""r"":36}","{""detection_events"":806571}" + 233040, 0, 0, 1.00,chromobius,70f85606748c1cb07ccb68eb8817c0ebdd1fd509aedf913524b9b3cfdaa710c3,"{""c"":""phenom_color_code"",""d"":9,""noise"":""uniform"",""p"":0.0003,""q"":62,""r"":36}","{""detection_events"":823215}" + 142986, 0, 0, 1.00,chromobius,5bdb5d99a4c1b3b6200b5cc41c7a34e2a83a9f5113b03c1f55d8495be533895a,"{""c"":""phenom_color_code"",""d"":9,""noise"":""uniform"",""p"":0.0005,""q"":62,""r"":36}","{""detection_events"":845360}" + 103194, 0, 0, 1.00,chromobius,a624fe9400e855d4a0a963a41ba8001138eb0bd5b18fd6d9a692c5c591bf96fd,"{""c"":""phenom_color_code"",""d"":9,""noise"":""uniform"",""p"":0.0007,""q"":62,""r"":36}","{""detection_events"":848546}" + 72291, 0, 0, 1.00,chromobius,6ea1972c8e3e51231d3cbaf43ac6622fae6ad00691d399f193a9bb0d89d48b5f,"{""c"":""phenom_color_code"",""d"":9,""noise"":""uniform"",""p"":0.001,""q"":62,""r"":36}","{""detection_events"":853529}" + 36521, 0, 0, 1.01,chromobius,40bdddc5cb7bd0ed42325babecb7c21773e2263cf068fec93e23d963298816de,"{""c"":""phenom_color_code"",""d"":9,""noise"":""uniform"",""p"":0.002,""q"":62,""r"":36}","{""detection_events"":857502}" + 23478, 0, 0, 1.01,chromobius,835ef4281c07b54f3985d05e923ea25a693942e034838de71b7b20317bc5286a,"{""c"":""phenom_color_code"",""d"":9,""noise"":""uniform"",""p"":0.003,""q"":62,""r"":36}","{""detection_events"":818575}" + 14232, 0, 0, 1.01,chromobius,e7f50b41df470283597177a6573530076c0073460b6f0c0a56ebb6217140964d,"{""c"":""phenom_color_code"",""d"":9,""noise"":""uniform"",""p"":0.005,""q"":62,""r"":36}","{""detection_events"":820765}" + 9788, 0, 0, 1.02,chromobius,ad292f6c21eb26c22d4b8a246794330897ebc29f5a5225e43706fed08b31f22f,"{""c"":""phenom_color_code"",""d"":9,""noise"":""uniform"",""p"":0.007,""q"":62,""r"":36}","{""detection_events"":786362}" + 6887, 3, 0, 1.05,chromobius,1a641f8e063606f809d97f60b2430e3a99048c30b5c58f7ce726a9e11bc6e08b,"{""c"":""phenom_color_code"",""d"":9,""noise"":""uniform"",""p"":0.01,""q"":62,""r"":36}","{""detection_events"":773904}" + 296777, 0, 0, 1.00,chromobius,da63fddb90021a9aef515dd68625402a200c3e9b4f027949bf85ec7bb7b44e1a,"{""c"":""phenom_color_code"",""d"":11,""noise"":""uniform"",""p"":0.0001,""q"":92,""r"":44}","{""detection_events"":650751}" + 164829, 0, 0, 1.00,chromobius,952f5b0c707c6d064ca1fcea610877bd1ce31b6e434fe75cb86cee1230abeab3,"{""c"":""phenom_color_code"",""d"":11,""noise"":""uniform"",""p"":0.0002,""q"":92,""r"":44}","{""detection_events"":724333}" + 110996, 0, 0, 1.00,chromobius,f7aa6d68ffa493e066d9468ac560f3ec23dc3346b39fbf17d4bfb9a484e52967,"{""c"":""phenom_color_code"",""d"":11,""noise"":""uniform"",""p"":0.0003,""q"":92,""r"":44}","{""detection_events"":732907}" + 69898, 0, 0, 1.00,chromobius,630b28b67bc7f2275247deeaa7abfc002f616ff28f7ee2bafca17fbafbe8aa03,"{""c"":""phenom_color_code"",""d"":11,""noise"":""uniform"",""p"":0.0005,""q"":92,""r"":44}","{""detection_events"":769070}" + 50621, 0, 0, 1.00,chromobius,3afda094aad10dd55ce1bea26777a80a7fb1896bd08cb72120dd3c024b84c51d,"{""c"":""phenom_color_code"",""d"":11,""noise"":""uniform"",""p"":0.0007,""q"":92,""r"":44}","{""detection_events"":777451}" + 35423, 0, 0, 1.00,chromobius,fa8e064f0df8c52b9c3a4300d9c38a464b61c191f9f23ca7974987618e75c3f0,"{""c"":""phenom_color_code"",""d"":11,""noise"":""uniform"",""p"":0.001,""q"":92,""r"":44}","{""detection_events"":775814}" + 17968, 0, 0, 1.01,chromobius,4b63b786ae37b89726defae5eacfcd2ef77cee6e7d1572e8569e3010acd4773d,"{""c"":""phenom_color_code"",""d"":11,""noise"":""uniform"",""p"":0.002,""q"":92,""r"":44}","{""detection_events"":784619}" + 11768, 0, 0, 1.03,chromobius,46cd34e562bcd9a87bfa15167fa01458893a817e813e07e63504038ae3c16a29,"{""c"":""phenom_color_code"",""d"":11,""noise"":""uniform"",""p"":0.003,""q"":92,""r"":44}","{""detection_events"":765135}" + 7344, 0, 0, 1.05,chromobius,d8039d1dafebf73da47e3f1c5fd5bb3e5f88e532601978f625514b6200a50439,"{""c"":""phenom_color_code"",""d"":11,""noise"":""uniform"",""p"":0.005,""q"":92,""r"":44}","{""detection_events"":789228}" + 4912, 0, 0, 1.02,chromobius,ee2c97b1ded7d23ef4bfb332009f83ece621d2ba62aa4ee8ca862406d4563b35,"{""c"":""phenom_color_code"",""d"":11,""noise"":""uniform"",""p"":0.007,""q"":92,""r"":44}","{""detection_events"":732816}" + 3596, 0, 0, 1.11,chromobius,d5a4eb8ff3aa2663b9397c594a4283f56e843eebcec83bff759a295bc04e4c9e,"{""c"":""phenom_color_code"",""d"":11,""noise"":""uniform"",""p"":0.01,""q"":92,""r"":44}","{""detection_events"":752838}" + 144678, 0, 0, 1.00,chromobius,98c8f0a7996682f37dab8004402f8adbbcd52869c6796bda4e3f18ebb0a75d24,"{""c"":""phenom_color_code"",""d"":13,""noise"":""uniform"",""p"":0.0001,""q"":128,""r"":52}","{""detection_events"":531187}" + 84396, 0, 0, 1.00,chromobius,781e65481ed95f455265c22988fcb3364660d84c5ef7c9cbc903f0501e15e99c,"{""c"":""phenom_color_code"",""d"":13,""noise"":""uniform"",""p"":0.0002,""q"":128,""r"":52}","{""detection_events"":622975}" + 57030, 0, 0, 1.01,chromobius,7f5def9a1e5f9f44cf35e57f65c4ecb2a7e4cef9bff936b28111134576955d32,"{""c"":""phenom_color_code"",""d"":13,""noise"":""uniform"",""p"":0.0003,""q"":128,""r"":52}","{""detection_events"":629671}" + 37628, 0, 0, 1.00,chromobius,6e89716ee598a900c80981e3f51c210d690baa4c813af8d5274bec751dcb0354,"{""c"":""phenom_color_code"",""d"":13,""noise"":""uniform"",""p"":0.0005,""q"":128,""r"":52}","{""detection_events"":692006}" + 27926, 0, 0, 1.01,chromobius,8c9ffbba08bc54dba701277b93981c619f1c2341823d25faa5207878d0350e9c,"{""c"":""phenom_color_code"",""d"":13,""noise"":""uniform"",""p"":0.0007,""q"":128,""r"":52}","{""detection_events"":719094}" + 19814, 0, 0, 1.01,chromobius,641397d5ecf1fa891b15c77918a4596bede81901b01c9dcc76cf96f81805dfb8,"{""c"":""phenom_color_code"",""d"":13,""noise"":""uniform"",""p"":0.001,""q"":128,""r"":52}","{""detection_events"":727779}" + 10078, 0, 0, 1.02,chromobius,5e565029c2a64f0252d68f7f3d7c46ebe8a723d0a84741477413034b6b819853,"{""c"":""phenom_color_code"",""d"":13,""noise"":""uniform"",""p"":0.002,""q"":128,""r"":52}","{""detection_events"":732954}" + 6636, 0, 0, 1.04,chromobius,41fdf4879409cfc33a31205836013738c976c6af113b2495785875443a039485,"{""c"":""phenom_color_code"",""d"":13,""noise"":""uniform"",""p"":0.003,""q"":128,""r"":52}","{""detection_events"":721416}" + 3993, 0, 0, 1.07,chromobius,b49fa168326f756de1cc248a4debd1473c66342cecc124cbb54ff507872175bd,"{""c"":""phenom_color_code"",""d"":13,""noise"":""uniform"",""p"":0.005,""q"":128,""r"":52}","{""detection_events"":720157}" + 3089, 0, 0, 1.14,chromobius,67dcd29f4c0f0f9febd4a66efcb0d8e31640bab6e409d84ff6b09dda362fb0eb,"{""c"":""phenom_color_code"",""d"":13,""noise"":""uniform"",""p"":0.007,""q"":128,""r"":52}","{""detection_events"":772276}" + 2055, 0, 0, 1.14,chromobius,043938179909dc65bf1bfc2a537936484aa7c41e1ebf7d0e08b48c377a0e08fe,"{""c"":""phenom_color_code"",""d"":13,""noise"":""uniform"",""p"":0.01,""q"":128,""r"":52}","{""detection_events"":718728}" + 1963831, 4642, 0, 1.00,chromobius,043c652d2f19815a3f0a8b2ef4a021ea3ed1531ec63a81fc993daf42774ceccc,"{""c"":""superdense_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0001,""q"":13,""r"":12}","{""detection_events"":553850}" + 1008784, 5241, 0, 1.00,chromobius,aa0d7c3809c3d93f48358cc4678ef1921505bf893d7385d26c9139e3edb0b552,"{""c"":""superdense_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0002,""q"":13,""r"":12}","{""detection_events"":566161}" + 690325, 5960, 0, 1.00,chromobius,f50a7f372950ed42d13e3c7f6926f0cbdf71712d7445f450072ee1c10be76ad4,"{""c"":""superdense_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0003,""q"":13,""r"":12}","{""detection_events"":577950}" + 412584, 6815, 0, 1.00,chromobius,c7e283014a06eccdf889989958ba4f841a438cafa30c30b3c61157dd8ce46e94,"{""c"":""superdense_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0005,""q"":13,""r"":12}","{""detection_events"":572560}" + 292423, 7715, 0, 1.00,chromobius,2794dc0fcc06b37647cd0d235d17ed23da819baa0ec861c25738b98300c54e3b,"{""c"":""superdense_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0007,""q"":13,""r"":12}","{""detection_events"":562086}" + 205066, 8910, 0, 1.00,chromobius,955d9720bba9f3683c1db7f0d9b3a7adf30d4f2d79bda7759fc23ca42df5bc17,"{""c"":""superdense_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.001,""q"":13,""r"":12}","{""detection_events"":558911}" + 102224, 11982, 0, 1.00,chromobius,d0f3c19b86524c4954d71964e211e23d7b5041276f6cb61b53ba856eb07851ef,"{""c"":""superdense_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.002,""q"":13,""r"":12}","{""detection_events"":535934}" + 69305, 13639, 0, 1.00,chromobius,44d0b1e95cd6cc63ddbbc15131841fb541c96d841c1423f07183ca0cf2bd8e52,"{""c"":""superdense_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.003,""q"":13,""r"":12}","{""detection_events"":523299}" + 42474, 14296, 0, 1.00,chromobius,51d81407e0c85947a2055756e134c3212b08f9e36f37923f931010a37b149306,"{""c"":""superdense_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.005,""q"":13,""r"":12}","{""detection_events"":495614}" + 31931, 13382, 0, 1.01,chromobius,a7534fce73f0f9457ab596a439b697f5fe1ebf2759dcbeb323aadcd29fae2a39,"{""c"":""superdense_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.007,""q"":13,""r"":12}","{""detection_events"":486447}" + 23541, 11284, 0, 1.01,chromobius,c52dfca25e89cf1e27dc644f8b01870f0b41ae003de4f7b84787d7a75c23e503,"{""c"":""superdense_color_code_X"",""d"":3,""noise"":""uniform"",""p"":0.01,""q"":13,""r"":12}","{""detection_events"":460071}" + 366401, 431, 0, 1.00,chromobius,b0a476cebcf83cc2408b3450c38613b41ff70c0bb1fbd72e708795909061facb,"{""c"":""superdense_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0001,""q"":37,""r"":20}","{""detection_events"":569128}" + 184329, 502, 0, 1.00,chromobius,a0f56881d2da39f9418b9d8306c0ec5d514d9a70a57bc2ea40ccead9d9a2252e,"{""c"":""superdense_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0002,""q"":37,""r"":20}","{""detection_events"":571719}" + 120513, 612, 0, 1.00,chromobius,23ccd15f2df0c2e5b6d9e35d8386fa33b2165323c302a1324100a006e0e5cb60,"{""c"":""superdense_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0003,""q"":37,""r"":20}","{""detection_events"":557524}" + 71706, 803, 0, 1.00,chromobius,7d1aead4f9cb353ac03efe0b668d5c2be54427eabf7313eb6bbb54461b7939bf,"{""c"":""superdense_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0005,""q"":37,""r"":20}","{""detection_events"":543740}" + 49635, 1020, 0, 1.00,chromobius,ac252f19061b58f67596ad3c4f05e29651c47cce3430453c8edf4dbd8fc43467,"{""c"":""superdense_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0007,""q"":37,""r"":20}","{""detection_events"":526587}" + 33697, 1255, 0, 1.00,chromobius,2c0cddf830412f753375e28d1e4820fc90968bfaaff1328a891087232a076cbc,"{""c"":""superdense_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.001,""q"":37,""r"":20}","{""detection_events"":506693}" + 16086, 2155, 0, 1.03,chromobius,e9b1cf296cfb4be32baf3ecedcff5f1d4c812edf546db53b466f8e4323e118e8,"{""c"":""superdense_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.002,""q"":37,""r"":20}","{""detection_events"":461119}" + 10020, 2566, 0, 1.01,chromobius,40ac7974db81f9437ffe34ebb8d9530df5737d3171d58f06f2e1adae6c45fad6,"{""c"":""superdense_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.003,""q"":37,""r"":20}","{""detection_events"":412316}" + 5730, 2567, 0, 1.02,chromobius,aff49acbde36de58ff03112222c0a5e8d9003e501f4812c5de0a959447b8ffb9,"{""c"":""superdense_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.005,""q"":37,""r"":20}","{""detection_events"":362318}" + 4096, 1995, 0, 1.07,chromobius,4713e2a2be1a25d2188fea1e8b0b623488faf7739fab6bde10b7e97e937f12db,"{""c"":""superdense_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.007,""q"":37,""r"":20}","{""detection_events"":332445}" + 3028, 1503, 0, 1.12,chromobius,b6195b8c546537843e180637a01369be50333d689798e606e651e9cb77e423e7,"{""c"":""superdense_color_code_X"",""d"":5,""noise"":""uniform"",""p"":0.01,""q"":37,""r"":20}","{""detection_events"":314628}" + 126197, 1, 0, 1.00,chromobius,1f225e67c9ecdfdef9b8d6bf086c861ea59ee23b376a60e03a67130ed37df7c8,"{""c"":""superdense_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0001,""q"":73,""r"":28}","{""detection_events"":577531}" + 62767, 8, 0, 1.00,chromobius,9ea6e6d659ce7cb2c7185271a5515ff9e69d3fa83b34c81e612daa79ed03e361,"{""c"":""superdense_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0002,""q"":73,""r"":28}","{""detection_events"":567851}" + 42404, 8, 0, 1.00,chromobius,7b153f0a06ad2daeb9a6b2f8e96fe65b79bc44db99d2c110cc09ce8e7d4b969f,"{""c"":""superdense_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0003,""q"":73,""r"":28}","{""detection_events"":572480}" + 24545, 30, 0, 1.01,chromobius,9f2e517e23956e6cae4ebe0c81404e813a9abc2668bf0f189f9cccb943fdfb9e,"{""c"":""superdense_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0005,""q"":73,""r"":28}","{""detection_events"":548896}" + 16829, 73, 0, 1.00,chromobius,09465bb6986b877025237bc2f757713386037b6c1498fac4e8ebc0d49e9c5a66,"{""c"":""superdense_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0007,""q"":73,""r"":28}","{""detection_events"":519902}" + 11552, 148, 0, 1.03,chromobius,6f2a12e85c2f665e7dbb0a41da7f261e8ad2bb0503d0ba7351413c6174fdbdf9,"{""c"":""superdense_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.001,""q"":73,""r"":28}","{""detection_events"":506750}" + 5072, 428, 0, 1.02,chromobius,2f36d56c1c2c6badb2b743625adefaab0a85c75e0c3ffbc83f855b22e3fb4d04,"{""c"":""superdense_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.002,""q"":73,""r"":28}","{""detection_events"":423852}" + 3300, 802, 0, 1.09,chromobius,86b08e115196e7dd0c0830981449338d3b0d2179076f22f11781eee4cb2bc8a9,"{""c"":""superdense_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.003,""q"":73,""r"":28}","{""detection_events"":396879}" + 1692, 789, 0, 1.09,chromobius,3201309176d9d7b24540643a7ec42c1fac0fde6de44c70657918e87c072393be,"{""c"":""superdense_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.005,""q"":73,""r"":28}","{""detection_events"":309985}" + 1100, 543, 0, 1.12,chromobius,8f1a54461265e4bde3261a8e505a4db280c74d4c6dc3b9ef30742d6d5b1720fc,"{""c"":""superdense_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.007,""q"":73,""r"":28}","{""detection_events"":259259}" + 700, 366, 0, 1.10,chromobius,70728c7c854c4e827a2e5ae7919a27197d47a5edbce7dc5a36dde007843dc7dd,"{""c"":""superdense_color_code_X"",""d"":7,""noise"":""uniform"",""p"":0.01,""q"":73,""r"":28}","{""detection_events"":210230}" + 55473, 0, 0, 1.00,chromobius,5f960454464cb6c09b20a4bafee45a1098107f5104445a6be15cab2179663ea8,"{""c"":""superdense_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0001,""q"":121,""r"":36}","{""detection_events"":554762}" + 27031, 0, 0, 1.01,chromobius,177de51ecf83b7d6c2d978c20870dc52f20695369e457ec1b31f9a786d93b64e,"{""c"":""superdense_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0002,""q"":121,""r"":36}","{""detection_events"":538217}" + 18308, 0, 0, 1.01,chromobius,c89561c82dca54b18405214059d7f05c7aa81f70b691e3a1c5587f33e8dcc670,"{""c"":""superdense_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0003,""q"":121,""r"":36}","{""detection_events"":544717}" + 10609, 3, 0, 1.03,chromobius,992eeb509d2bd10a85d31fa683953d268bed3a0fdf11691e345472011891f2f6,"{""c"":""superdense_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0005,""q"":121,""r"":36}","{""detection_events"":523011}" + 7590, 12, 0, 1.05,chromobius,402f5f1e747f3eac8a7e7e24663a4b9dd4170d6ee1647d4936d57193f6225501,"{""c"":""superdense_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0007,""q"":121,""r"":36}","{""detection_events"":519191}" + 4933, 24, 0, 1.01,chromobius,144434321585e2ef47fd83952e19299897e10d07a284c5a2f251b8be515e3f92,"{""c"":""superdense_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.001,""q"":121,""r"":36}","{""detection_events"":477654}" + 2273, 137, 0, 1.08,chromobius,e04cbba50c85f7618841834684fc14d12a2e381f0dde582b3244ceff8b2be4bd,"{""c"":""superdense_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.002,""q"":121,""r"":36}","{""detection_events"":417185}" + 1331, 309, 0, 1.10,chromobius,401c5cd1895a91f603d9de345973eb02fdd329610dfb830aaa3d4d3a0ebce3c4,"{""c"":""superdense_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.003,""q"":121,""r"":36}","{""detection_events"":351313}" + 621, 305, 0, 1.12,chromobius,5ffad3ff2975f299592bc73f7ac3254a08215b7214d11fe91b6c1f1cd1f4a7fd,"{""c"":""superdense_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.005,""q"":121,""r"":36}","{""detection_events"":248256}" + 343, 183, 0, 1.05,chromobius,c97052a8ac32d6e7e60fc6de46cd16ffe4bddc435992553d15d96699d5635508,"{""c"":""superdense_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.007,""q"":121,""r"":36}","{""detection_events"":176016}" + 224, 99, 0, 1.13,chromobius,47703cf5a405323edbc3929ba90d359510070ffcf99741411ecf9ed74cd02673,"{""c"":""superdense_color_code_X"",""d"":9,""noise"":""uniform"",""p"":0.01,""q"":121,""r"":36}","{""detection_events"":147481}" + 25938, 0, 0, 1.00,chromobius,fc69f287d689cf8753e47773e351a3fa4cdfeb88de8ed1f8fb01d722192d9130,"{""c"":""superdense_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0001,""q"":181,""r"":44}","{""detection_events"":485374}" + 13231, 0, 0, 1.01,chromobius,dfd4617137b9d70669a477045ff15b2da59f8f8dda12b3e7c70824f6b87145a8,"{""c"":""superdense_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0002,""q"":181,""r"":44}","{""detection_events"":492049}" + 9106, 0, 0, 1.01,chromobius,86e9c378bde0847f9f212ef715f6656d92926eacbbe43783e79fca7e33ab40b4,"{""c"":""superdense_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0003,""q"":181,""r"":44}","{""detection_events"":505043}" + 5025, 1, 0, 1.02,chromobius,ca31b3260e8316a49e723463d1ea63f7d248c5886e482b73b88ddb3e3e526b85,"{""c"":""superdense_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0005,""q"":181,""r"":44}","{""detection_events"":462716}" + 3968, 1, 0, 1.10,chromobius,de823e8f05cfeaaa54f0601db35ef2de851c1d55762c6cd573f5a34a95e6c202,"{""c"":""superdense_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0007,""q"":181,""r"":44}","{""detection_events"":504878}" + 2756, 4, 0, 1.13,chromobius,ee62ffbed83ba27ab5d95f0c17fa38ae0272b71f4b14c313132accc7594cd3e5,"{""c"":""superdense_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.001,""q"":181,""r"":44}","{""detection_events"":493627}" + 1143, 55, 0, 1.09,chromobius,78d5bc21c1e97b946b24adfd335040561334717f9175ed73c6ccb6e1146c1f46,"{""c"":""superdense_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.002,""q"":181,""r"":44}","{""detection_events"":389463}" + 643, 143, 0, 1.11,chromobius,7153bc706621d69ef32622219c4be23084a886014512e7512d06aafd286b3567,"{""c"":""superdense_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.003,""q"":181,""r"":44}","{""detection_events"":315994}" + 252, 126, 0, 1.05,chromobius,8d51fc72ca6fd599962d53cc691392fbea593042bdb8c51d4b3b8333b3788b4a,"{""c"":""superdense_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.005,""q"":181,""r"":44}","{""detection_events"":187725}" + 143, 69, 0, 1.21,chromobius,e537c9e83d3c28a5754677ef821f8785e0a8f21198bbf23373fbfce58945eeaf,"{""c"":""superdense_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.007,""q"":181,""r"":44}","{""detection_events"":137319}" + 74, 43, 0, 1.01,chromobius,6e1b81b38e5f079100a4ac9bdd67dc5efebb11ef1db8e6843f1b7f6a9f2fe980,"{""c"":""superdense_color_code_X"",""d"":11,""noise"":""uniform"",""p"":0.01,""q"":181,""r"":44}","{""detection_events"":90252}" + 14802, 0, 0, 1.03,chromobius,66e7c2a0ea010b26542be3ecf767e987e91f0673af8389f678e00905b8f64e47,"{""c"":""superdense_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0001,""q"":253,""r"":52}","{""detection_events"":460866}" + 7641, 0, 0, 1.05,chromobius,b28b5041a32bf45e2faf8ca36ec399077db3214cd9a2e889ad37140ceebb7cb8,"{""c"":""superdense_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0002,""q"":253,""r"":52}","{""detection_events"":475651}" + 4765, 0, 0, 1.02,chromobius,245fa6ace58d4b1a9540b8cffb3cc1f6fa7449ee62a822e209af35dabb4da520,"{""c"":""superdense_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0003,""q"":253,""r"":52}","{""detection_events"":442912}" + 2922, 0, 0, 1.02,chromobius,9aa759b2994dd9200a55b600d80c1b430c72bba7bc0160e95005a653eea34a9c,"{""c"":""superdense_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0005,""q"":253,""r"":52}","{""detection_events"":447543}" + 1951, 0, 0, 1.04,chromobius,cb77ec77833753d108aac23b11c57c7455175798fe590f7cd1d312adafa714a1,"{""c"":""superdense_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0007,""q"":253,""r"":52}","{""detection_events"":415323}" + 1442, 1, 0, 1.12,chromobius,a81e0cdb391058429bed6d2b07ff93da65f5cebec061d62f4fae1fbaf4eda9d0,"{""c"":""superdense_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.001,""q"":253,""r"":52}","{""detection_events"":433425}" + 639, 15, 0, 1.07,chromobius,039f482a3b16b9b224d64871650acdf86c0fde98f3efde2ec7f69775311bf422,"{""c"":""superdense_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.002,""q"":253,""r"":52}","{""detection_events"":365756}" + 319, 86, 0, 1.03,chromobius,81e56909088058417a95449567d6c643ff553941e6d1d7d605ea8e07aa0b1088,"{""c"":""superdense_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.003,""q"":253,""r"":52}","{""detection_events"":262446}" + 105, 55, 0, 1.12,chromobius,f5d304744a6beb160eddb7d4da594ec5a6f1d7d753295e83c75d5408253db8bb,"{""c"":""superdense_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.005,""q"":253,""r"":52}","{""detection_events"":131258}" + 43, 15, 0, 1.13,chromobius,2c0798980361f08590cec682bf2598f9c25acf00de1df5ba5e07f4ab358892a4,"{""c"":""superdense_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.007,""q"":253,""r"":52}","{""detection_events"":69972}" + 30, 17, 0, 1.06,chromobius,b58c661b1fc2f66d053943a1343daa0e94d93290f96a5313db9358f4d17a612c,"{""c"":""superdense_color_code_X"",""d"":13,""noise"":""uniform"",""p"":0.01,""q"":253,""r"":52}","{""detection_events"":60182}" + 13687761, 41933, 0, 1.00,pymatching,40d157c1e7c7f1adb3aadad59110c7455cb251b41ea41b42487de1fc9972077f,"{""c"":""surface_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0001,""q"":17,""r"":12}","{""detection_events"":2318366}" + 8991362, 55745, 0, 1.00,pymatching,64d17376dbbdb2ce75fba4ca6baa646efb258a2acbfecf703d3116f73bad9f2f,"{""c"":""surface_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0002,""q"":17,""r"":12}","{""detection_events"":3043347}" + 6758178, 62725, 0, 1.00,pymatching,d5e26bc01074af0672b2927419e3beb02b241c3592aa35ace97ef6ac8193a41a,"{""c"":""surface_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0003,""q"":17,""r"":12}","{""detection_events"":3416604}" + 4318238, 67776, 0, 1.00,pymatching,23e2eeff9d6aab182144840095ec43510fb088574dfce7f4680f751b091b1e59,"{""c"":""surface_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0005,""q"":17,""r"":12}","{""detection_events"":3625125}" + 3201829, 71740, 0, 1.00,pymatching,f35e78adca6f4f9a02eac49d8c3f4e194a85d6517ebf7fa1062d3eece7e3cf04,"{""c"":""surface_code_X"",""d"":3,""noise"":""uniform"",""p"":0.0007,""q"":17,""r"":12}","{""detection_events"":3748727}" + 2240960, 73807, 0, 1.00,pymatching,8a1d00914c8fa16a6782b501484ad1f6492e2c43fcd558f259197c2a2e027b69,"{""c"":""surface_code_X"",""d"":3,""noise"":""uniform"",""p"":0.001,""q"":17,""r"":12}","{""detection_events"":3734364}" + 1081679, 74992, 0, 1.00,pymatching,983acea7659d8cb0d81fc364d9f4e98338cf570d824a66c0bfd884635fddb37d,"{""c"":""surface_code_X"",""d"":3,""noise"":""uniform"",""p"":0.002,""q"":17,""r"":12}","{""detection_events"":3539532}" + 685669, 74322, 0, 1.00,pymatching,6255c7f94a61c010450583dd94f6bb381bddfb89cad610d9d27b4407226bb867,"{""c"":""surface_code_X"",""d"":3,""noise"":""uniform"",""p"":0.003,""q"":17,""r"":12}","{""detection_events"":3309713}" + 383891, 71774, 0, 1.00,pymatching,26b8479fcdf7f671b43d72e4ff9d68d1380cd66bd5a785661cacd3e289ee7664,"{""c"":""surface_code_X"",""d"":3,""noise"":""uniform"",""p"":0.005,""q"":17,""r"":12}","{""detection_events"":2983216}" + 262144, 68556, 0, 1.00,pymatching,ff329d6d19e008ed632e2b53beec9a8fe6f61f8e86f4a82d6489cce804aaec3e,"{""c"":""surface_code_X"",""d"":3,""noise"":""uniform"",""p"":0.007,""q"":17,""r"":12}","{""detection_events"":2756960}" + 175823, 62378, 0, 1.00,pymatching,afd06feae61f6b6cc8d09ac0674a55bd226769fe3570d83fb9b9d4436a99c4c0,"{""c"":""surface_code_X"",""d"":3,""noise"":""uniform"",""p"":0.01,""q"":17,""r"":12}","{""detection_events"":2508739}" + 3379935, 32, 0, 1.00,pymatching,6317333f509080327b532f74394ef1ef6a29fff34e684bfaaf8a2a5b00eef50c,"{""c"":""surface_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0001,""q"":49,""r"":20}","{""detection_events"":3047247}" + 2009743, 85, 0, 1.00,pymatching,6622bc4335bcc3b13b5393fd28b085aabcdac5f5b7b90704effa26b29a315bbc,"{""c"":""surface_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0002,""q"":49,""r"":20}","{""detection_events"":3613451}" + 1442015, 189, 0, 1.00,pymatching,d2792cab631cd991dab67a5bd1809514c42a66ea9d4b9efefc04faea79164a60,"{""c"":""surface_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0003,""q"":49,""r"":20}","{""detection_events"":3878955}" + 887981, 350, 0, 1.00,pymatching,e0b7b83cb21fbabdb350a6756f2275d63e3aa0ac9e045b89539d66347da22d3d,"{""c"":""surface_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0005,""q"":49,""r"":20}","{""detection_events"":3964377}" + 634581, 620, 0, 1.00,pymatching,02d031a6d70061cc21bdfe7c8225c1da77674ebf4747e7a48ef2289797744203,"{""c"":""surface_code_X"",""d"":5,""noise"":""uniform"",""p"":0.0007,""q"":49,""r"":20}","{""detection_events"":3954271}" + 431041, 916, 0, 1.00,pymatching,965703c642705ab4cf852e22266f2d730b0b1226e92041ab572c4f028428377a,"{""c"":""surface_code_X"",""d"":5,""noise"":""uniform"",""p"":0.001,""q"":49,""r"":20}","{""detection_events"":3816338}" + 195966, 2727, 0, 1.00,pymatching,bd41201c42622e1768fc6a7dc120f3b335974c94f1a2c65f52d47d2437421926,"{""c"":""surface_code_X"",""d"":5,""noise"":""uniform"",""p"":0.002,""q"":49,""r"":20}","{""detection_events"":3407435}" + 117613, 4522, 0, 1.00,pymatching,8b13ccaf5d66dffac0c3f0538b2efba4a3aa66e4a77f456d8b9e7031bf8d0426,"{""c"":""surface_code_X"",""d"":5,""noise"":""uniform"",""p"":0.003,""q"":49,""r"":20}","{""detection_events"":3014582}" + 61431, 7944, 0, 1.01,pymatching,48689a0e09a6d76c8945bb6a30796434344caa72ff49239a1dde2d65a4a89917,"{""c"":""surface_code_X"",""d"":5,""noise"":""uniform"",""p"":0.005,""q"":49,""r"":20}","{""detection_events"":2527733}" + 39981, 10137, 0, 1.00,pymatching,3bd82eac0eb5b8578d3991b3a3fcc36100edb3672c96ec9e1e2f02f2afd6659e,"{""c"":""surface_code_X"",""d"":5,""noise"":""uniform"",""p"":0.007,""q"":49,""r"":20}","{""detection_events"":2222064}" + 24976, 10036, 0, 1.00,pymatching,81467af4142afbed871cd9aebd404586907df0330edd96c41d72b32e5e9bd72e,"{""c"":""surface_code_X"",""d"":5,""noise"":""uniform"",""p"":0.01,""q"":49,""r"":20}","{""detection_events"":1880391}" + 1240163, 0, 0, 1.00,pymatching,f97ca4d46ef4b641e43eab833faea1b8597cb26bac6d892c354d224133adec7d,"{""c"":""surface_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0001,""q"":97,""r"":28}","{""detection_events"":3224449}" + 741376, 0, 0, 1.00,pymatching,762bbb6aa3a58bd815e93a7a4137257929f7a4e51de67bd27dd8c0bbb7c53527,"{""c"":""surface_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0002,""q"":97,""r"":28}","{""detection_events"":3839375}" + 523196, 2, 0, 1.00,pymatching,2c87e46e237b990251f452e28f6af25747399de152377a87127cf4cd03d325a4,"{""c"":""surface_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0003,""q"":97,""r"":28}","{""detection_events"":4060843}" + 315664, 3, 0, 1.00,pymatching,67daaab79a5eb44d1857559c57e7e8db803df431a6ffd40083150a254adef9e2,"{""c"":""surface_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0005,""q"":97,""r"":28}","{""detection_events"":4067944}" + 221308, 14, 0, 1.00,pymatching,937ab4bcc7c0dc1b16d13454560fa78d4a27d91cb5330a6fc5606ea5d33acd2b,"{""c"":""surface_code_X"",""d"":7,""noise"":""uniform"",""p"":0.0007,""q"":97,""r"":28}","{""detection_events"":3980117}" + 153999, 46, 0, 1.00,pymatching,3c0dc70b5cd6114700281dce13a50db78966c1f676fb2650b73cc1da99c0a800,"{""c"":""surface_code_X"",""d"":7,""noise"":""uniform"",""p"":0.001,""q"":97,""r"":28}","{""detection_events"":3927426}" + 67675, 285, 0, 1.00,pymatching,eb1016ca182c0973dd2e27368fa3c8745da588f001fa9f042f24f19b82c78f0e,"{""c"":""surface_code_X"",""d"":7,""noise"":""uniform"",""p"":0.002,""q"":97,""r"":28}","{""detection_events"":3395370}" + 40240, 729, 0, 1.01,pymatching,bd39353a374a702e909e50a9de3b7049cf425f76b1c8a52f43054af9b48cc454,"{""c"":""surface_code_X"",""d"":7,""noise"":""uniform"",""p"":0.003,""q"":97,""r"":28}","{""detection_events"":2971271}" + 19569, 2089, 0, 1.02,pymatching,aaa7a328ae4b0a349ce79e44eadf2edb0c5d11ba26a2b836cadb1dc3227e076d,"{""c"":""surface_code_X"",""d"":7,""noise"":""uniform"",""p"":0.005,""q"":97,""r"":28}","{""detection_events"":2317217}" + 11878, 3135, 0, 1.03,pymatching,3fabbaeb4e6eeeead0ca066fe46a5e549b83e80e4f95ce175645386da51f00bc,"{""c"":""surface_code_X"",""d"":7,""noise"":""uniform"",""p"":0.007,""q"":97,""r"":28}","{""detection_events"":1900319}" + 7245, 3212, 0, 1.04,pymatching,5fe17b970cb0bb2d8f59ff6a7e54cd343e75c726015b56d4c5d4642c321a8f70,"{""c"":""surface_code_X"",""d"":7,""noise"":""uniform"",""p"":0.01,""q"":97,""r"":28}","{""detection_events"":1567755}" + 576438, 0, 0, 1.00,pymatching,068cabd14fb42635de3d9d5ecea6ebd749508279aa3bd5c456c1213d67252a62,"{""c"":""surface_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0001,""q"":161,""r"":36}","{""detection_events"":3266040}" + 339820, 0, 0, 1.00,pymatching,1e9f4fd3bf83270c35ad450ffd6748b46a2d6a78f511754ee6714b93fc5cfd72,"{""c"":""surface_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0002,""q"":161,""r"":36}","{""detection_events"":3843768}" + 237842, 0, 0, 1.00,pymatching,476ed894ef84ffd370a51d6d318048f4dfdd3ed7bf05a82530b8ef8eef76d1ae,"{""c"":""surface_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0003,""q"":161,""r"":36}","{""detection_events"":4032355}" + 144151, 0, 0, 1.00,pymatching,7f7c2f2d07858e398136ce84462b711f486e57a772a82d7753d5b75ee783b38d,"{""c"":""surface_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0005,""q"":161,""r"":36}","{""detection_events"":4054925}" + 104773, 0, 0, 1.00,pymatching,135a27c5b1d39d06aa71c552a0405063bfc12a4f0ae23da4b2938e605b2adaec,"{""c"":""surface_code_X"",""d"":9,""noise"":""uniform"",""p"":0.0007,""q"":161,""r"":36}","{""detection_events"":4105292}" + 70141, 1, 0, 1.00,pymatching,bb8dfb7990f2b087335d14353ea867187e7266937d47ecce49b95d6f220a2d26,"{""c"":""surface_code_X"",""d"":9,""noise"":""uniform"",""p"":0.001,""q"":161,""r"":36}","{""detection_events"":3905391}" + 31254, 40, 0, 1.01,pymatching,4dae9cd03fa5d0714b23fb663bc9963ac623030940287afceb6cf7d4a30350ce,"{""c"":""surface_code_X"",""d"":9,""noise"":""uniform"",""p"":0.002,""q"":161,""r"":36}","{""detection_events"":3417701}" + 17970, 161, 0, 1.01,pymatching,fb958b9295e4d23b5ccf9ae220b9022d15667f89ddf4074217c2a62b0709a7c8,"{""c"":""surface_code_X"",""d"":9,""noise"":""uniform"",""p"":0.003,""q"":161,""r"":36}","{""detection_events"":2886883}" + 8192, 763, 0, 1.02,pymatching,161f5e711b1f5178892c401e864b31595619b6331602fa81a4b1b267b328a760,"{""c"":""surface_code_X"",""d"":9,""noise"":""uniform"",""p"":0.005,""q"":161,""r"":36}","{""detection_events"":2114655}" + 4715, 1276, 0, 1.01,pymatching,816be8690eb51e101ee969d1ff391373658dec035364761080033b124ee601ca,"{""c"":""surface_code_X"",""d"":9,""noise"":""uniform"",""p"":0.007,""q"":161,""r"":36}","{""detection_events"":1640876}" + 2914, 1392, 0, 1.11,pymatching,fedd55897c0ac815fe78df93079e8f32f637f34ad34aa28e12946c9a98c367bf,"{""c"":""surface_code_X"",""d"":9,""noise"":""uniform"",""p"":0.01,""q"":161,""r"":36}","{""detection_events"":1368157}" + 311116, 0, 0, 1.00,pymatching,b5105a003222706d61ee71b6bdb571bafcdef75e9b5ea2d4f161418ff09e05e3,"{""c"":""surface_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0001,""q"":241,""r"":44}","{""detection_events"":3267390}" + 182737, 0, 0, 1.00,pymatching,fbac57643154c44ea18ed770fd0443ddab4e252d1915f48a6caaac5eb5028cad,"{""c"":""surface_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0002,""q"":241,""r"":44}","{""detection_events"":3832772}" + 129061, 0, 0, 1.00,pymatching,30ed4bc5e58dd54b793eff2cf8e29184fdb6ab41c9084e7111f8bb9e4a70bd86,"{""c"":""surface_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0003,""q"":241,""r"":44}","{""detection_events"":4052845}" + 77623, 0, 0, 1.00,pymatching,1df9ca265d8c35d72290952511deff3996646abdc2047232caece106184e4d49,"{""c"":""surface_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0005,""q"":241,""r"":44}","{""detection_events"":4045120}" + 56213, 0, 0, 1.01,pymatching,79f77e55da130359c010dfa3a39c86267d4fd483c4b15bd029cbf4b47f64824e,"{""c"":""surface_code_X"",""d"":11,""noise"":""uniform"",""p"":0.0007,""q"":241,""r"":44}","{""detection_events"":4084624}" + 38180, 0, 0, 1.00,pymatching,49056b09c531c9f6588e5e07c50142e286a8335ac99ea65466310d1130cd7f05,"{""c"":""surface_code_X"",""d"":11,""noise"":""uniform"",""p"":0.001,""q"":241,""r"":44}","{""detection_events"":3939783}" + 16384, 5, 0, 1.02,pymatching,e6d89c4df3a1e1d21cb7870178197c0aaeed1346528068b1c6d7ead34c47f464,"{""c"":""surface_code_X"",""d"":11,""noise"":""uniform"",""p"":0.002,""q"":241,""r"":44}","{""detection_events"":3319228}" + 9189, 36, 0, 1.01,pymatching,7d20892d20da9e3c66225778c2851301142a9940e006ca49de02845848865dfb,"{""c"":""surface_code_X"",""d"":11,""noise"":""uniform"",""p"":0.003,""q"":241,""r"":44}","{""detection_events"":2741807}" + 4096, 260, 0, 1.04,pymatching,ccb72714330d46f9530ac18438715973f6ed2f33ec83bfb03cf16afc8cd2ae3d,"{""c"":""surface_code_X"",""d"":11,""noise"":""uniform"",""p"":0.005,""q"":241,""r"":44}","{""detection_events"":1956350}" + 2371, 647, 0, 1.09,pymatching,e883a41ae3eef4270c763b8f249b75db90e0424bef4e338ed803a8542254245a,"{""c"":""surface_code_X"",""d"":11,""noise"":""uniform"",""p"":0.007,""q"":241,""r"":44}","{""detection_events"":1529641}" + 1336, 639, 0, 1.09,pymatching,ab484974c28db3cd30edd76ef456d6457aff046aae963a2fc72ca525d9efe87a,"{""c"":""surface_code_X"",""d"":11,""noise"":""uniform"",""p"":0.01,""q"":241,""r"":44}","{""detection_events"":1158662}" + 179832, 0, 0, 1.00,pymatching,f98e034814fc3e3737496099a7c191af4299691fc9e2883f8963f0d63b3dc0be,"{""c"":""surface_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0001,""q"":337,""r"":52}","{""detection_events"":3152593}" + 106199, 0, 0, 1.01,pymatching,6aa537a42b7247cbd613a8f768f095daf830825c99b6458823a0913612d75a62,"{""c"":""surface_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0002,""q"":337,""r"":52}","{""detection_events"":3715821}" + 76474, 0, 0, 1.00,pymatching,3d51c749ea1ccaaab218e9b483bdeb4e89b4ae24252cdde31eb15c12c02d6012,"{""c"":""surface_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0003,""q"":337,""r"":52}","{""detection_events"":4001382}" + 46273, 0, 0, 1.00,pymatching,c8b6f49f81e1cb17781faf22c9a156bd51120b8c9cfb56cbc1f6e25656ded92d,"{""c"":""surface_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0005,""q"":337,""r"":52}","{""detection_events"":4029835}" + 32768, 0, 0, 1.00,pymatching,0afedfc7296da1b267f4d97eb5c4e54254d1c79ed2338e29efd50211020213bb,"{""c"":""surface_code_X"",""d"":13,""noise"":""uniform"",""p"":0.0007,""q"":337,""r"":52}","{""detection_events"":3968301}" + 22383, 0, 0, 1.01,pymatching,21ff12a19419695061f67202b70da647b1b872a7ad8907f12f97f434c0234c9c,"{""c"":""surface_code_X"",""d"":13,""noise"":""uniform"",""p"":0.001,""q"":337,""r"":52}","{""detection_events"":3854910}" + 9167, 1, 0, 1.01,pymatching,848059f6318e06ead6a83618df347abd17873b9954d6dc8d7702c29d96d6c51d,"{""c"":""surface_code_X"",""d"":13,""noise"":""uniform"",""p"":0.002,""q"":337,""r"":52}","{""detection_events"":3097272}" + 5232, 12, 0, 1.02,pymatching,fae2adaedac14df484377776fd8448fe972a1adabd57b155e225d23e65d7302b,"{""c"":""surface_code_X"",""d"":13,""noise"":""uniform"",""p"":0.003,""q"":337,""r"":52}","{""detection_events"":2599187}" + 2394, 127, 0, 1.09,pymatching,e9152d58e76e760ea397aba670fb87b0248ffe442f08d4f644e52ec6eb177d61,"{""c"":""surface_code_X"",""d"":13,""noise"":""uniform"",""p"":0.005,""q"":337,""r"":52}","{""detection_events"":1909474}" + 1342, 380, 0, 1.12,pymatching,e56a01a1b5d6cfc88b1b78655a5df3cf76045a2854735a512c81886e2e59fb33,"{""c"":""surface_code_X"",""d"":13,""noise"":""uniform"",""p"":0.007,""q"":337,""r"":52}","{""detection_events"":1439070}" + 696, 353, 0, 1.07,pymatching,2fbbc8739c52fa63beb45346161eb239e325a27b45ae49b07ef30ffed026f1d7,"{""c"":""surface_code_X"",""d"":13,""noise"":""uniform"",""p"":0.01,""q"":337,""r"":52}","{""detection_events"":1006690}" + 37434264, 3, 0, 1.00,chromobius,8f74deac0352a709ba738248cf86250c59f5ce941b1b61a9531b1d92a8fccfe9,"{""c"":""transit_color_code"",""d"":3,""noise"":""uniform"",""p"":0.0001,""q"":8,""r"":1}","{""detection_events"":59493}" + 35703087, 30, 0, 1.00,chromobius,1100d69938dc2b6cc1758f83397c3962422aa8420e0ee3cf090e27b76375b306,"{""c"":""transit_color_code"",""d"":3,""noise"":""uniform"",""p"":0.0002,""q"":8,""r"":1}","{""detection_events"":113859}" + 34081765, 47, 0, 1.00,chromobius,10b83aeeca1ceefc3ec80b66167d09982e4df66ae59876bc9d0d67972980939e,"{""c"":""transit_color_code"",""d"":3,""noise"":""uniform"",""p"":0.0003,""q"":8,""r"":1}","{""detection_events"":163423}" + 31069566, 102, 0, 1.00,chromobius,e4165dc6ff4fd76ecdf0a01d2ab0edbbd74a53be44d3e3605186e03fde98749a,"{""c"":""transit_color_code"",""d"":3,""noise"":""uniform"",""p"":0.0005,""q"":8,""r"":1}","{""detection_events"":246969}" + 29125514, 236, 0, 1.00,chromobius,4ef4d26627d96a1f0c3635d88586bfaf6b40b6b110a1b9723b4aa85160acea4a,"{""c"":""transit_color_code"",""d"":3,""noise"":""uniform"",""p"":0.0007,""q"":8,""r"":1}","{""detection_events"":323859}" + 26585826, 421, 0, 1.00,chromobius,9f2b617ba16bc2e1e0b713ca5131833df5862ab043e4d5c2c33a859d0e59972c,"{""c"":""transit_color_code"",""d"":3,""noise"":""uniform"",""p"":0.001,""q"":8,""r"":1}","{""detection_events"":426283}" + 20227496, 1342, 0, 1.00,chromobius,149fd4fc080266e90d7565ce95cf74944f0f50f97a807bb747e5911023eede3a,"{""c"":""transit_color_code"",""d"":3,""noise"":""uniform"",""p"":0.002,""q"":8,""r"":1}","{""detection_events"":646930}" + 16485016, 2444, 0, 1.00,chromobius,aea1289e949b6f00a4ef2f1cde69708855e750bd565aa771f837ba3445608f77,"{""c"":""transit_color_code"",""d"":3,""noise"":""uniform"",""p"":0.003,""q"":8,""r"":1}","{""detection_events"":788470}" + 11858223, 4699, 0, 1.00,chromobius,b9b0177948aa53cf45aba6533d78200efb65392cbc9d7eb70c6ca57834701363,"{""c"":""transit_color_code"",""d"":3,""noise"":""uniform"",""p"":0.005,""q"":8,""r"":1}","{""detection_events"":940318}" + 9414262, 7332, 0, 1.00,chromobius,eb72143ddfeb186cc1cc7a283b7f17aff59ff2bf0eb994976e852128db36ac59,"{""c"":""transit_color_code"",""d"":3,""noise"":""uniform"",""p"":0.007,""q"":8,""r"":1}","{""detection_events"":1040771}" + 7074299, 11230, 0, 1.00,chromobius,0d2c7f919c0be3fbda46f969d4945a189aa55e40598fdfe34e5384f9aaa3385d,"{""c"":""transit_color_code"",""d"":3,""noise"":""uniform"",""p"":0.01,""q"":8,""r"":1}","{""detection_events"":1108296}" + 31472904, 0, 0, 1.00,chromobius,2826f8fee2f4078741f2aa8ac89d149e5be4ab05697063d050dc066d3cd851a7,"{""c"":""transit_color_code"",""d"":5,""noise"":""uniform"",""p"":0.0001,""q"":20,""r"":1}","{""detection_events"":176792}" + 27623089, 0, 0, 1.00,chromobius,be5e594b35c751dd3f6831ed45ba362d9efc57ea2e777bf370113dc74460fb2d,"{""c"":""transit_color_code"",""d"":5,""noise"":""uniform"",""p"":0.0002,""q"":20,""r"":1}","{""detection_events"":309756}" + 24462140, 2, 0, 1.00,chromobius,604f2fb5d86b867cd22c74e2836fbd0e761e16a35adc3c1d2e74899b4efba7b6,"{""c"":""transit_color_code"",""d"":5,""noise"":""uniform"",""p"":0.0003,""q"":20,""r"":1}","{""detection_events"":409874}" + 20796818, 1, 0, 1.00,chromobius,61e46ded31250c63f16decee2feea63647f98429e56e8a9d27726bb6a2c1f0b8,"{""c"":""transit_color_code"",""d"":5,""noise"":""uniform"",""p"":0.0005,""q"":20,""r"":1}","{""detection_events"":581238}" + 17956611, 0, 0, 1.00,chromobius,68aacb434c5002eadba89b0b22ad06673ea508672300eefe7d800f6331b51e8c,"{""c"":""transit_color_code"",""d"":5,""noise"":""uniform"",""p"":0.0007,""q"":20,""r"":1}","{""detection_events"":700266}" + 14999114, 2, 0, 1.00,chromobius,aa553cbe4fdab5a6c3f935d65c2eefba73da8e7fba846a646f5486f6ae14e8c9,"{""c"":""transit_color_code"",""d"":5,""noise"":""uniform"",""p"":0.001,""q"":20,""r"":1}","{""detection_events"":837557}" + 9668522, 20, 0, 1.00,chromobius,1a71a1182e0283de55bec90ce72efef18c89a5e99409390edf9d0b8dea3fb27c,"{""c"":""transit_color_code"",""d"":5,""noise"":""uniform"",""p"":0.002,""q"":20,""r"":1}","{""detection_events"":1074665}" + 7030135, 35, 0, 1.00,chromobius,a397d82e6c4282aee2ef738982c7bde235101e6b6a34b357864171b8a219230e,"{""c"":""transit_color_code"",""d"":5,""noise"":""uniform"",""p"":0.003,""q"":20,""r"":1}","{""detection_events"":1169849}" + 4595855, 115, 0, 1.00,chromobius,1783cf358d826d56b9f58691a90cd258340b698349a9e0e196bbd314f455f7b2,"{""c"":""transit_color_code"",""d"":5,""noise"":""uniform"",""p"":0.005,""q"":20,""r"":1}","{""detection_events"":1270348}" + 3374898, 225, 0, 1.00,chromobius,9b111067337c559d37cf80f83334ee43eba86096a65205259900a64cc9a8162a,"{""c"":""transit_color_code"",""d"":5,""noise"":""uniform"",""p"":0.007,""q"":20,""r"":1}","{""detection_events"":1301456}" + 2397866, 447, 0, 1.00,chromobius,9e0f5aa551d2e22f245fb25756259186d42f13197a7d9d38f1a2c6301a18f48f,"{""c"":""transit_color_code"",""d"":5,""noise"":""uniform"",""p"":0.01,""q"":20,""r"":1}","{""detection_events"":1311436}" + 25884721, 0, 0, 1.00,chromobius,b1921dd72acbb7d1a5b8d8c96ec007c6e268f8d4a8f18dc7d26e1532cfa2aab9,"{""c"":""transit_color_code"",""d"":7,""noise"":""uniform"",""p"":0.0001,""q"":38,""r"":1}","{""detection_events"":312708}" + 20933315, 0, 0, 1.00,chromobius,38a28882d8dabda6d4e3d7d29770cedfdea18a5158e7f3eb380cf5a21406cf93,"{""c"":""transit_color_code"",""d"":7,""noise"":""uniform"",""p"":0.0002,""q"":38,""r"":1}","{""detection_events"":502971}" + 17650528, 0, 0, 1.00,chromobius,36ba15d9cfb1049e7510ee9b3d50790e6fc1d887d52ab806a82763e64f4235d2,"{""c"":""transit_color_code"",""d"":7,""noise"":""uniform"",""p"":0.0003,""q"":38,""r"":1}","{""detection_events"":634258}" + 13571927, 0, 0, 1.00,chromobius,d6fb60c61eb34ea022ba17d72e73a5a4dda64b578520f102cf0e44551d12258c,"{""c"":""transit_color_code"",""d"":7,""noise"":""uniform"",""p"":0.0005,""q"":38,""r"":1}","{""detection_events"":813377}" + 11058083, 0, 0, 1.00,chromobius,892f21eefa59ff401cf11628d1004a15b1cb43d2c5283b04f90da522843bfd9e,"{""c"":""transit_color_code"",""d"":7,""noise"":""uniform"",""p"":0.0007,""q"":38,""r"":1}","{""detection_events"":928652}" + 8718163, 0, 0, 1.00,chromobius,7c5e98e9bfeab189d93d6331109455ddc5ae9d09ee5a4726b54ff315593f309e,"{""c"":""transit_color_code"",""d"":7,""noise"":""uniform"",""p"":0.001,""q"":38,""r"":1}","{""detection_events"":1044309}" + 5145456, 2, 0, 1.00,chromobius,f588f22267366c3e13bea82b6aa377ed9105b3eb1839c1e9cadf14fb5933611a,"{""c"":""transit_color_code"",""d"":7,""noise"":""uniform"",""p"":0.002,""q"":38,""r"":1}","{""detection_events"":1226512}" + 3618430, 0, 0, 1.00,chromobius,a0de8c41d55636a91b94aa9d2ce0661a5eccf59d6172ac893e4553ebcf2e6200,"{""c"":""transit_color_code"",""d"":7,""noise"":""uniform"",""p"":0.003,""q"":38,""r"":1}","{""detection_events"":1291724}" + 2239931, 12, 0, 1.00,chromobius,627c96bfe84a58532287d29f588360b7246b51aa34d54ee81728d804132f436d,"{""c"":""transit_color_code"",""d"":7,""noise"":""uniform"",""p"":0.005,""q"":38,""r"":1}","{""detection_events"":1326555}" + 1613365, 18, 0, 1.00,chromobius,81269ecee4931f53bfa2f429230876466525be0f36cb46f5ab841edb7f3edeef,"{""c"":""transit_color_code"",""d"":7,""noise"":""uniform"",""p"":0.007,""q"":38,""r"":1}","{""detection_events"":1329023}" + 1125386, 46, 0, 1.00,chromobius,9f4cc792a8cc83b1d5f30bcc838a82754559c1a846a7f1b57412f9807f40f1fd,"{""c"":""transit_color_code"",""d"":7,""noise"":""uniform"",""p"":0.01,""q"":38,""r"":1}","{""detection_events"":1310683}" + 20778530, 0, 0, 1.00,chromobius,bb4655ded4c78bb50e40dab0a122b3d4b0fc6c00e5aa3808c3270a606d78c816,"{""c"":""transit_color_code"",""d"":9,""noise"":""uniform"",""p"":0.0001,""q"":62,""r"":1}","{""detection_events"":432104}" + 15419376, 0, 0, 1.00,chromobius,30b3d24d2963ae0eba10134c8605cac4a82b0a1584bd72913d3cd0fe485a409d,"{""c"":""transit_color_code"",""d"":9,""noise"":""uniform"",""p"":0.0002,""q"":62,""r"":1}","{""detection_events"":642953}" + 12475283, 0, 0, 1.00,chromobius,0d8b68e505077b4757f408030fed1b59901c7d2843f17a3837d2924decb00cad,"{""c"":""transit_color_code"",""d"":9,""noise"":""uniform"",""p"":0.0003,""q"":62,""r"":1}","{""detection_events"":778082}" + 9037024, 0, 0, 1.00,chromobius,4f3e168a8b1e714781e7a6a3fa000b3cd926c8a8048c880270d1a1fbdab4fb4e,"{""c"":""transit_color_code"",""d"":9,""noise"":""uniform"",""p"":0.0005,""q"":62,""r"":1}","{""detection_events"":938676}" + 7126265, 0, 0, 1.00,chromobius,5e9bbc8b94eac5e565a9b14ff8f36051daedfd7bd381dbb19834c0e2725d4d00,"{""c"":""transit_color_code"",""d"":9,""noise"":""uniform"",""p"":0.0007,""q"":62,""r"":1}","{""detection_events"":1036348}" + 5390552, 0, 0, 1.00,chromobius,6fb8746d33a9be5e098eeb768f4c885f93a57dfdb9ccc5cc56035b7a90c67ce4,"{""c"":""transit_color_code"",""d"":9,""noise"":""uniform"",""p"":0.001,""q"":62,""r"":1}","{""detection_events"":1117114}" + 3029049, 0, 0, 1.00,chromobius,77aebadf067cf574601adb21a3398cc3b755e9badb2dd7d443a220524f15e299,"{""c"":""transit_color_code"",""d"":9,""noise"":""uniform"",""p"":0.002,""q"":62,""r"":1}","{""detection_events"":1250423}" + 2084388, 0, 0, 1.00,chromobius,49866e82faa9d45ccf044e662ebbca2d17206f27f0cc64f8fafa349e0d26fd18,"{""c"":""transit_color_code"",""d"":9,""noise"":""uniform"",""p"":0.003,""q"":62,""r"":1}","{""detection_events"":1282828}" + 1276996, 0, 0, 1.00,chromobius,4c7e8beb38e2471d1c024e138e26b01a6ae4a5d40c51f7c0d2a0a5d0c0368296,"{""c"":""transit_color_code"",""d"":9,""noise"":""uniform"",""p"":0.005,""q"":62,""r"":1}","{""detection_events"":1307005}" + 913381, 2, 0, 1.00,chromobius,aeb18c03b23e59de8ea6def6c6d8948d654a4f36214efb7b051d90e68e38f2a2,"{""c"":""transit_color_code"",""d"":9,""noise"":""uniform"",""p"":0.007,""q"":62,""r"":1}","{""detection_events"":1298115}" + 630784, 0, 0, 1.00,chromobius,5c6884e3401b3779bc85bceb4145e108b74f5bca2a8fe6d28c2a02973bc180d6,"{""c"":""transit_color_code"",""d"":9,""noise"":""uniform"",""p"":0.01,""q"":62,""r"":1}","{""detection_events"":1272620}" + 16503037, 0, 0, 1.00,chromobius,da8c9587a64fa7510b1d4adf38337915b00f52458fcdf233ee3f7614fad52cc4,"{""c"":""transit_color_code"",""d"":11,""noise"":""uniform"",""p"":0.0001,""q"":92,""r"":1}","{""detection_events"":528020}" + 11748384, 0, 0, 1.00,chromobius,dd840850cb9a9810784b956ec1139e1aa1451a003e735c9b7685a8f1e349fd06,"{""c"":""transit_color_code"",""d"":11,""noise"":""uniform"",""p"":0.0002,""q"":92,""r"":1}","{""detection_events"":752403}" + 9090214, 0, 0, 1.00,chromobius,d176f4f11bcf294f0cbc8215be3a3653864c747c8d59e573607cffdac926248c,"{""c"":""transit_color_code"",""d"":11,""noise"":""uniform"",""p"":0.0003,""q"":92,""r"":1}","{""detection_events"":866540}" + 6315820, 0, 0, 1.00,chromobius,5269b6e05236a6583969b510f4dec732956a40750380345edba627d927734743,"{""c"":""transit_color_code"",""d"":11,""noise"":""uniform"",""p"":0.0005,""q"":92,""r"":1}","{""detection_events"":1006595}" + 4836977, 0, 0, 1.00,chromobius,37f06c1fc75ed5d28adee2a9be4e7334e35fb68e7bc95ebe595fccc11b533895,"{""c"":""transit_color_code"",""d"":11,""noise"":""uniform"",""p"":0.0007,""q"":92,""r"":1}","{""detection_events"":1080891}" + 3589626, 0, 0, 1.00,chromobius,84692a87125b0a223fe80d676f4f7e33799427ec73d1fe48613777cdc7957c52,"{""c"":""transit_color_code"",""d"":11,""noise"":""uniform"",""p"":0.001,""q"":92,""r"":1}","{""detection_events"":1147378}" + 1945072, 0, 0, 1.00,chromobius,813dc2aa8c6c5a2817a86e07a7f8a97b79338f2d969312303ad9e621ac1db5cc,"{""c"":""transit_color_code"",""d"":11,""noise"":""uniform"",""p"":0.002,""q"":92,""r"":1}","{""detection_events"":1234618}" + 1312606, 0, 0, 1.00,chromobius,857f7a1098c81a5f06b98d5b7aec6b372f52730e735917a153553dd02746bd24,"{""c"":""transit_color_code"",""d"":11,""noise"":""uniform"",""p"":0.003,""q"":92,""r"":1}","{""detection_events"":1250969}" + 799501, 0, 0, 1.00,chromobius,bf1b70fd5c2b825a9b7ac838f506d49bb050f1b9cf56b004954e249890179a5e,"{""c"":""transit_color_code"",""d"":11,""noise"":""uniform"",""p"":0.005,""q"":92,""r"":1}","{""detection_events"":1260441}" + 569619, 0, 0, 1.00,chromobius,2dfb0263e32887cda4352547820a901fe4b3b0322c7f890b40d409b018d2420e,"{""c"":""transit_color_code"",""d"":11,""noise"":""uniform"",""p"":0.007,""q"":92,""r"":1}","{""detection_events"":1250818}" + 397414, 0, 0, 1.00,chromobius,5a262ec1906f822b7abe542b9d5851068d7eac4542311f9bf3652e1de71b3b42,"{""c"":""transit_color_code"",""d"":11,""noise"":""uniform"",""p"":0.01,""q"":92,""r"":1}","{""detection_events"":1236199}" + 13287679, 0, 0, 1.00,chromobius,d7ae9c0ad4709fda8609d045688acb0292e22c9d7de68fd044584edf14391fde,"{""c"":""transit_color_code"",""d"":13,""noise"":""uniform"",""p"":0.0001,""q"":128,""r"":1}","{""detection_events"":605517}" + 8944770, 0, 0, 1.00,chromobius,760b8fda0e1907f7bfa67a064952fb68be706e1524ca14dff2bd3634aad97671,"{""c"":""transit_color_code"",""d"":13,""noise"":""uniform"",""p"":0.0002,""q"":128,""r"":1}","{""detection_events"":817427}" + 6845088, 0, 0, 1.00,chromobius,8bb67d45277a9cb577e50576ce85d2e331fb916df1e15cbabfd22d2a98fdbf34,"{""c"":""transit_color_code"",""d"":13,""noise"":""uniform"",""p"":0.0003,""q"":128,""r"":1}","{""detection_events"":935152}" + 4562944, 0, 0, 1.00,chromobius,fea01e039174688973429cf2134b9caa50796de49b5d91966423f60da337c3bb,"{""c"":""transit_color_code"",""d"":13,""noise"":""uniform"",""p"":0.0005,""q"":128,""r"":1}","{""detection_events"":1038847}" + 3455095, 0, 0, 1.00,chromobius,fe96c637d0e54eeba89e1a4ddffbb948333ef4997c6179bf893f069a14d0c6c5,"{""c"":""transit_color_code"",""d"":13,""noise"":""uniform"",""p"":0.0007,""q"":128,""r"":1}","{""detection_events"":1103340}" + 2529584, 0, 0, 1.00,chromobius,e845606d92a0b88cbb8f8ef236488911be315b35967dd192f8ec51373c795b3c,"{""c"":""transit_color_code"",""d"":13,""noise"":""uniform"",""p"":0.001,""q"":128,""r"":1}","{""detection_events"":1155883}" + 1339392, 0, 0, 1.00,chromobius,d16cab82db96681f12a1d7e7c0a60efff9eeab4646ebee5821a59e81649babda,"{""c"":""transit_color_code"",""d"":13,""noise"":""uniform"",""p"":0.002,""q"":128,""r"":1}","{""detection_events"":1212546}" + 909896, 0, 0, 1.00,chromobius,4263db45b8cb85cef20fe0c10008356e48060369268070e17a3e5877ae38038c,"{""c"":""transit_color_code"",""d"":13,""noise"":""uniform"",""p"":0.003,""q"":128,""r"":1}","{""detection_events"":1232979}" + 541921, 0, 0, 1.00,chromobius,5eb68c16485d6f8b15c5c4a2d58ed611918a600547c075f57a41074cf39f3010,"{""c"":""transit_color_code"",""d"":13,""noise"":""uniform"",""p"":0.005,""q"":128,""r"":1}","{""detection_events"":1215352}" + 393952, 0, 0, 1.00,chromobius,0c37128a20dffc05159428863d30a72df07fd9d4564a22a7951bd9c2decea286,"{""c"":""transit_color_code"",""d"":13,""noise"":""uniform"",""p"":0.007,""q"":128,""r"":1}","{""detection_events"":1226694}" + 272025, 0, 0, 1.00,chromobius,27ee77ec1ac977718a169d50cce58297a6ceb34dd2fff45ce6e96ce116b4cba6,"{""c"":""transit_color_code"",""d"":13,""noise"":""uniform"",""p"":0.01,""q"":128,""r"":1}","{""detection_events"":1203376}" diff --git a/doc/chromobius.pyi b/doc/chromobius.pyi new file mode 100644 index 0000000..869d50d --- /dev/null +++ b/doc/chromobius.pyi @@ -0,0 +1,226 @@ +"""Chromobius (Development Version): an implementation of the mobius color code decoder.""" +# (This a stubs file describing the classes and methods in stim.) +from __future__ import annotations +from typing import overload, TYPE_CHECKING, Any, Iterable +if TYPE_CHECKING: + import io + import pathlib + import numpy as np + import stim + import sinter + import chromobius +class CompiledDecoder: + """A chromobius decoder ready to predict observable flips from detection events. + + Example: + >>> import stim + >>> import chromobius + + >>> dem = stim.Circuit(''' + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 + ... DETECTOR(0, 0, 0, 1) rec[-4] + ... DETECTOR(1, 0, 0, 2) rec[-3] + ... DETECTOR(2, 0, 0, 0) rec[-2] + ... DETECTOR(3, 0, 0, 1) rec[-1] + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''').detector_error_model() + + >>> decoder = chromobius.CompiledDecoder.from_dem(dem) + """ + @staticmethod + def from_dem( + dem: stim.DetectorErrorModel, + ) -> chromobius.CompiledDecoder: + """Compiles a decoder for a stim detector error model. + + Args: + dem: A stim detector error model. The detector error model must satisfy: + 1. Basis+Color annotations. Every detector that appears in an error + must specify coordinate data including a fourth coordinate. The 4th + coordinate indicates the basis and color of the detector with the + convention: + 0 = Red X + 1 = Green X + 2 = Blue X + 3 = Red Z + 4 = Green Z + 5 = Blue Z + 2. Rainbow triplets. Bulk errors with three symptoms in one basis should + have one symptom of each color. Errors with three symptoms that + repeat a color will cause an exception unless they can be decomposed + into other basic errors. + 3. Movable excitations. It needs to be possible to combine bulk errors + to form simpler errors with one or two symptoms that can be used to + move or destroy excitations. If bulk errors don't have this + property, decoding will fail when attempting to lift a solution + from the matcher requires dragging an excitation along a path but + there's no way to move the excitation along that path. + 4. Matchable-avoids-color. In parts of the dem that correspond to a + matchable code, at least one of the colors must be avoided. + Otherwise the matcher may be given a problem that can be solved + locally, but when lifting it needs to be solved non-locally. + + Returns: + A decoder object that can be used to predict observable flips from + detection event samples. + + Example: + >>> import stim + >>> import chromobius + + >>> dem = stim.Circuit(''' + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 + ... DETECTOR(0, 0, 0, 1) rec[-4] + ... DETECTOR(1, 0, 0, 2) rec[-3] + ... DETECTOR(2, 0, 0, 0) rec[-2] + ... DETECTOR(3, 0, 0, 1) rec[-1] + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''').detector_error_model() + + >>> decoder = chromobius.CompiledDecoder.from_dem(dem) + """ + @staticmethod + def predict_obs_flips_from_dets_bit_packed( + dets: np.ndarray, + ) -> np.ndarray: + """Predicts observable flips from detection events. + + Args: + dets: A bit packed numpy array of detection event data. The array can either + be 1-dimensional (a single shot to decode) or 2-dimensional (multiple + shots to decode, with the first axis being the shot axis and the second + axis being the detection event byte axis). + + The array's dtype must be np.uint8. If you have an array of dtype + np.bool_, you have data that's not bit packed. You can pack it by + using `np.packbits(array, bitorder='little')`. But ideally you + should attempt to never have unpacked data in the first place, + since it's 8x larger which can be a large performance loss. For + example, stim's sampler methods all have a `bit_packed=True` argument + that cause them to return bit packed data. + + Returns: + A bit packed numpy array of observable flip data. The array will have + the same number of dimensions as the dets argument. + + If dets is a 1D array, then the result has: + shape = (math.ceil(num_obs / 8),) + dtype = np.uint8 + If dets is a 2D array, then the result has: + shape = (dets.shape[0], math.ceil(num_obs / 8),) + dtype = np.uint8 + + To determine if the observable with index k was flipped in shot s, compute: + `bool((result[s, k // 8] >> (k % 8)) & 1)` + + Example: + >>> import stim + >>> import chromobius + >>> import numpy as np + + >>> repetition_color_code = stim.Circuit(''' + ... # Apply noise. + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... # Measure three-body stabilizers to catch errors. + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 Z4*Z5*Z6 Z5*Z6*Z7 + ... + ... # Annotate detectors, with a coloring in the 4th coordinate. + ... DETECTOR(0, 0, 0, 2) rec[-6] + ... DETECTOR(1, 0, 0, 0) rec[-5] + ... DETECTOR(2, 0, 0, 1) rec[-4] + ... DETECTOR(3, 0, 0, 2) rec[-3] + ... DETECTOR(4, 0, 0, 0) rec[-2] + ... DETECTOR(5, 0, 0, 1) rec[-1] + ... + ... # Check on the message. + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''') + + >>> # Sample the circuit. + >>> shots = 4096 + >>> sampler = repetition_color_code.compile_detector_sampler() + >>> dets, actual_obs_flips = sampler.sample( + ... shots=shots, + ... separate_observables=True, + ... bit_packed=True, + ... ) + + >>> # Decode with Chromobius. + >>> dem = repetition_color_code.detector_error_model() + >>> decoder = chromobius.compile_decoder_for_dem(dem) + >>> predicted_flips = decoder.predict_obs_flips_from_dets_bit_packed(dets) + + >>> # Count mistakes. + >>> differences = np.any(predicted_flips != actual_obs_flips, axis=1) + >>> mistakes = np.count_nonzero(differences) + >>> assert mistakes < shots / 5 + """ +def compile_decoder_for_dem( + dem: stim.DetectorErrorModel, +) -> chromobius.CompiledDecoder: + """Compiles a decoder for a stim detector error model. + + Args: + dem: A stim detector error model. The detector error model must satisfy: + 1. Basis+Color annotations. Every detector that appears in an error + must specify coordinate data including a fourth coordinate. The 4th + coordinate indicates the basis and color of the detector with the + convention: + 0 = Red X + 1 = Green X + 2 = Blue X + 3 = Red Z + 4 = Green Z + 5 = Blue Z + 2. Rainbow triplets. Bulk errors with three symptoms in one basis should + have one symptom of each color. Errors with three symptoms that + repeat a color will cause an exception unless they can be decomposed + into other basic errors. + 3. Movable excitations. It needs to be possible to combine bulk errors + to form simpler errors with one or two symptoms that can be used to + move or destroy excitations. If bulk errors don't have this + property, decoding will fail when attempting to lift a solution + from the matcher requires dragging an excitation along a path but + there's no way to move the excitation along that path. + 4. Matchable-avoids-color. In parts of the dem that correspond to a + matchable code, at least one of the colors must be avoided. + Otherwise the matcher may be given a problem that can be solved + locally, but when lifting it needs to be solved non-locally. + + Returns: + A decoder object that can be used to predict observable flips from + detection event samples. + + Example: + >>> import stim + >>> import chromobius + + >>> dem = stim.Circuit(''' + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 + ... DETECTOR(0, 0, 0, 1) rec[-4] + ... DETECTOR(1, 0, 0, 2) rec[-3] + ... DETECTOR(2, 0, 0, 0) rec[-2] + ... DETECTOR(3, 0, 0, 1) rec[-1] + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''').detector_error_model() + + >>> decoder = chromobius.compile_decoder_for_dem(dem) + """ +def sinter_decoders() -> dict[str, sinter.Decoder]: + """A dictionary describing chromobius to sinter. + + Giving the result of this function to the `custom_decoders` argument of + `sinter.collect` will tell sinter about the decoder 'chromobius'. On the + command line, the equivalent argument is + `--custom_decoders 'chromobius:sinter_decoders'`. + + Returns: + The dict `{'chromobius': }`. + """ diff --git a/doc/chromobius_api_reference.md b/doc/chromobius_api_reference.md new file mode 100644 index 0000000..968137e --- /dev/null +++ b/doc/chromobius_api_reference.md @@ -0,0 +1,266 @@ +# Chromobius (Development Version) API Reference + +## Index +- `` + - [`chromobius.compile_decoder_for_dem`](#chromobius.compile_decoder_for_dem) + - [`chromobius.sinter_decoders`](#chromobius.sinter_decoders) +- [`chromobius.CompiledDecoder`](#chromobius.CompiledDecoder) + - [`chromobius.CompiledDecoder.from_dem`](#chromobius.CompiledDecoder.from_dem) + - [`chromobius.CompiledDecoder.predict_obs_flips_from_dets_bit_packed`](#chromobius.CompiledDecoder.predict_obs_flips_from_dets_bit_packed) +```python +# Types used by the method definitions. +from typing import overload, TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Tuple, Union +import io +import pathlib +import numpy as np +``` + + +```python +# chromobius.compile_decoder_for_dem + +# (at top-level in the chromobius module) +def compile_decoder_for_dem( + dem: stim.DetectorErrorModel, +) -> chromobius.CompiledDecoder: + """Compiles a decoder for a stim detector error model. + + Args: + dem: A stim detector error model. The detector error model must satisfy: + 1. Basis+Color annotations. Every detector that appears in an error + must specify coordinate data including a fourth coordinate. The 4th + coordinate indicates the basis and color of the detector with the + convention: + 0 = Red X + 1 = Green X + 2 = Blue X + 3 = Red Z + 4 = Green Z + 5 = Blue Z + 2. Rainbow triplets. Bulk errors with three symptoms in one basis should + have one symptom of each color. Errors with three symptoms that + repeat a color will cause an exception unless they can be decomposed + into other basic errors. + 3. Movable excitations. It needs to be possible to combine bulk errors + to form simpler errors with one or two symptoms that can be used to + move or destroy excitations. If bulk errors don't have this + property, decoding will fail when attempting to lift a solution + from the matcher requires dragging an excitation along a path but + there's no way to move the excitation along that path. + 4. Matchable-avoids-color. In parts of the dem that correspond to a + matchable code, at least one of the colors must be avoided. + Otherwise the matcher may be given a problem that can be solved + locally, but when lifting it needs to be solved non-locally. + + Returns: + A decoder object that can be used to predict observable flips from + detection event samples. + + Example: + >>> import stim + >>> import chromobius + + >>> dem = stim.Circuit(''' + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 + ... DETECTOR(0, 0, 0, 1) rec[-4] + ... DETECTOR(1, 0, 0, 2) rec[-3] + ... DETECTOR(2, 0, 0, 0) rec[-2] + ... DETECTOR(3, 0, 0, 1) rec[-1] + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''').detector_error_model() + + >>> decoder = chromobius.compile_decoder_for_dem(dem) + """ +``` + + +```python +# chromobius.sinter_decoders + +# (at top-level in the chromobius module) +def sinter_decoders() -> dict[str, sinter.Decoder]: + """A dictionary describing chromobius to sinter. + + Giving the result of this function to the `custom_decoders` argument of + `sinter.collect` will tell sinter about the decoder 'chromobius'. On the + command line, the equivalent argument is + `--custom_decoders 'chromobius:sinter_decoders'`. + + Returns: + The dict `{'chromobius': }`. + """ +``` + + +```python +# chromobius.CompiledDecoder + +# (at top-level in the chromobius module) +class CompiledDecoder: + """A chromobius decoder ready to predict observable flips from detection events. + + Example: + >>> import stim + >>> import chromobius + + >>> dem = stim.Circuit(''' + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 + ... DETECTOR(0, 0, 0, 1) rec[-4] + ... DETECTOR(1, 0, 0, 2) rec[-3] + ... DETECTOR(2, 0, 0, 0) rec[-2] + ... DETECTOR(3, 0, 0, 1) rec[-1] + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''').detector_error_model() + + >>> decoder = chromobius.CompiledDecoder.from_dem(dem) + """ +``` + + +```python +# chromobius.CompiledDecoder.from_dem + +# (in class chromobius.CompiledDecoder) +@staticmethod +def from_dem( + dem: stim.DetectorErrorModel, +) -> chromobius.CompiledDecoder: + """Compiles a decoder for a stim detector error model. + + Args: + dem: A stim detector error model. The detector error model must satisfy: + 1. Basis+Color annotations. Every detector that appears in an error + must specify coordinate data including a fourth coordinate. The 4th + coordinate indicates the basis and color of the detector with the + convention: + 0 = Red X + 1 = Green X + 2 = Blue X + 3 = Red Z + 4 = Green Z + 5 = Blue Z + 2. Rainbow triplets. Bulk errors with three symptoms in one basis should + have one symptom of each color. Errors with three symptoms that + repeat a color will cause an exception unless they can be decomposed + into other basic errors. + 3. Movable excitations. It needs to be possible to combine bulk errors + to form simpler errors with one or two symptoms that can be used to + move or destroy excitations. If bulk errors don't have this + property, decoding will fail when attempting to lift a solution + from the matcher requires dragging an excitation along a path but + there's no way to move the excitation along that path. + 4. Matchable-avoids-color. In parts of the dem that correspond to a + matchable code, at least one of the colors must be avoided. + Otherwise the matcher may be given a problem that can be solved + locally, but when lifting it needs to be solved non-locally. + + Returns: + A decoder object that can be used to predict observable flips from + detection event samples. + + Example: + >>> import stim + >>> import chromobius + + >>> dem = stim.Circuit(''' + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 + ... DETECTOR(0, 0, 0, 1) rec[-4] + ... DETECTOR(1, 0, 0, 2) rec[-3] + ... DETECTOR(2, 0, 0, 0) rec[-2] + ... DETECTOR(3, 0, 0, 1) rec[-1] + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''').detector_error_model() + + >>> decoder = chromobius.CompiledDecoder.from_dem(dem) + """ +``` + + +```python +# chromobius.CompiledDecoder.predict_obs_flips_from_dets_bit_packed + +# (in class chromobius.CompiledDecoder) +@staticmethod +def predict_obs_flips_from_dets_bit_packed( + dets: np.ndarray, +) -> np.ndarray: + """Predicts observable flips from detection events. + + Args: + dets: A bit packed numpy array of detection event data. The array can either + be 1-dimensional (a single shot to decode) or 2-dimensional (multiple + shots to decode, with the first axis being the shot axis and the second + axis being the detection event byte axis). + + The array's dtype must be np.uint8. If you have an array of dtype + np.bool_, you have data that's not bit packed. You can pack it by + using `np.packbits(array, bitorder='little')`. But ideally you + should attempt to never have unpacked data in the first place, + since it's 8x larger which can be a large performance loss. For + example, stim's sampler methods all have a `bit_packed=True` argument + that cause them to return bit packed data. + + Returns: + A bit packed numpy array of observable flip data. The array will have + the same number of dimensions as the dets argument. + + If dets is a 1D array, then the result has: + shape = (math.ceil(num_obs / 8),) + dtype = np.uint8 + If dets is a 2D array, then the result has: + shape = (dets.shape[0], math.ceil(num_obs / 8),) + dtype = np.uint8 + + To determine if the observable with index k was flipped in shot s, compute: + `bool((result[s, k // 8] >> (k % 8)) & 1)` + + Example: + >>> import stim + >>> import chromobius + >>> import numpy as np + + >>> repetition_color_code = stim.Circuit(''' + ... # Apply noise. + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... # Measure three-body stabilizers to catch errors. + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 Z4*Z5*Z6 Z5*Z6*Z7 + ... + ... # Annotate detectors, with a coloring in the 4th coordinate. + ... DETECTOR(0, 0, 0, 2) rec[-6] + ... DETECTOR(1, 0, 0, 0) rec[-5] + ... DETECTOR(2, 0, 0, 1) rec[-4] + ... DETECTOR(3, 0, 0, 2) rec[-3] + ... DETECTOR(4, 0, 0, 0) rec[-2] + ... DETECTOR(5, 0, 0, 1) rec[-1] + ... + ... # Check on the message. + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''') + + >>> # Sample the circuit. + >>> shots = 4096 + >>> sampler = repetition_color_code.compile_detector_sampler() + >>> dets, actual_obs_flips = sampler.sample( + ... shots=shots, + ... separate_observables=True, + ... bit_packed=True, + ... ) + + >>> # Decode with Chromobius. + >>> dem = repetition_color_code.detector_error_model() + >>> decoder = chromobius.compile_decoder_for_dem(dem) + >>> predicted_flips = decoder.predict_obs_flips_from_dets_bit_packed(dets) + + >>> # Count mistakes. + >>> differences = np.any(predicted_flips != actual_obs_flips, axis=1) + >>> mistakes = np.count_nonzero(differences) + >>> assert mistakes < shots / 5 + """ +``` diff --git a/doc/developers.md b/doc/developers.md new file mode 100644 index 0000000..9b93efe --- /dev/null +++ b/doc/developers.md @@ -0,0 +1,214 @@ +# Chromobius Developer Documentation + +## Index + +- [Repository Layout](#Repository_Layout) +- [Building chromobius as a standalone command line tool](#build-cli) + - [with bazel](#build-cli-bazel) + - [with cmake](#build-cli-cmake) + - [with gcc](#build-cli-gcc) + - [with clang](#build-cli-clang) +- [Building chromobius as a python package](#build-python) + - [with bazel](#build-python-bazel) + - [with cmake](#build-python-cmake) + - [with cibuildwheels](#build-python-cibuildwheels) + - [with pip](#build-python-pip) +- [Running tests](#test) + - [python unit tests](#test-python) + - [C++ unit tests with Bazel](#test-bazel) + - [C++ unit tests with cmake](#test-cmake) +- [Running performance benchmarks](#perf) + - [with bazel](#perf-bazel) + - [with cmake](#perf-cmake) + + +## Repository Layout + +- `src/chromobius/`: C++ code implementing Chromobius and its python package. +- `src/clorco/`: Python code for generating color code and surface code circuits used to test Chromobius. +- `src/gen/`: Generic utilities for making circuits; used by `src/clorco/`. +- `tools/`: Bash scripts for generating circuits and statistics and plots presented in the paper. + + +## Building chromobius as a standalone command line tool + + +### with bazel: + +```bash +bazel build :chromobius +``` + +Or, to run the tool: + +```bash +bazel run :chromobius +``` + + +### with cmake: + +```bash +cmake . +make chromobius_pybind +``` + +Then, to run the built tool: + +```bash +out/chromobius +``` + + +### with gcc: + +```bash +# This must be run from the repository root. +# This requires that you have libstim and libpymatching installed. + +readarray -d '' CC_FILES_TO_BUILD < \ + <( \ + find src \ + | grep "\\.cc$" \ + | grep -v "\\.\(test\|perf\|pybind\)\\.cc$" \ + ) + +g++ \ + -I src \ + -std=c++20 \ + -O3 \ + -march=native \ + ${CC_FILES_TO_BUILD[@]} \ + -l stim \ + -l pymatching +``` + + +### with clang: + +```bash +# This must be run from the repository root. +# This requires that you have libstim and libpymatching installed. + +readarray -d '' CC_FILES_TO_BUILD < \ + <( \ + find src \ + | grep "\\.cc$" \ + | grep -v "\\.\(test\|perf\|pybind\)\\.cc$" \ + ) + +clang \ + -I src \ + -std=c++20 \ + -O3 \ + -march=native \ + ${CC_FILES_TO_BUILD[@]} \ + -l "stdc++" \ + -l m \ + -l stim \ + -l pymatching +``` + +Then, to run the built tool: + +```bash +./a.out +``` + + +## Building chromobius as a python package + + +### with bazel: + +```bash +bazel build :chromobius_dev_wheel +pip install bazel-bin/chromobius-0.0.dev0-py3-none-any.whl +``` + + +### with cmake: + +```bash +# Requires pybind11 and python to be installed on your system. +cmake . +make chromobius_pybind +# output is in `out/` with a path that depends on your machine +# e.g. it might be `out/chromobius.cpython-311-x86_64-linux-gnu.so` +``` + + +### with cibuildwheel: + +```bash +pip install cibuildwheel +# See https://cibuildwheel.readthedocs.io/en/stable/options/#build-skip for CIBW_BUILD values +CIBW_BUILD=cp311-manylinux_x86_64 cibuildwheel --platform linux +# output is in `wheelhouse/` with a path that depends on platform/target +# e.g. it might be `out/chromobius-0.0.dev0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl` +``` + + +### with pip: + +```bash +# Must be run from the chromobius git repository root. +# Note this will build the package AND install it into your python environment. +pip install . +# output is in `python_build_chromobius/` under a platform dependent directory and filename +# e.g. it might be `python_build_chromobius/lib.linux-x86_64-cpython-311/chromobius.cpython-311-x86_64-linux-gnu.so` +``` + + + +## Running unit tests + + +### python unit tests + +The python unit tests check that the circuit generation utilities +are working correctly, and that Chromobius can decode the generated +circuits. + +Note that these tests require the chromobius python package to be installed. + +```bash +pip install -r requirements.txt +pytest src +``` + + +### C++ unit tests with bazel + +```bash +bazel test :all +``` + + +### C++ unit tests with cmake + +```bash +# Requires googletest to be installed on your system. +cmake . +make chromobius_test +out/chromobius_test +``` + + +## Running performance benchmarks + + +### with bazel + +```bash +bazel run :chromobius_perf +``` + + +### with cmake + +```bash +cmake . +make chromobius_perf +out/chromobius_perf +``` diff --git a/doc/getting_started.ipynb b/doc/getting_started.ipynb new file mode 100644 index 0000000..f9964f8 --- /dev/null +++ b/doc/getting_started.ipynb @@ -0,0 +1,2694 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "eddcd418-aac7-41bf-806a-abf24775e2d5", + "metadata": {}, + "source": [ + "# Getting Started with Chromobius\n", + "\n", + "1. [What is Chromobius?](#what-is-chromobius)\n", + "2. [Installing Chromobius](#installing)\n", + "3. [Creating a Color Code Circuit](#circuit)\n", + "4. [Decoding shots from your circuit with Chromobius](#decode)\n", + "5. [Using Sinter to collect and plot statistics](#sinter)\n", + "\n", + "# Prereqs\n", + "This tutorial assumes you can read and write Python code, and that you have a working **Python 3.10**+ environment.\n", + "\n", + "This tutorial assumes you're somewhat familiar with quantum error correction, especially stabilizer codes, and *especially* the color code. It assumes you know what a color code is and why you'd want to decode it." + ] + }, + { + "cell_type": "markdown", + "id": "4c2c8e32-b8a5-408c-aa80-4c803946e192", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "\n", + "# What is Chromobius?\n", + "\n", + "Chromobius is an [open source](https://github.com/quantumlib/chromobius) color code decoder.\n", + "Chromobius is an implementation of the [mobius decoder](https://arxiv.org/abs/2108.11395), which approximates the color code decoding problem as a minimum weight matching problem.\n", + "Chromobius uses [PyMatching](https://github.com/oscarhiggott/PyMatching/) to solve the minimum weight matching problem." + ] + }, + { + "cell_type": "markdown", + "id": "e4435295-281d-438e-bd92-87d86c4a1adb", + "metadata": {}, + "source": [ + "\n", + "# Installing Chromobius\n", + "\n", + "Chromobius is available as a python pypi package.\n", + "You can install Chromobius with `pip` by running the command `pip install chromobius`." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "c99723c9-56c3-4123-8935-4a3868b2dcb3", + "metadata": {}, + "outputs": [], + "source": [ + "#!pip install chromobius~=1.0.0" + ] + }, + { + "cell_type": "markdown", + "id": "b6ae556d-e7d7-435b-b041-8fffa65f9836", + "metadata": {}, + "source": [ + "You can check that you installed Chromobius by importing it and printing its version:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "0c74f8ae-5ea1-424b-a57e-3d8bebe12b68", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.0.dev0\n" + ] + } + ], + "source": [ + "import chromobius\n", + "print(chromobius.__version__)" + ] + }, + { + "cell_type": "markdown", + "id": "0c89a941-5b7b-4f64-91f4-620af1f9ee89", + "metadata": {}, + "source": [ + "\n", + "# Creating a Color Code Circuit\n", + "\n", + "The first (and unfortunately hardest) part of benchmarking a QEC circuit is creating the circuit.\n", + "For this notebook, you'll create a color code circuit with a phenomenological noise model.\n", + "\n", + "A color code is typically built out of a hexagonal tiling, with the hexagons truncated into trapezoids at boundaries forming an overall triangular shape.\n", + "You don't want to be dealing with trapezoids-vs-hexagons logic when also dealing with circuit logic.\n", + "So, the first thing you should do is to build a list of objects describing the tiling.\n", + "\n", + "Define a `Tile` class with a list of qubit positions, as well as a color.\n", + "The positions are 2D locations, which can be conveniently represented in Python using complex numbers." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "bcd2bd06-ac3b-49cb-987b-4bf7e48e8816", + "metadata": {}, + "outputs": [], + "source": [ + "import dataclasses\n", + "\n", + "@dataclasses.dataclass\n", + "class Tile:\n", + " qubits: list[complex]\n", + " color: str" + ] + }, + { + "cell_type": "markdown", + "id": "20345285-8343-49d4-95e1-505b39f41139", + "metadata": {}, + "source": [ + "You can make the tiling for a color code by starting with a normal hexagonal tiling, and then cutting away anything outside three half-planes defining the boundaries.\n", + "To avoid issues with floating point rounding error, it's safest to use a distorted hexagonal grid where all vertices have integer coordinates." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c349d77a-87a5-45cb-b520-cc9483a0d00e", + "metadata": {}, + "outputs": [], + "source": [ + "def make_color_code_tiles(*, base_data_width: int) -> list[Tile]:\n", + " if not (base_data_width % 2 == 1 and base_data_width >= 3):\n", + " raise ValueError(f\"{base_data_width=} wasn't an odd number at least as large as 3.\")\n", + " w = base_data_width * 2 - 1\n", + "\n", + " def is_in_bounds(q: complex) -> bool:\n", + " # Check that it's within the intersection of the three boundary half planes.\n", + " if q.imag < 0:\n", + " # Too far up.\n", + " return False\n", + " if q.imag * 2 > q.real * 3:\n", + " # Too far downleft.\n", + " return False\n", + " if q.imag * 2 > (w - q.real) * 3:\n", + " # Too far downright.\n", + " return False\n", + " return True\n", + "\n", + " # Make a hexagonal tiling, cutting away any vertices that are out of bounds.\n", + " tiles = []\n", + " hexagon_offsets = [-1, +1j, +1j + 1, +2, -1j + 1, -1j]\n", + " for x in range(1, w, 2):\n", + " for y in range((x // 2) % 2, w, 2):\n", + " q = x + 1j * y\n", + " tile = Tile(\n", + " color=['red', 'green', 'blue'][y % 3],\n", + " qubits=[\n", + " q + d\n", + " for d in hexagon_offsets\n", + " if is_in_bounds(q + d)\n", + " ],\n", + " )\n", + " # Only keep the hexagons and trapezoids.\n", + " # No empty tiles, or single-point tiles, or etc.\n", + " if len(tile.qubits) in [4, 6]:\n", + " tiles.append(tile)\n", + "\n", + " return tiles " + ] + }, + { + "cell_type": "markdown", + "id": "5d7edf94-a405-4b56-ab1c-5c18ba8cc20e", + "metadata": {}, + "source": [ + "The easiest way to check that the tiling is correct is to draw it.\n", + "The easiest way to do draw it is by creating an SVG image.\n", + "An SVG image is easy to show in a python notebook, because any class with a `_repr_svg_` method will display as an image.\n", + "And an SVG image is reasonably easy to create, because it's just a list of [drawing commands written in an HTML style](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths).\n", + "For example, the command `` will draw a red square with a black outline.\n", + "\n", + "By turning each tile into a path command, you can transform tiles into shapes in an SVG image:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "2379f28a-f09a-45d0-827e-19b4317bf817", + "metadata": {}, + "outputs": [], + "source": [ + "class ShowAsSvg:\n", + " def __init__(self, svg: str):\n", + " self.svg = svg\n", + " def _repr_svg_(self) -> str:\n", + " return self.svg\n", + "\n", + "def draw_tiles_as_svg(tiles: list[Tile]) -> ShowAsSvg:\n", + " # Size the SVG to fit the tiles.\n", + " max_r = max(q.real for tile in tiles for q in tile.qubits)\n", + " max_i = max(q.imag for tile in tiles for q in tile.qubits)\n", + " svg = f'\\n'\n", + "\n", + " # Add each tile to the SVG as a filled shape.\n", + " for tile in tiles:\n", + " pts = [q * 20 for q in tile.qubits]\n", + " p = pts[-1]\n", + " d = f'M{p.real},{p.imag}'\n", + " for p in pts:\n", + " d += f' L{p.real},{p.imag}'\n", + " svg += f'\\n'\n", + " \n", + " svg += ''\n", + " \n", + " return ShowAsSvg(svg)" + ] + }, + { + "cell_type": "markdown", + "id": "5c8f4da8-6e13-4fa9-88f0-e6986356e252", + "metadata": {}, + "source": [ + "Now that you have this method, you can use it on your color code tiling method to get a picture of a color code!\n", + "It will look a bit wobbly because you distorted the vertices to land on integer coordinates, but that's fine:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "e851d72f-6865-48f4-af51-0d82a642c0e4", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "<__main__.ShowAsSvg at 0x7f77347dacd0>" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "draw_tiles_as_svg(make_color_code_tiles(base_data_width=13))" + ] + }, + { + "cell_type": "markdown", + "id": "670a7411-d291-4bca-85cc-ed605d5ff915", + "metadata": {}, + "source": [ + "Now that you have the building blocks of a color code, you can go about turning them into a circuit.\n", + "You first need to prepare the system by measuring the observables and stabilizers without noise.\n", + "Then you need to perform a specified number of rounds of stabilizer measurement with noise.\n", + "Finally, you need to end the circuit with one last noiseless measurement of the stabilizers and the observables.\n", + "\n", + "For each stabilizer measurement, you need to declare a `DETECTOR` comparing it to the corresponding measurement from the previous round.\n", + "The easiest way to do this is to make sure you always measure the stabilizers in the same order, so that the offset between measurements to compare is always the same.\n", + "For the observable measurements, the measurement indexing logic is much easier because you can lean on the fact that stim's `OBSERVABLE_INCLUDE` instruction can gradually accumulate measurements for an observable over the entire circuit.\n", + "(The `DETECTOR` instruction instead requires all measurements to be given at once).\n", + "\n", + "Other details you want to include are: `QUBIT_COORDS` instructions indicating the spatial layout, `TICK` instructions indicating the progression of time, and noise instructions indicating qubits to depolarize and measurements to probabilistically flip.\n", + "(For more complicated circuits, you would try to split this work into more pieces.\n", + "For example, you would add noise to the finished circuit, instead of adding it while building the circuit.)\n", + "\n", + "A very key detail that you must include in this circuit, that wouldn't normally be required by a stim circuit, is annotations on every detector stating its basis and color.\n", + "Chromobius needs this information in order to decode the circuit.\n", + "You add color and basis annotations to detectors by using their coordinate data.\n", + "Chromobius will look at the 4th coordinate of a detector's coordinate data to see what its basis and color are, using this convention:\n", + "- 0: red X\n", + "- 1: green X\n", + "- 2: blue X\n", + "- 3: red Z\n", + "- 4: green Z\n", + "- 5: blue Z.\n", + "\n", + "As you can maybe tell, making a circuit can be a very involved process!\n", + "This notebook isn't really about making circuits, and you probably don't want to get too bogged down in this detail, so let's not get stuck on this.\n", + "Just... write a function that makes an annotated color code circuit:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "5887447a-4720-4f68-b99b-cf1a22cd9e5f", + "metadata": {}, + "outputs": [], + "source": [ + "import stim\n", + "from typing import Literal\n", + "\n", + "def make_color_code_circuit(\n", + " *,\n", + " obs_basis: Literal['X', 'Y', 'Z'],\n", + " base_data_width: int,\n", + " rounds: int,\n", + " noise_strength: float,\n", + ") -> stim.Circuit:\n", + " \"\"\"Creates a color code circuit with a phenomenological noise model.\n", + "\n", + " The circuit's detectors are annotated so that Chromobius can decode them.\n", + "\n", + " Args:\n", + " obs_basis: The basis of the observable to prepare and verify at the end of the circuit.\n", + " base_data_width: The number of data qubits along one side of the patch.\n", + " rounds: The number of times to apply depolarizing noise. One more than the number of\n", + " times to apply measurement noise.\n", + " noise_strength: The strength of the depolarizing noise applied to the data qubits,\n", + " and also the probability of noisy measurements reporting the wrong result.\n", + "\n", + " Returns:\n", + " The created circuit.\n", + " \"\"\"\n", + "\n", + " def mpp_targets(\n", + " qubits: list[complex],\n", + " basis: Literal['X', 'Y', 'Z']\n", + " ) -> list[stim.GateTarget]:\n", + " \"\"\"Makes a pauli product for an MPP instruction.\"\"\"\n", + " target_b = {'X': stim.target_x, 'Y': stim.target_y, 'Z': stim.target_z}[basis]\n", + " indices = sorted(q2i[q] for q in qubits)\n", + " targets = []\n", + " for k in indices:\n", + " targets.append(target_b(k))\n", + " targets.append(stim.target_combiner())\n", + " targets.pop()\n", + " return targets\n", + "\n", + " def measure_observables() -> stim.Circuit:\n", + " \"\"\"Make instructions to measure an observable of the color code.\"\"\"\n", + " c = stim.Circuit()\n", + " c.append(\"MPP\", mpp_targets(sorted_qubits, obs_basis))\n", + " c.append(\"OBSERVABLE_INCLUDE\", stim.target_rec(-1), 0)\n", + " return c\n", + " \n", + " def measure_stabilizers(\n", + " *,\n", + " data_noise_after: bool,\n", + " measure_noise: bool,\n", + " include_detectors: bool,\n", + " ) -> stim.Circuit:\n", + " \"\"\"Make instructions to measure the stabilizers of the color code.\"\"\"\n", + " c = stim.Circuit()\n", + "\n", + " # Measure every stabilizer.\n", + " for basis in ['X', 'Z']:\n", + " for tile in tiles:\n", + " c.append(\"MPP\", mpp_targets(tile.qubits, basis), noise_strength if measure_noise else None)\n", + " \n", + " # Compare the measurements to the previous round to produce detection events.\n", + " if include_detectors:\n", + " num_stabilizers = len(tiles) * 2\n", + " for xz in range(2):\n", + " for k, tile in enumerate(tiles):\n", + " center = sum(tile.qubits) / len(tile.qubits)\n", + " chromobius_color = {'red': 0, 'green': 1, 'blue': 2}[tile.color]\n", + " chromobius_annotation = chromobius_color + xz*3\n", + " offset = xz * len(tiles) + k\n", + " c.append(\"DETECTOR\", [\n", + " stim.target_rec(-num_stabilizers + offset), \n", + " stim.target_rec(-num_stabilizers*2 + offset),\n", + " ], [center.real, center.imag, 0, chromobius_annotation])\n", + "\n", + " # End the round.\n", + " if data_noise_after:\n", + " c.append(\"DEPOLARIZE1\", range(len(all_qubits)), noise_strength)\n", + " c.append(\"SHIFT_COORDS\", [], [0, 0, 1])\n", + " c.append(\"TICK\")\n", + "\n", + " return c\n", + "\n", + " tiles = make_color_code_tiles(base_data_width=base_data_width)\n", + " circuit = stim.Circuit()\n", + "\n", + " # Index the qubit coordinates and put coordinate data in the circuit.\n", + " all_qubits = {q for tile in tiles for q in tile.qubits}\n", + " sorted_qubits = sorted(all_qubits, key=lambda q: (q.real, q.imag))\n", + " q2i = {q: i for i, q in enumerate(sorted_qubits)}\n", + " for q, i in q2i.items():\n", + " circuit.append(\"QUBIT_COORDS\", [i], [q.real, q.imag])\n", + "\n", + " # Use the helper methods you just defined to build the rounds and combine them into a full circuit.\n", + " circuit += measure_observables()\n", + " circuit += measure_stabilizers(data_noise_after=True, measure_noise=False, include_detectors=False)\n", + " circuit += (rounds - 1) * measure_stabilizers(data_noise_after=True, measure_noise=True, include_detectors=True)\n", + " circuit += measure_stabilizers(data_noise_after=False, measure_noise=False, include_detectors=True)\n", + " circuit += measure_observables()\n", + " \n", + " return circuit" + ] + }, + { + "cell_type": "markdown", + "id": "aaa82ea6-77d6-4f0f-9597-5004e942c07c", + "metadata": {}, + "source": [ + "To look at the circuit, you can make a timeline diagram:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "f9d25d3e-9242-41c1-bf9f-e2b329d56626", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "q0\n", + "\n", + "q1\n", + "\n", + "q2\n", + "\n", + "q3\n", + "\n", + "q4\n", + "\n", + "q5\n", + "\n", + "q6\n", + "\n", + "\n", + "COORDS(0,0)\n", + "\n", + "COORDS(1,1)\n", + "\n", + "COORDS(2,1)\n", + "\n", + "COORDS(2,3)\n", + "\n", + "COORDS(3,0)\n", + "\n", + "COORDS(3,2)\n", + "\n", + "COORDS(4,0)\n", + "\n", + "\n", + "MPPY\n", + "rec[0]\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "OBS_INCLUDE(0)\n", + "L0 *= rec[0]\n", + "\n", + "\n", + "MPPX\n", + "rec[1]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPX\n", + "rec[2]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPX\n", + "rec[3]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPZ\n", + "rec[4]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "\n", + "MPPZ\n", + "rec[5]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "\n", + "MPPZ\n", + "rec[6]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "\n", + "\n", + "REP6\n", + "\n", + "\n", + "MPPX\n", + "rec[7+iter*6]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "0.001\n", + "\n", + "\n", + "MPPX\n", + "rec[8+iter*6]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "0.001\n", + "\n", + "\n", + "MPPX\n", + "rec[9+iter*6]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "0.001\n", + "\n", + "\n", + "MPPZ\n", + "rec[10+iter*6]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "0.001\n", + "\n", + "\n", + "MPPZ\n", + "rec[11+iter*6]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "0.001\n", + "\n", + "\n", + "MPPZ\n", + "rec[12+iter*6]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "0.001\n", + "\n", + "DETECTOR\n", + "coords=(1.5,0.5,1+iter,0)\n", + "D[0+iter*6] = rec[7+iter*6]*rec[1+iter*6]\n", + "\n", + "DETECTOR\n", + "coords=(2,1.75,1+iter,2)\n", + "D[1+iter*6] = rec[8+iter*6]*rec[2+iter*6]\n", + "\n", + "DETECTOR\n", + "coords=(3,0.75,1+iter,1)\n", + "D[2+iter*6] = rec[9+iter*6]*rec[3+iter*6]\n", + "\n", + "DETECTOR\n", + "coords=(1.5,0.5,1+iter,3)\n", + "D[3+iter*6] = rec[10+iter*6]*rec[4+iter*6]\n", + "\n", + "DETECTOR\n", + "coords=(2,1.75,1+iter,5)\n", + "D[4+iter*6] = rec[11+iter*6]*rec[5+iter*6]\n", + "\n", + "DETECTOR\n", + "coords=(3,0.75,1+iter,4)\n", + "D[5+iter*6] = rec[12+iter*6]*rec[6+iter*6]\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "MPPX\n", + "rec[43]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPX\n", + "rec[44]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPX\n", + "rec[45]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPZ\n", + "rec[46]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "\n", + "MPPZ\n", + "rec[47]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "\n", + "MPPZ\n", + "rec[48]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "DETECTOR\n", + "coords=(1.5,0.5,7,0)\n", + "D36 = rec[43]*rec[37]\n", + "\n", + "DETECTOR\n", + "coords=(2,1.75,7,2)\n", + "D37 = rec[44]*rec[38]\n", + "\n", + "DETECTOR\n", + "coords=(3,0.75,7,1)\n", + "D38 = rec[45]*rec[39]\n", + "\n", + "DETECTOR\n", + "coords=(1.5,0.5,7,3)\n", + "D39 = rec[46]*rec[40]\n", + "\n", + "DETECTOR\n", + "coords=(2,1.75,7,5)\n", + "D40 = rec[47]*rec[41]\n", + "\n", + "DETECTOR\n", + "coords=(3,0.75,7,4)\n", + "D41 = rec[48]*rec[42]\n", + "\n", + "\n", + "\n", + "\n", + "MPPY\n", + "rec[49]\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "OBS_INCLUDE(0)\n", + "L0 *= rec[49]\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "\n", + "\n", + "\n", + "q0\n", + "\n", + "q1\n", + "\n", + "q2\n", + "\n", + "q3\n", + "\n", + "q4\n", + "\n", + "q5\n", + "\n", + "q6\n", + "\n", + "\n", + "COORDS(0,0)\n", + "\n", + "COORDS(1,1)\n", + "\n", + "COORDS(2,1)\n", + "\n", + "COORDS(2,3)\n", + "\n", + "COORDS(3,0)\n", + "\n", + "COORDS(3,2)\n", + "\n", + "COORDS(4,0)\n", + "\n", + "\n", + "MPPY\n", + "rec[0]\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "OBS_INCLUDE(0)\n", + "L0 *= rec[0]\n", + "\n", + "\n", + "MPPX\n", + "rec[1]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPX\n", + "rec[2]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPX\n", + "rec[3]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPZ\n", + "rec[4]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "\n", + "MPPZ\n", + "rec[5]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "\n", + "MPPZ\n", + "rec[6]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "\n", + "\n", + "REP6\n", + "\n", + "\n", + "MPPX\n", + "rec[7+iter*6]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "0.001\n", + "\n", + "\n", + "MPPX\n", + "rec[8+iter*6]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "0.001\n", + "\n", + "\n", + "MPPX\n", + "rec[9+iter*6]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "0.001\n", + "\n", + "\n", + "MPPZ\n", + "rec[10+iter*6]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "0.001\n", + "\n", + "\n", + "MPPZ\n", + "rec[11+iter*6]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "0.001\n", + "\n", + "\n", + "MPPZ\n", + "rec[12+iter*6]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "0.001\n", + "\n", + "DETECTOR\n", + "coords=(1.5,0.5,1+iter,0)\n", + "D[0+iter*6] = rec[7+iter*6]*rec[1+iter*6]\n", + "\n", + "DETECTOR\n", + "coords=(2,1.75,1+iter,2)\n", + "D[1+iter*6] = rec[8+iter*6]*rec[2+iter*6]\n", + "\n", + "DETECTOR\n", + "coords=(3,0.75,1+iter,1)\n", + "D[2+iter*6] = rec[9+iter*6]*rec[3+iter*6]\n", + "\n", + "DETECTOR\n", + "coords=(1.5,0.5,1+iter,3)\n", + "D[3+iter*6] = rec[10+iter*6]*rec[4+iter*6]\n", + "\n", + "DETECTOR\n", + "coords=(2,1.75,1+iter,5)\n", + "D[4+iter*6] = rec[11+iter*6]*rec[5+iter*6]\n", + "\n", + "DETECTOR\n", + "coords=(3,0.75,1+iter,4)\n", + "D[5+iter*6] = rec[12+iter*6]*rec[6+iter*6]\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "DEP1\n", + "0.001\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "MPPX\n", + "rec[43]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPX\n", + "rec[44]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPX\n", + "rec[45]\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "MPPX\n", + "\n", + "\n", + "MPPZ\n", + "rec[46]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "\n", + "MPPZ\n", + "rec[47]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "\n", + "MPPZ\n", + "rec[48]\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "MPPZ\n", + "\n", + "DETECTOR\n", + "coords=(1.5,0.5,7,0)\n", + "D36 = rec[43]*rec[37]\n", + "\n", + "DETECTOR\n", + "coords=(2,1.75,7,2)\n", + "D37 = rec[44]*rec[38]\n", + "\n", + "DETECTOR\n", + "coords=(3,0.75,7,1)\n", + "D38 = rec[45]*rec[39]\n", + "\n", + "DETECTOR\n", + "coords=(1.5,0.5,7,3)\n", + "D39 = rec[46]*rec[40]\n", + "\n", + "DETECTOR\n", + "coords=(2,1.75,7,5)\n", + "D40 = rec[47]*rec[41]\n", + "\n", + "DETECTOR\n", + "coords=(3,0.75,7,4)\n", + "D41 = rec[48]*rec[42]\n", + "\n", + "\n", + "\n", + "\n", + "MPPY\n", + "rec[49]\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "MPPY\n", + "\n", + "OBS_INCLUDE(0)\n", + "L0 *= rec[49]\n", + "\n", + "\n", + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "make_color_code_circuit(\n", + " obs_basis='Y',\n", + " base_data_width=3,\n", + " rounds=7,\n", + " noise_strength=1e-3,\n", + ").diagram(\"timeline\")" + ] + }, + { + "cell_type": "markdown", + "id": "a0b25005-68b5-436f-a871-9fd4e03d4091", + "metadata": {}, + "source": [ + "You can also make a \"detslice\" diagram, which shows stabilizers of the circuit from moment to moment.\n", + "It's called \"det\" slice because the stabilizers that are shown correspond to the sensitivity regions of the detectors declared by the circuit.\n", + "For a color code, this means the detslice diagram looks like a color code.\n", + "(The shapes will all have the same color, instead of a three coloring, because in the diagram the color indicates the basis being checked and all the shapes use the same basis)." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "4d1bb1c3-7fae-423f-8fc6-0e58363863bd", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\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", + "\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", + "\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", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "\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", + "\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", + "\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", + "\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", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "make_color_code_circuit(\n", + " obs_basis='Y',\n", + " base_data_width=3,\n", + " rounds=7,\n", + " noise_strength=1e-3,\n", + ").diagram(\"detslice\")" + ] + }, + { + "cell_type": "markdown", + "id": "7cff2307-35bb-4276-9997-3c394fe953eb", + "metadata": {}, + "source": [ + "\n", + "# Decoding shots from your circuit with Chromobius\n", + "\n", + "Now that you can make color code circuits, you can make a circuit to sample and decode shots from." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "68c20917-6f02-46c9-997e-873c9b27a604", + "metadata": {}, + "outputs": [], + "source": [ + "circuit = make_color_code_circuit(\n", + " obs_basis='X',\n", + " base_data_width=7,\n", + " rounds=5,\n", + " noise_strength=1e-2,\n", + ")\n", + "sampler = circuit.compile_detector_sampler()" + ] + }, + { + "cell_type": "markdown", + "id": "2c789935-4f12-413a-b6cc-5fcb230295e9", + "metadata": {}, + "source": [ + "To configure Chromobius, you need the detector error model (the \"dem\") of the circuit.\n", + "A dem is a representation of the circuit's \"[Tanner graph](https://en.wikipedia.org/wiki/Tanner_graph)\", which describes all error mechanisms and their symptoms.\n", + "This abstracts away all of the circuit-y details that a decoder doesn't want to have to care about.\n", + "\n", + "You can get the circuit's dem with `circuit.detector_error_model()`.\n", + "You can make diagrams of dems using their diagram method.\n", + "For example, the `matchgraph-svg` diagram is a picture of the decoding graph.\n", + "\n", + "Each node in a matchgraph diagram is a detector, and each edge is an error.\n", + "The color code decoding graph is interesting in that it has hyper edges; errors with three symptoms instead of one or two.\n", + "In the diagram these are shown by blue lines converging to a common midpoint from all three symptoms.\n", + "Since the circuit has multiple rounds, the diagram shows multiple layers of nodes." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "dc7cc10b-1817-49e9-abed-21040afdb146", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\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", + "\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", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "\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", + "\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", + "\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", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dem = circuit.detector_error_model()\n", + "dem.diagram(\"matchgraph-svg\")" + ] + }, + { + "cell_type": "markdown", + "id": "1bd4f391-397d-4ce4-a97d-a463297118f0", + "metadata": {}, + "source": [ + "You can also get a 3d model of the graph using the `matchgraph-3d` diagram type.\n", + "(If you're viewing this notebook on github, the 3d viewer won't show up.\n", + "If it does show up, you can click and drag to move the view around.)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "bcc02e51-d0f7-43c2-ad1e-27f89409f2bc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "{\"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\":468,\"max\":[46.0785331726074,34.6817970275879,19.4751358032227],\"min\":[0.0817275047302246,-3.8176417350769,-1.47513675689697],\"name\":\"buf_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":2,\"byteOffset\":0,\"componentType\":5126,\"count\":210,\"max\":[41.8868141174316,33.8922309875488,19.8790016174316],\"min\":[-3.65077877044678,-4.29351329803467,-1.87900161743164],\"name\":\"buf_red_scattered_lines\",\"type\":\"VEC3\"},{\"bufferView\":3,\"byteOffset\":0,\"componentType\":5126,\"count\":2880,\"max\":[37.4444427490234,24.9166660308838,15],\"min\":[4.5,1.5,3],\"name\":\"buf_blue_scattered_lines\",\"type\":\"VEC3\"}],\"asset\":{\"version\":\"2.0\"},\"bufferViews\":[{\"buffer\":0,\"byteLength\":204,\"byteOffset\":0,\"name\":\"circle_loop\",\"target\":34962},{\"buffer\":1,\"byteLength\":5616,\"byteOffset\":0,\"name\":\"buf_scattered_lines\",\"target\":34962},{\"buffer\":2,\"byteLength\":2520,\"byteOffset\":0,\"name\":\"buf_red_scattered_lines\",\"target\":34962},{\"buffer\":3,\"byteLength\":34560,\"byteOffset\":0,\"name\":\"buf_blue_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\":5616,\"name\":\"buf_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,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\"},{\"byteLength\":2520,\"name\":\"buf_red_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,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\"},{\"byteLength\":34560,\"name\":\"buf_blue_scattered_lines\",\"uri\":\"data:application/octet-stream;base64,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HMchQauqwkAAABBBHMc5QVZVVUAAABBBHMchQauqwkAAABBBAAAoQQAAEEEAABBBx3EwQaqq/kAAABBBOY4DQVVVvUAAABBBx3EwQaqq/kAAABBBAAAoQQAAEEEAABBBx3EwQaqq/kAAABBBjuM4QVZV3UAAABBBx3EwQaqq/kAAABBBVlVdQQAAIEEAABBByHF0Qauq2kAAABBBHMc5QVZVVUAAABBByHF0Qauq2kAAABBBAAAoQQAAEEEAABBByHF0Qauq2kAAABBBHMeVQVZV1UAAABBByHF0Qauq2kAAABBBchxvQaqqikAAABBByHF0Qauq2kAAABBBVlVdQQAAIEEAABBByHF0Qauq2kAAABBBxnGwQVZV9UAAABBBHMdZQauqykAAABBBHMc5QVZVVUAAABBBHMdZQauqykAAABBBAAAoQQAAEEEAABBBHMdZQauqykAAABBBHMeVQVZV1UAAABBB5DiKQauqikAAABBBHMc5QVZVVUAAABBB5DiKQauqikAAABBBAACEQQAAwD8AABBB5DiKQauqikAAABBBHMeVQVZV1UAAABBB5DiKQauqikAAABBBchxvQaqqikAAABBB5DiKQauqikAAABBBq6qeQQAAIEAAABBB5DiKQauqikAAABBBxnGwQVZV9UAAABBBHMd5QVVVdUAAABBBHMc5QVZVVUAAABBBHMd5QVVVdUAAABBBAACEQQAAwD8AABBBHMd5QVVVdUAAABBBHMeVQVZV1UAAABBBOo57QaqqOkAAABBBHMc5QVZVVUAAABBBOo57QaqqOkAAABBBAACEQQAAwD8AABBBOo57QaqqOkAAABBBchxvQaqqikAAABBBOo57QaqqOkAAABBBq6qeQQAAIEAAABBBxXF8QVVVSUEAABBBAAAoQQAAEEEAABBBxXF8QVVVSUEAABBBOY5jQauqbkEAABBBxXF8QVVVSUEAABBBjuOMQVZVRUEAABBBxXF8QVVVSUEAABBBVlVdQQAAIEEAABBBxXF8QVVVSUEAABBBxnGMQaqqfkEAABBBxXF8QVVVSUEAABBBOY6nQVZVVUEAABBBHMdhQVVVQUEAABBBAAAoQQAAEEEAABBBHMdhQVVVQUEAABBBOY5jQauqbkEAABBBHMdhQVVVQUEAABBBjuOMQVZVRUEAABBBx3FgQVZVR0EAABBB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AACEQQAAkEEAABBB4ziqQauqqkEAABBBHMehQVZVv0EAABBB4ziqQauqqkEAABBBjuOwQauqpEEAABBB4ziqQauqqkEAABBBq6qeQQAAmEEAABBB4ziqQauqqkEAABBBxnG8QVVVx0EAABBB4ziqQauqqkEAABBBOY7LQauqrEEAABBBjuOcQauqpkEAABBBAACEQQAAkEEAABBBjuOcQauqpkEAABBBHMehQVZVv0EAABBBjuOcQauqpkEAABBBjuOwQauqpEEAABBB5DigQauqq0EAABBBAACEQQAAkEEAABBB5DigQauqq0EAABBBHMehQVZVv0EAABBB5DigQauqq0EAABBBq6qeQQAAmEEAABBB5DigQauqq0EAABBBxnG8QVVVx0EAABBB5Di2QauqlEEAABBBAACEQQAAkEEAABBB5Di2QauqlEEAABBBHMfFQauqekEAABBB5Di2QauqlEEAABBBjuOwQauqpEEAABBB5Di2QauqlEEAABBBq6qeQQAAmEEAABBB5Di2QauqlEEAABBByHHgQVVVhUEAABBB5Di2QauqlEEAABBBOY7LQauqrEEAABBBjuOoQauqkEEAABBBAACEQQAAkEEAABBBjuOoQauqkEEAABBBHMfFQauqekEAABBBjuOoQauqkEEAABBBjuOwQauqpEEAABBBqqq2QQAAtkEAABBBHMehQVZVv0EAABBBqqq2QQAAtkEAABBBjuOwQauqpEEAABBBqqq2QQAAtkEAABBBxnG8QVVVx0EAABBBqqq2QQAAtkEAABBBOY7LQauqrEEAABBB4zjaQauq2kAAABBBjuO8QVZVVUAAABBB4zjaQauq2kAAABBBAAC0QQAAEEEAABBB4zjaQauq2kAAABBBHMf1QVZV1UAAABBB4zjaQauq2kAAABBBOY7XQaqqikAAABBB4zjaQauq2kAAABBBqqrOQQAAIEEAABBB4zjaQauq2kAAABBB5DgIQlZV9UAAABBBjePMQauqykAAABBBjuO8QVZVVUAAABBBjePMQauqykAAABBBAAC0QQAAEEEAABBBjePMQauqykAAABBBHMf1QVZV1UAAABBB4zjqQauqikAAABBBjuO8QVZVVUAAABBB4zjqQauqikAAABBBAADkQQAAwD8AABBB4zjqQauqikAAABBBHMf1QVZV1UAAABBB4zjqQauqikAAABBBOY7XQaqqikAAABBB4zjqQauqikAAABBBqqr+QQAAIEAAABBB4zjqQauqikAAABBB5DgIQlZV9UAAABBBjePcQVVVdUAAABBBjuO8QVZVVUAAABBBjePcQVVVdUAAABBBAADkQQAAwD8AABBBjePcQVVVdUAAABBBHMf1QVZV1UAAABBBHMfdQaqqOkAAABBBjuO8QVZVVUAAABBBHMfdQaqqOkAAABBBAADkQQAAwD8AABBBHMfdQaqqOkAAABBBOY7XQaqqikAAABBBHMfdQaqqOkAAABBBqqr+QQAAIEAAABBB4zjWQVVVSUEAABBBAAC0QQAAEEEAABBB4zjWQVVVSUEAABBBHMfFQauqekEAABBB4zjWQVVVSUEAABBBjuPgQVZVOUEAABBB4zjWQVVVSUEAABBBqqrOQQAAIEEAABBB4zjWQVVVSUEAABBByHHgQVVVhUEAABBB4zjWQVVVSUEAABBBOY77QVZVSUEAABBBjePIQVVVQUEAABBBAAC0QQAAEEEAABBBjePIQVVVQUEAABBBHMfFQauqekEAABBBjePIQVVVQUEAABBBjuPgQVZVOUEAABBB4zjmQVVVGUEAABBBAAC0QQAAEEEAABBB4zjmQVVVGUEAABBBHMf1QVZV1UAAABBB4zjmQVVVGUEAABBBjuPgQVZVOUEAABBB4zjmQVVVGUEAABBBqqrOQQAAIEEAABBB4zjmQVVVGUEAABBB5DgIQlZV9UAAABBB4zjmQVVVGUEAABBBOY77QVZVSUEAABBBjePYQVVVEUEAABBBAAC0QQAAEEEAABBBjePYQVVVEUEAABBBHMf1QVZV1UAAABBBjePYQVVVEUEAABBBjuPgQVZVOUEAABBBqqrIQQAAlUEAABBBHMfFQauqekEAABBBqqrIQQAAlUEAABBBjuOwQauqpEEAABBBqqrIQQAAlUEAABBByHHgQVVVhUEAABBBqqrIQQAAlUEAABBBOY7LQauqrEEAABBBqqrgQQAAYkEAABBBHMfFQauqekEAABBBqqrgQQAAYkEAABBBjuPgQVZVOUEAABBBqqrgQQAAYkEAABBByHHgQVVVhUEAABBBqqrgQQAAYkEAABBBOY77QVZVSUEAABBBcRwDQquqgkAAABBBAADkQQAAwD8AABBBcRwDQquqgkAAABBBHMf1QVZV1UAAABBBcRwDQquqgkAAABBBx3EIQlVVJUAAABBBcRwDQquqgkAAABBBqqr+QQAAIEAAABBBcRwDQquqgkAAABBB5DgIQlZV9UAAABBBcRwDQquqgkAAABBBHMcVQlVVZUAAABBBjeP4QVVVZUAAABBBAADkQQAAwD8AABBBjeP4QVVVZUAAABBBHMf1QVZV1UAAABBBjeP4QVVVZUAAABBBx3EIQlVVJUAAABBBjuMDQqqqIkAAABBBAADkQQAAwD8AABBBjuMDQqqqIkAAABBBx3EIQlVVJUAAABBBjuMDQqqqIkAAABBBqqr+QQAAIEAAABBBjuMDQqqqIkAAABBBHMcVQlVVZUAAABBBqqr4QQAAGkEAABBBHMf1QVZV1UAAABBBqqr4QQAAGkEAABBBjuPgQVZVOUEAABBBqqr4QQAAGkEAABBB5DgIQlZV9UAAABBBqqr4QQAAGkEAABBBOY77QVZVSUEAABBBVVUIQgEApEAAABBBHMf1QVZV1UAAABBBVVUIQgEApEAAABBBx3EIQlVVJUAAABBBVVUIQgEApEAAABBB5DgIQlZV9UAAABBBVVUIQgEApEAAABBBHMcVQlVVZUAAABBBcxw3QauqkkAAABBBq6r6QAAAIEAAABBBcxw3QauqkkAAABBBjuM4QVZV3UAAABBBcxw3QauqkkAAABBBchxvQaqqikAAABBBcxxXQauq4kAAABBBjuM4QVZV3UAAABBBcxxXQauq4kAAABBBchxvQaqqikAAABBBcxxXQauq4kAAABBBVlVdQQAAIEEAABBBOY6HQauq6kAAABBBchxvQaqqikAAABBBOY6HQauq6kAAABBBVlVdQQAAIEEAABBBOY6HQauq6kAAABBBxnGwQVZV9UAAABBBOY6XQauqmkAAABBBchxvQaqqikAAABBBOY6XQauqmkAAABBBq6qeQQAAIEAAABBBOY6XQauqmkAAABBBxnGwQVZV9UAAABBBOY6LQVVVUUEAABBBVlVdQQAAIEEAABBBOY6LQVVVUUEAABBBxnGMQaqqfkEAABBBOY6LQVVVUUEAABBBOY6nQVZVVUEAABBBOI6XQVZVJUEAABBBVlVdQQAAIEEAABBBOI6XQVZVJUEAABBBxnGwQVZV9UAAABBBOI6XQVZVJUEAABBBOY6nQVZVVUEAABBBOY6bQauqgEEAABBBxnGMQaqqfkEAABBBOY6bQauqgEEAABBBOY6nQVZVVUEAABBBOY6bQauqgEEAABBBq6qeQQAAmEEAABBBOI63QauqmkAAABBBq6qeQQAAIEAAABBBOI63QauqmkAAABBBxnGwQVZV9UAAABBBOI63QauqmkAAABBBOY7XQaqqikAAABBBOI63QVVVJUEAABBBxnGwQVZV9UAAABBBOI63QVVVJUEAABBBOY6nQVZVVUEAABBBOI63QVVVJUEAABBBqqrOQQAAIEEAABBBOI7HQauq6kAAABBBxnGwQVZV9UAAABBBOI7HQauq6kAAABBBOY7XQaqqikAAABBBOI7HQauq6kAAABBBqqrOQQAAIEEAABBBOY63QauqgkEAABBBOY6nQVZVVUEAABBBOY63QauqgkEAABBBq6qeQQAAmEEAABBBOY63QauqgkEAABBByHHgQVVVhUEAABBBOY7HQVVVVUEAABBBOY6nQVZVVUEAABBBOY7HQVVVVUEAABBBqqrOQQAAIEEAABBBOY7HQVVVVUEAABBByHHgQVVVhUEAABBBOI63QauqrkEAABBBq6qeQQAAmEEAABBBOI63QauqrkEAABBBxnG8QVVVx0EAABBBOI63QauqrkEAABBBOY7LQauqrEEAABBBOY7DQauqmEEAABBBq6qeQQAAmEEAABBBOY7DQauqmEEAABBByHHgQVVVhUEAABBBOY7DQauqmEEAABBBOY7LQauqrEEAABBBOY7nQauq6kAAABBBOY7XQaqqikAAABBBOY7nQauq6kAAABBBqqrOQQAAIEEAABBBOY7nQauq6kAAABBB5DgIQlZV9UAAABBBOY73QauqmkAAABBBOY7XQaqqikAAABBBOY73QauqmkAAABBBqqr+QQAAIEAAABBBOY73QauqmkAAABBB5DgIQlZV9UAAABBBOY7jQVVVUUEAABBBqqrOQQAAIEEAABBBOY7jQVVVUUEAABBByHHgQVVVhUEAABBBOY7jQVVVUUEAABBBOY77QVZVSUEAABBBOY7zQVZVIUEAABBBqqrOQQAAIEEAABBBOY7zQVZVIUEAABBB5DgIQlZV9UAAABBBOY7zQVZVIUEAABBBOY77QVZVSUEAABBBHMcJQquqkkAAABBBqqr+QQAAIEAAABBBHMcJQquqkkAAABBB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\"}],\"materials\":[{\"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},\"material\":0,\"mode\":6}]},{\"primitives\":[{\"attributes\":{\"POSITION\":1},\"material\":1,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":2},\"material\":2,\"mode\":1}]},{\"primitives\":[{\"attributes\":{\"POSITION\":3},\"material\":3,\"mode\":1}]}],\"nodes\":[{\"mesh\":0,\"translation\":[4.5,1.5,3]},{\"mesh\":0,\"translation\":[8.22222,5.91667,3]},{\"mesh\":0,\"translation\":[11.6111,3.33333,3]},{\"mesh\":0,\"translation\":[10.5,9,3]},{\"mesh\":0,\"translation\":[14.2222,14.9167,3]},{\"mesh\":0,\"translation\":[16.5,1.5,3]},{\"mesh\":0,\"translation\":[18.7222,6.66667,3]},{\"mesh\":0,\"translation\":[17.6111,12.3333,3]},{\"mesh\":0,\"translation\":[16.5,18,3]},{\"mesh\":0,\"translation\":[20.2222,23.9167,3]},{\"mesh\":0,\"translation\":[23.6111,3.33333,3]},{\"mesh\":0,\"translation\":[22.5,9,3]},{\"mesh\":0,\"translation\":[24.7222,15.6667,3]},{\"mesh\":0,\"translation\":[22.1111,20.5833,3]},{\"mesh\":0,\"translation\":[28.5,1.5,3]},{\"mesh\":0,\"translation\":[30.7222,6.66667,3]},{\"mesh\":0,\"translation\":[28.1111,11.5833,3]},{\"mesh\":0,\"translation\":[34.1111,2.58333,3]},{\"mesh\":0,\"translation\":[7.83333,2.5,3]},{\"mesh\":0,\"translation\":[11.5556,6.91667,3]},{\"mesh\":0,\"translation\":[14.9444,4.33333,3]},{\"mesh\":0,\"translation\":[13.8333,10,3]},{\"mesh\":0,\"translation\":[17.5556,15.9167,3]},{\"mesh\":0,\"translation\":[19.8333,2.5,3]},{\"mesh\":0,\"translation\":[22.0556,7.66667,3]},{\"mesh\":0,\"translation\":[20.9444,13.3333,3]},{\"mesh\":0,\"translation\":[19.8333,19,3]},{\"mesh\":0,\"translation\":[23.5556,24.9167,3]},{\"mesh\":0,\"translation\":[26.9444,4.33333,3]},{\"mesh\":0,\"translation\":[25.8333,10,3]},{\"mesh\":0,\"translation\":[28.0556,16.6667,3]},{\"mesh\":0,\"translation\":[25.4444,21.5833,3]},{\"mesh\":0,\"translation\":[31.8333,2.5,3]},{\"mesh\":0,\"translation\":[34.0556,7.66667,3]},{\"mesh\":0,\"translation\":[31.4444,12.5833,3]},{\"mesh\":0,\"translation\":[37.4444,3.58333,3]},{\"mesh\":0,\"translation\":[4.5,1.5,6]},{\"mesh\":0,\"translation\":[8.22222,5.91667,6]},{\"mesh\":0,\"translation\":[11.6111,3.33333,6]},{\"mesh\":0,\"translation\":[10.5,9,6]},{\"mesh\":0,\"translation\":[14.2222,14.9167,6]},{\"mesh\":0,\"translation\":[16.5,1.5,6]},{\"mesh\":0,\"translation\":[18.7222,6.66667,6]},{\"mesh\":0,\"translation\":[17.6111,12.3333,6]},{\"mesh\":0,\"translation\":[16.5,18,6]},{\"mesh\":0,\"translation\":[20.2222,23.9167,6]},{\"mesh\":0,\"translation\":[23.6111,3.33333,6]},{\"mesh\":0,\"translation\":[22.5,9,6]},{\"mesh\":0,\"translation\":[24.7222,15.6667,6]},{\"mesh\":0,\"translation\":[22.1111,20.5833,6]},{\"mesh\":0,\"translation\":[28.5,1.5,6]},{\"mesh\":0,\"translation\":[30.7222,6.66667,6]},{\"mesh\":0,\"translation\":[28.1111,11.5833,6]},{\"mesh\":0,\"translation\":[34.1111,2.58333,6]},{\"mesh\":0,\"translation\":[7.83333,2.5,6]},{\"mesh\":0,\"translation\":[11.5556,6.91667,6]},{\"mesh\":0,\"translation\":[14.9444,4.33333,6]},{\"mesh\":0,\"translation\":[13.8333,10,6]},{\"mesh\":0,\"translation\":[17.5556,15.9167,6]},{\"mesh\":0,\"translation\":[19.8333,2.5,6]},{\"mesh\":0,\"translation\":[22.0556,7.66667,6]},{\"mesh\":0,\"translation\":[20.9444,13.3333,6]},{\"mesh\":0,\"translation\":[19.8333,19,6]},{\"mesh\":0,\"translation\":[23.5556,24.9167,6]},{\"mesh\":0,\"translation\":[26.9444,4.33333,6]},{\"mesh\":0,\"translation\":[25.8333,10,6]},{\"mesh\":0,\"translation\":[28.0556,16.6667,6]},{\"mesh\":0,\"translation\":[25.4444,21.5833,6]},{\"mesh\":0,\"translation\":[31.8333,2.5,6]},{\"mesh\":0,\"translation\":[34.0556,7.66667,6]},{\"mesh\":0,\"translation\":[31.4444,12.5833,6]},{\"mesh\":0,\"translation\":[37.4444,3.58333,6]},{\"mesh\":0,\"translation\":[4.5,1.5,9]},{\"mesh\":0,\"translation\":[8.22222,5.91667,9]},{\"mesh\":0,\"translation\":[11.6111,3.33333,9]},{\"mesh\":0,\"translation\":[10.5,9,9]},{\"mesh\":0,\"translation\":[14.2222,14.9167,9]},{\"mesh\":0,\"translation\":[16.5,1.5,9]},{\"mesh\":0,\"translation\":[18.7222,6.66667,9]},{\"mesh\":0,\"translation\":[17.6111,12.3333,9]},{\"mesh\":0,\"translation\":[16.5,18,9]},{\"mesh\":0,\"translation\":[20.2222,23.9167,9]},{\"mesh\":0,\"translation\":[23.6111,3.33333,9]},{\"mesh\":0,\"translation\":[22.5,9,9]},{\"mesh\":0,\"translation\":[24.7222,15.6667,9]},{\"mesh\":0,\"translation\":[22.1111,20.5833,9]},{\"mesh\":0,\"translation\":[28.5,1.5,9]},{\"mesh\":0,\"translation\":[30.7222,6.66667,9]},{\"mesh\":0,\"translation\":[28.1111,11.5833,9]},{\"mesh\":0,\"translation\":[34.1111,2.58333,9]},{\"mesh\":0,\"translation\":[7.83333,2.5,9]},{\"mesh\":0,\"translation\":[11.5556,6.91667,9]},{\"mesh\":0,\"translation\":[14.9444,4.33333,9]},{\"mesh\":0,\"translation\":[13.8333,10,9]},{\"mesh\":0,\"translation\":[17.5556,15.9167,9]},{\"mesh\":0,\"translation\":[19.8333,2.5,9]},{\"mesh\":0,\"translation\":[22.0556,7.66667,9]},{\"mesh\":0,\"translation\":[20.9444,13.3333,9]},{\"mesh\":0,\"translation\":[19.8333,19,9]},{\"mesh\":0,\"translation\":[23.5556,24.9167,9]},{\"mesh\":0,\"translation\":[26.9444,4.33333,9]},{\"mesh\":0,\"translation\":[25.8333,10,9]},{\"mesh\":0,\"translation\":[28.0556,16.6667,9]},{\"mesh\":0,\"translation\":[25.4444,21.5833,9]},{\"mesh\":0,\"translation\":[31.8333,2.5,9]},{\"mesh\":0,\"translation\":[34.0556,7.66667,9]},{\"mesh\":0,\"translation\":[31.4444,12.5833,9]},{\"mesh\":0,\"translation\":[37.4444,3.58333,9]},{\"mesh\":0,\"translation\":[4.5,1.5,12]},{\"mesh\":0,\"translation\":[8.22222,5.91667,12]},{\"mesh\":0,\"translation\":[11.6111,3.33333,12]},{\"mesh\":0,\"translation\":[10.5,9,12]},{\"mesh\":0,\"translation\":[14.2222,14.9167,12]},{\"mesh\":0,\"translation\":[16.5,1.5,12]},{\"mesh\":0,\"translation\":[18.7222,6.66667,12]},{\"mesh\":0,\"translation\":[17.6111,12.3333,12]},{\"mesh\":0,\"translation\":[16.5,18,12]},{\"mesh\":0,\"translation\":[20.2222,23.9167,12]},{\"mesh\":0,\"translation\":[23.6111,3.33333,12]},{\"mesh\":0,\"translation\":[22.5,9,12]},{\"mesh\":0,\"translation\":[24.7222,15.6667,12]},{\"mesh\":0,\"translation\":[22.1111,20.5833,12]},{\"mesh\":0,\"translation\":[28.5,1.5,12]},{\"mesh\":0,\"translation\":[30.7222,6.66667,12]},{\"mesh\":0,\"translation\":[28.1111,11.5833,12]},{\"mesh\":0,\"translation\":[34.1111,2.58333,12]},{\"mesh\":0,\"translation\":[7.83333,2.5,12]},{\"mesh\":0,\"translation\":[11.5556,6.91667,12]},{\"mesh\":0,\"translation\":[14.9444,4.33333,12]},{\"mesh\":0,\"translation\":[13.8333,10,12]},{\"mesh\":0,\"translation\":[17.5556,15.9167,12]},{\"mesh\":0,\"translation\":[19.8333,2.5,12]},{\"mesh\":0,\"translation\":[22.0556,7.66667,12]},{\"mesh\":0,\"translation\":[20.9444,13.3333,12]},{\"mesh\":0,\"translation\":[19.8333,19,12]},{\"mesh\":0,\"translation\":[23.5556,24.9167,12]},{\"mesh\":0,\"translation\":[26.9444,4.33333,12]},{\"mesh\":0,\"translation\":[25.8333,10,12]},{\"mesh\":0,\"translation\":[28.0556,16.6667,12]},{\"mesh\":0,\"translation\":[25.4444,21.5833,12]},{\"mesh\":0,\"translation\":[31.8333,2.5,12]},{\"mesh\":0,\"translation\":[34.0556,7.66667,12]},{\"mesh\":0,\"translation\":[31.4444,12.5833,12]},{\"mesh\":0,\"translation\":[37.4444,3.58333,12]},{\"mesh\":0,\"translation\":[4.5,1.5,15]},{\"mesh\":0,\"translation\":[8.22222,5.91667,15]},{\"mesh\":0,\"translation\":[11.6111,3.33333,15]},{\"mesh\":0,\"translation\":[10.5,9,15]},{\"mesh\":0,\"translation\":[14.2222,14.9167,15]},{\"mesh\":0,\"translation\":[16.5,1.5,15]},{\"mesh\":0,\"translation\":[18.7222,6.66667,15]},{\"mesh\":0,\"translation\":[17.6111,12.3333,15]},{\"mesh\":0,\"translation\":[16.5,18,15]},{\"mesh\":0,\"translation\":[20.2222,23.9167,15]},{\"mesh\":0,\"translation\":[23.6111,3.33333,15]},{\"mesh\":0,\"translation\":[22.5,9,15]},{\"mesh\":0,\"translation\":[24.7222,15.6667,15]},{\"mesh\":0,\"translation\":[22.1111,20.5833,15]},{\"mesh\":0,\"translation\":[28.5,1.5,15]},{\"mesh\":0,\"translation\":[30.7222,6.66667,15]},{\"mesh\":0,\"translation\":[28.1111,11.5833,15]},{\"mesh\":0,\"translation\":[34.1111,2.58333,15]},{\"mesh\":0,\"translation\":[7.83333,2.5,15]},{\"mesh\":0,\"translation\":[11.5556,6.91667,15]},{\"mesh\":0,\"translation\":[14.9444,4.33333,15]},{\"mesh\":0,\"translation\":[13.8333,10,15]},{\"mesh\":0,\"translation\":[17.5556,15.9167,15]},{\"mesh\":0,\"translation\":[19.8333,2.5,15]},{\"mesh\":0,\"translation\":[22.0556,7.66667,15]},{\"mesh\":0,\"translation\":[20.9444,13.3333,15]},{\"mesh\":0,\"translation\":[19.8333,19,15]},{\"mesh\":0,\"translation\":[23.5556,24.9167,15]},{\"mesh\":0,\"translation\":[26.9444,4.33333,15]},{\"mesh\":0,\"translation\":[25.8333,10,15]},{\"mesh\":0,\"translation\":[28.0556,16.6667,15]},{\"mesh\":0,\"translation\":[25.4444,21.5833,15]},{\"mesh\":0,\"translation\":[31.8333,2.5,15]},{\"mesh\":0,\"translation\":[34.0556,7.66667,15]},{\"mesh\":0,\"translation\":[31.4444,12.5833,15]},{\"mesh\":0,\"translation\":[37.4444,3.58333,15]},{\"mesh\":1,\"translation\":[0,0,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,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]}]}" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dem.diagram(\"matchgraph-3d\")" + ] + }, + { + "cell_type": "markdown", + "id": "5460fabd-195c-4f5c-a12e-3146404637b8", + "metadata": {}, + "source": [ + "Anyways, putting the cool 3d model viewer aside, now that you have the dem you can use it to configure Chromobius.\n", + "You do this by calling `chromobius.compile_decoder_for_dem`, like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "e822b618-81b7-4d9e-b062-5740d57a3a7f", + "metadata": {}, + "outputs": [], + "source": [ + "decoder = chromobius.compile_decoder_for_dem(dem)" + ] + }, + { + "cell_type": "markdown", + "id": "f1cc5417-681f-4105-8964-66fa7d558dd0", + "metadata": {}, + "source": [ + "With the decoder in hand, you can take detector shots from the circuit and have Chromobius predict whether or not the logical observable was flipped.\n", + "The method for doing this is `predict_obs_flips_from_dets_bit_packed`.\n", + "The `bit_packed` means each byte of data given to it must contain 8 bits of data, instead of only 1 bit per byte.\n", + "You can get bit packed detection events from stim samplers by passing `bit_packed=True`.\n", + "If you have unbitpacked data, you can pack it by using [`np.packbits(data, bitorder='little')`](https://numpy.org/doc/stable/reference/generated/numpy.packbits.html)\n", + "\n", + "After Chromobius makes its predictions, you can compare them to the actual observable flips and count how many times Chromobius made a mistake:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "98e3f2b1-7521-4b88-ae0a-95978152abef", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mistakes=0\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "dets, actual_obs = sampler.sample(\n", + " shots=1024,\n", + " separate_observables=True,\n", + " bit_packed=True,\n", + ")\n", + "\n", + "predicted_obs = decoder.predict_obs_flips_from_dets_bit_packed(dets)\n", + "\n", + "mistakes = np.count_nonzero(np.any(predicted_obs != actual_obs, axis=1))\n", + "print(f'{mistakes=}')" + ] + }, + { + "cell_type": "markdown", + "id": "ee7500f3-0a07-479f-be0f-1b7451302d02", + "metadata": {}, + "source": [ + "1024 shots isn't really enough to get a sense of the error rate for this circuit.\n", + "It's possible you didn't even see one mistake.\n", + "Try taking a hundred times as many shots:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "8feab0c7-cba5-4030-89fb-cc5b6cd08394", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " shots = 102400\n", + " mistakes = 28\n", + " error_rate = 0.027344%\n", + "shots/second = 89627\n" + ] + } + ], + "source": [ + "import time\n", + "\n", + "t0 = time.monotonic()\n", + "total_shots = 0\n", + "total_mistakes = 0\n", + "for _ in range(100):\n", + " total_shots += 1024\n", + " dets, actual_obs = sampler.sample(\n", + " shots=1024,\n", + " separate_observables=True,\n", + " bit_packed=True,\n", + " )\n", + " predicted_obs = decoder.predict_obs_flips_from_dets_bit_packed(dets)\n", + " total_mistakes += np.count_nonzero(np.any(predicted_obs != actual_obs, axis=1))\n", + "t1 = time.monotonic()\n", + "\n", + "print(f' shots = {total_shots}')\n", + "print(f' mistakes = {total_mistakes}')\n", + "print(f' error_rate = {total_mistakes / total_shots:%}')\n", + "print(f'shots/second = {round(total_shots / (t1 - t0))}')" + ] + }, + { + "cell_type": "markdown", + "id": "92965b1e-abf4-4e59-a163-9df20e7811c0", + "metadata": {}, + "source": [ + "Nice! Pretty quick, right? But you probably don't want to have to deal with all this batching and collecting and timing stuff (nevermind multiprocessing!). That's what `sinter` is for." + ] + }, + { + "cell_type": "markdown", + "id": "cebf42c7-7b8d-4c54-bd98-a0637a2ef407", + "metadata": {}, + "source": [ + "\n", + "# Using Sinter to collect and plot statistics\n", + "\n", + "Sinter is a tool for performing bulk Monte Carlo sampling of quantum error correction circuits using python multiprocessing.\n", + "Like Chromobius, you can install `sinter` using `pip`:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "4f62876b-cefa-4dc1-bc83-f6e0df111cfa", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install sinter~=1.12 --quiet" + ] + }, + { + "cell_type": "markdown", + "id": "58a16293-eceb-426d-bbfa-2e98cf4712b9", + "metadata": {}, + "source": [ + "To get sinter to sample and decode circuits, you need to wrap the circuits into `sinter.Task`s that provide metadata about the circuits.\n", + "This metadata will be useful later, when plotting.\n", + "Typically you want to explore a variety of circuit sizes and noise strengths.\n", + "Try defining a list of sinter tasks for a variety of sizes and noise strengths:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "e0e7d670-4461-463b-80be-270f3766669f", + "metadata": {}, + "outputs": [], + "source": [ + "import sinter\n", + "\n", + "tasks = [\n", + " sinter.Task(\n", + " circuit=make_color_code_circuit(\n", + " obs_basis=b,\n", + " base_data_width=d,\n", + " rounds=r,\n", + " noise_strength=p,\n", + " ),\n", + " json_metadata={'d': d, 'p': p, 'r': r, 'b': b},\n", + " )\n", + " for d in [3, 5, 7, 9]\n", + " for r in [d*4]\n", + " for b in ['X']\n", + " for p in [0.01, 0.02]\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "521f7f3e-b816-4633-b103-79cdb325d7fe", + "metadata": {}, + "source": [ + "Once you have your tasks, you call `sinter.collect` on them to perform sampling.\n", + "You also need to specify how many shots to take from each task, how many errors need to be seen before sampling can stop early, how many worker processes to use, and what decoders to use.\n", + "You want to use chromobius, so you should set the decoders to `['chromobius']`.\n", + "Because chromobius isn't one of sinter's built in decoders, you also have to tell it what `'chomobius'` means.\n", + "You do that by giving a dictionary to the `custom_decoders` argument mapping strings to instances of `sinter.Decoder`.\n", + "For convenience, the `chromobius.sinter_decoders()` method returns this dictionary.\n", + "\n", + "You can specify `print_progress=True` to get progress updates.\n", + "Collecting these stats should take less than a minute." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "4db774f3-638b-4520-b3d5-5ef0453455f4", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[31mStarting 12 workers...\u001b[0m\n", + "\u001b[31m4 cases left:\n", + " chromobius processes=5 ~core_mins_left=1 shots_left=95200 errors_left=80 {b=X,d=7,p=0.01,r=28}\n", + " chromobius processes=1 ~core_mins_left=1 shots_left=97452 errors_left=27 {b=X,d=7,p=0.02,r=28}\n", + " chromobius processes=4 ~core_mins_left=2 shots_left=99400 errors_left=100 {b=X,d=9,p=0.01,r=36}\n", + " chromobius processes=2 ~core_mins_left=4 shots_left=99900 errors_left=100 {b=X,d=9,p=0.02,r=36}\u001b[0m\n", + "\u001b[31m3 cases left:\n", + " chromobius processes=2 ~core_mins_left=1 shots_left=68299 errors_left=15 {b=X,d=7,p=0.01,r=28}\n", + " chromobius processes=5 ~core_mins_left=1 shots_left=95200 errors_left=100 {b=X,d=9,p=0.01,r=36}\n", + " chromobius processes=3 ~core_mins_left=1 shots_left=99400 errors_left=91 {b=X,d=9,p=0.02,r=36}\u001b[0m\n", + "\u001b[31m2 cases left:\n", + " chromobius processes=5 ~core_mins_left=1 shots_left=89200 errors_left=96 {b=X,d=9,p=0.01,r=36}\n", + " chromobius processes=1 ~core_mins_left=1 shots_left=95319 errors_left=34 {b=X,d=9,p=0.02,r=36}\u001b[0m\n", + "\u001b[31m2 cases left:\n", + " chromobius processes=5 ~core_mins_left=1 shots_left=78400 errors_left=94 {b=X,d=9,p=0.01,r=36}\n", + " chromobius processes=1 ~core_mins_left=1 shots_left=95319 errors_left=34 {b=X,d=9,p=0.02,r=36}\u001b[0m\n", + "\u001b[31m1 cases left:\n", + " chromobius processes=3 ~core_mins_left=1 shots_left=67200 errors_left=89 {b=X,d=9,p=0.01,r=36}\u001b[0m\n", + "\u001b[31m1 cases left:\n", + " chromobius processes=2 ~core_mins_left=1 shots_left=52800 errors_left=80 {b=X,d=9,p=0.01,r=36}\u001b[0m\n", + "\u001b[31m1 cases left:\n", + " chromobius processes=1 ~core_mins_left=1 shots_left=31200 errors_left=75 {b=X,d=9,p=0.01,r=36}\u001b[0m\n", + "\u001b[31mDone collecting\u001b[0m\n" + ] + } + ], + "source": [ + "import os\n", + "\n", + "stats = sinter.collect(\n", + " tasks=tasks,\n", + " num_workers=os.cpu_count(),\n", + " max_shots=100_000,\n", + " max_errors=100,\n", + " print_progress=True,\n", + " decoders=['chromobius'],\n", + " custom_decoders=chromobius.sinter_decoders(),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "baf78849-79e1-4b40-a5d7-8058712b6ab1", + "metadata": {}, + "source": [ + "Now you have statistics describing how often each circuit experienced a logical error, when decoded using Chromobius.\n", + "To plot these statistics, you can use `matplotlib`.\n", + "You can iterate over the list of stats yourself, but it's usually more convenient to use sinter's `sinter.plot_error_rate` helper method.\n", + "It will split the statistics into curves according to a grouping function you provide, lay out those curves over the X axis using an X function you provide, and set the Y coordinate to the error rate.\n", + "It will also give uncertainty highlights indicating hypotheses with likelihoods near the max likelihood hypothesis." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "e7accd35-3cb5-43fb-8d5f-fded2b8ba73f", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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87zku8zYJFVi8NDq9v1qHro223m/klfsUVMoOpvUAK67+kQsPLBj/yprJow8UT1A/Twat+4LjJvL922266hTj13vqh+b09R84u4qFGUL93W9+zrjz+7bODXafWkroNaADnaAt0lt72y0qkGx2bWvDJslfXA1TBHiIOL6zh6Lpe5Kyfjx43v+rtFoCIVC1NTUSBAshjWtVkO2w0S2w8SorDD1ngC1bX5aOkM0dQRJsxhwWQ39Tlc4mKOZKpHtMFGUoe5jqPcE+bSylQybkXyXhXyXmQypKjH4aLX7fo3voqssmG+/vGK3eoQ6oaOrAkVHHXQ61HJhetPgWb002qFopnqAmgPdXK7mEzduVgPksE99LNAGlR+rB6ipIGaXuiJ+OCOOh4zR8Y1TZ9hX9aP76x3sgNZmtQybyaEGxbZstQybJR1MLinDJgadQb284fV6ueeee1izZg1r167F7XazdOlSrrzyygOuDQaD3HbbbTz11FO43W6mTJnCr371K04//fR+3//aa69l6dKlBAIBzjzzTI455pg4PhshUovDbMBhNjAi00pje5C6Nj+NPakSejKGaqoEakBUmGYh226m1ReisaONyhYjOc7uqhImDDr5D31Q0mj2dakjXz0XDqgBsafrNwbd1RG8DWq7ZL1p32qxwTJ4mnjojJA7WT1ATQVpq9yvs91mNcAHdUNh2P/1r3nspYkdY6+vN/uVYWvtKsNm6irDltZ7ldggm+bFwIs7CF62bBn33Xcfn332GR6P56CbSqLRaL9eu7m5mTvvvJMRI0Zw7LHH8v777x/y2iuvvJIXXniBG264gdLSUp544gnOPPNMVqxYwdy5c/t1/0ceeYQ//vGPvP/++2zatElWgIQ4CJNed8hUCQXIGMKpEhajjkKjhUg0htsXZnt9B9WtPrIcpp7VYUmVGAIMZvVIH6F+XDwbRo9QV1MD7V2d7TrVgLK9Vk256AmKrYNrs13GaPWYcI66CttRt6+rXeNmdfyHYs2Ell1qQPp1G+36Pcb9yrApivpDRrBDDd5bd+9Xhi0LbF1l2MyuwfM1FsNKXN+9X3zxRS666CImTZrEJZdcwqOPPspll12Goii8+uqrlJaWct555/X79fPz86mrqyMvL4/169cfstLE2rVrefbZZ7nnnnv4yU9+AsAVV1zB5MmTuemmm/j44497rp07dy6r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9957j507dw7waEQiydymLpnb1CVzm7q6Y6hgMJj4F1eGiHXr1imAsnTp0gMemzRpkjJ//vwDzm/evFkBlD/96U99vp/b7VbOP/98xW63KyNHjlT+/Oc/H/b622+/XQHkkEMOOeSQQw455Ejw8cQTT/Q5lvs6KbES7Pf7MZlMB5w3m809j/dVWloaL7744hFff+2117J48eJe5zZu3Mi3v/1tnn/+eSZOnNjnMYjBa+fOnZx33nm88sorjB07dqCHIxJI5jZ1ydymLpnb1LVlyxYuuugiysrKEv7aKREEWyyWgy6TBwKBnseTLScnh5ycnIM+NnHiRCZNmpT0MYijb+zYsTK3KUrmNnXJ3KYumdvU9dWU10QY1NUhjlR3FYmv6j5XUFBwtIckhBBCCCEGsZQIgqdOnUp5eTnt7e29zncnU0+dOnUARiWEEEIIIQarlAiCL7zwQqLRKI899ljPuWAwyNKlS5k9e3afKkMIIYQQQojUN+hzgh966CHa2tqora0F4LXXXqO6uhqA6667DpfLxezZs1m8eDE333wzjY2NjB07lieffJKKigoef/zxARt7dnY2t99+O9nZ2QM2BpEcMrepS+Y2dcncpi6Z29SVzLnVKIqiJPxVE2jkyJFUVlYe9LE9e/YwcuRIQN0Ed+utt/L000/jdruZMmUKd911F2ecccZRHK0QQgghhBgKBn0QLIQQQgghRKKlRE6wEEIIIYQQfSFBsBBCCCGEGHYkCBZCCCGEEMOOBMFCCCGEEGLYkSA4CYLBID/72c8oKCjAYrEwe/Zs3n777YEelojTunXr+NGPfsSkSZOw2WyMGDGCiy66iPLy8oEemkiCX//612g0GiZPnjzQQxEJ8Nlnn7Fo0SIyMjKwWq1MnjyZBx98cKCHJeK0Y8cOLrnkEoqKirBarYwfP54777wTn8830EMTfeD1ern99ttZsGABGRkZaDQannjiiYNeu3XrVhYsWIDdbicjI4PvfOc7NDU19eu+Uh0iCS699FJeeOEFbrjhBkpLS3niiSdYt24dK1asYO7cuQM9PNFPF154IatWrWLx4sVMmTKF+vp6HnroIbxeL5988okESymkurqacePGodFoGDlyJJs2bRroIYk4vPXWW5xzzjlMmzaNiy++GLvdzq5du4jFYvz+978f6OGJfqqqqmLKlCm4XC5+8IMfkJGRwerVq3niiSdYtGgRr7766kAPURyhiooKRo0axYgRIxg9ejTvv/8+S5cu5corr+x1XXV1NdOmTcPlcnH99dfj9Xq59957GTFiBGvXrsVoNPbtxopIqDVr1iiAcs899/Sc8/v9ypgxY5Tjjz9+AEcm4rVq1SolGAz2OldeXq6YTCbl8ssvH6BRiWS4+OKLlfnz5ysnn3yyMmnSpIEejoiDx+NRcnNzlW9961tKNBod6OGIBPr1r3+tAMqmTZt6nb/iiisUQGltbR2gkYm+CgQCSl1dnaIoirJu3ToFUJYuXXrAdT/84Q8Vi8WiVFZW9px7++23FUD585//3Of7SjpEgr3wwgvodDquueaannNms5mrrrqK1atXU1VVNYCjE/E44YQTDvgps7S0lEmTJrF169YBGpVItA8//JAXXniB+++/f6CHIhLgmWeeoaGhgV//+tdotVo6OzuJxWIDPSyRAO3t7QDk5ub2Op+fn49Wq+37qqAYMCaTiby8vK+97sUXX+Tss89mxIgRPedOO+00ysrKeP755/t8XwmCE2zDhg2UlZXhdDp7nZ81axYAGzduHIBRiWRRFIWGhgaysrIGeigiAaLRKNdddx1XX301xxxzzEAPRyTAO++8g9PppKamhnHjxmG323E6nfzwhz8kEAgM9PBEHE455RQArrrqKjZu3EhVVRXPPfccjz76KNdffz02m21gBygSqqamhsbGRmbMmHHAY7NmzWLDhg19fk0JghOsrq6O/Pz8A853n6utrT3aQxJJ9I9//IOamhouvvjigR6KSIA//elPVFZWctdddw30UESC7Nixg0gkwrnnnssZZ5zBiy++yPe+9z3+9Kc/8V//9V8DPTwRhwULFnDXXXfx9ttvM23aNEaMGMEll1zCddddxx/+8IeBHp5IsLq6OoBDxlitra0Eg8E+vaY+ISMTPfx+PyaT6YDzZrO553GRGrZt28b//M//cPzxx/Pd7353oIcj4tTS0sJtt93GrbfeSnZ29kAPRySI1+vF5/Pxgx/8oKcaxPnnn08oFOLPf/4zd955J6WlpQM8StFfI0eO5KSTTuKCCy4gMzOTN954g9/85jfk5eXxox/9aKCHJxKoO376uhjrYI8figTBCWaxWA76k0j3r90sFsvRHpJIy4UYsAAADOlJREFUgvr6es466yxcLldPHrgY2n75y1+S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QgiRYMuWLWPbtm2Amo/7zDPPsGPHDn7+85/jdDoBOOuss7jvvvtYsGABl112GY2NjTz88MOMHTuWL774oue17rzzTj788EPOOussSkpKaGxs5JFHHqGoqKgnGP3Od77D888/zw9+8ANWrFjBnDlziEajbNu2jeeff57//Oc/vZp3HMysWbMwGo2sXr2aU045pVdNY6vVyrHHHsvq1atJS0tj8uTJh32tqVOncumll/LII4/g8Xg44YQTePfdd9m5c+cB106fPh2AW265hUsuuQSDwcA555zTExwLIUSySBAshBAJdtttt/X83Ww2M378eB599FG+//3v95yfP38+jz/+OL/97W+54YYbGDVqFL/73e+oqKjoFQQvWrSIiooK/va3v9Hc3ExWVhYnn3wyd9xxBy6XC1DTJV555RX+8Ic/8Pe//52XX34Zq9XK6NGj+d///d+eDXKHYzabmT59OqtXr+7pBLe/OXPm8Omnn3L88cej1X79LxH/9re/kZ2dzT/+8Q9eeeUV5s+fzxtvvHFAfvLMmTO56667+NOf/sTy5cuJxWLs2bNHgmAhRNJpFNldIIQQQgghhhnJCRZCCCGEEMOOBMFCCCGEEGLYkSBYCCGEEEIMOxIECyGEEEKIYUeCYCGEEEIIMexIECyEEEIIIYYdCYKFEEIIIcSwI0GwEEIIIYQYdiQIFkIIIYQQw44EwUIIIYQQYtiRIFgIIYQQQgw7EgQLIYQQQohhR4JgIYQQQggx7EgQLIQQQgghhp3/D7sdo0+Iycj2AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "fig, ax = plt.subplots(1, 1)\n", + "sinter.plot_error_rate(\n", + " ax=ax,\n", + " stats=stats,\n", + " x_func=lambda stat: stat.json_metadata['d'],\n", + " group_func=lambda stat: f\"\"\"noise_strength={stat.json_metadata['p']} decoder={stat.decoder}\"\"\",\n", + " failure_units_per_shot_func=lambda stat: stat.json_metadata['r'],\n", + ")\n", + "ax.set_ylim(1e-6, 1e-0)\n", + "ax.set_xlim(0, 10)\n", + "ax.semilogy()\n", + "ax.set_title(\"Logical Error Rates of Phenomenological Color Codes\")\n", + "ax.set_xlabel(\"Base Width\")\n", + "ax.set_ylabel(\"Logical Error Rate (per round)\")\n", + "ax.grid(which='major', color='#000000')\n", + "ax.grid(which='minor', color='#DDDDDD')\n", + "ax.legend()\n", + "fig.set_dpi(120) # Show it bigger" + ] + }, + { + "cell_type": "markdown", + "id": "bfed1441-6075-4e2b-9914-ad6e5a32d5b0", + "metadata": {}, + "source": [ + "and that's it!" + ] + }, + { + "cell_type": "markdown", + "id": "daf50cde-0fa0-4264-a331-0197ed4e4f6b", + "metadata": {}, + "source": [ + "# Conclusion\n", + "\n", + "In this notebook you:\n", + "- Created a phenomenological color code circuit.\n", + "- Decoded shots from that circuit using Chromobius.\n", + "- Collected and presented statistics using Sinter." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/file_lists/perf_files b/file_lists/perf_files new file mode 100644 index 0000000..69ad922 --- /dev/null +++ b/file_lists/perf_files @@ -0,0 +1,5 @@ +src/chromobius/datatypes/atomic_error.perf.cc +src/chromobius/decode/decoder.perf.cc +src/chromobius/graph/euler_tours.perf.cc +src/chromobius/util.perf.h +src/main.perf.cc diff --git a/file_lists/pybind_files b/file_lists/pybind_files new file mode 100644 index 0000000..4a3ad5c --- /dev/null +++ b/file_lists/pybind_files @@ -0,0 +1,3 @@ +src/chromobius/pybind/chromobius.pybind.cc +src/chromobius/pybind/sinter_compat.pybind.cc +src/chromobius/pybind/sinter_compat.pybind.h diff --git a/file_lists/source_files_no_main b/file_lists/source_files_no_main new file mode 100644 index 0000000..9ecf062 --- /dev/null +++ b/file_lists/source_files_no_main @@ -0,0 +1,35 @@ +src/chromobius.h +src/chromobius/commands/main_all.cc +src/chromobius/commands/main_all.h +src/chromobius/commands/main_benchmark.cc +src/chromobius/commands/main_benchmark.h +src/chromobius/commands/main_describe_decoder.cc +src/chromobius/commands/main_describe_decoder.h +src/chromobius/commands/main_predict.cc +src/chromobius/commands/main_predict.h +src/chromobius/datatypes/atomic_error.cc +src/chromobius/datatypes/atomic_error.h +src/chromobius/datatypes/color_basis.cc +src/chromobius/datatypes/color_basis.h +src/chromobius/datatypes/conf.h +src/chromobius/datatypes/rgb_edge.cc +src/chromobius/datatypes/rgb_edge.h +src/chromobius/decode/decoder.cc +src/chromobius/decode/decoder.h +src/chromobius/decode/matcher_interface.h +src/chromobius/decode/pymatcher.cc +src/chromobius/decode/pymatcher.h +src/chromobius/graph/charge_graph.cc +src/chromobius/graph/charge_graph.h +src/chromobius/graph/choose_rgb_reps.cc +src/chromobius/graph/choose_rgb_reps.h +src/chromobius/graph/collect_atomic_errors.cc +src/chromobius/graph/collect_atomic_errors.h +src/chromobius/graph/collect_composite_errors.cc +src/chromobius/graph/collect_composite_errors.h +src/chromobius/graph/collect_nodes.cc +src/chromobius/graph/collect_nodes.h +src/chromobius/graph/drag_graph.cc +src/chromobius/graph/drag_graph.h +src/chromobius/graph/euler_tours.cc +src/chromobius/graph/euler_tours.h diff --git a/file_lists/test_files b/file_lists/test_files new file mode 100644 index 0000000..ee61c0f --- /dev/null +++ b/file_lists/test_files @@ -0,0 +1,16 @@ +src/chromobius/commands/main_all.test.cc +src/chromobius/commands/main_all.test.h +src/chromobius/commands/main_benchmark.test.cc +src/chromobius/commands/main_describe_decoder.test.cc +src/chromobius/commands/main_predict.test.cc +src/chromobius/datatypes/atomic_error.test.cc +src/chromobius/datatypes/color_basis.test.cc +src/chromobius/datatypes/rgb_edge.test.cc +src/chromobius/decode/decoder.test.cc +src/chromobius/decode/decoder_integration.test.cc +src/chromobius/graph/charge_graph.test.cc +src/chromobius/graph/choose_rgb_reps.test.cc +src/chromobius/graph/drag_graph.test.cc +src/chromobius/graph/euler_tours.test.cc +src/chromobius/test_util.test.cc +src/chromobius/test_util.test.h diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..fed528d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4442a6a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,9 @@ +# These are development requirements, not install requirements. +matplotlib ~= 3.5 +numpy +pymatching ~= 2.0 +pytest +scipy +sinter ~= 1.12.0 +stim ~= 1.12.0 +pygltflib diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..d8d0fed --- /dev/null +++ b/setup.py @@ -0,0 +1,113 @@ +import glob +import os +import pathlib +import re +import shutil +import subprocess +import sys + +import setuptools +import setuptools.command.build_ext + + +CC_FILES = glob.glob("src/**/*.cc", recursive=True) +H_FILES = glob.glob("src/**/*.h", recursive=True) + glob.glob("src/**/*.inl", recursive=True) +CMAKE_FILES = ['CMakeLists.txt', *glob.glob("file_lists/*", recursive=True)] +RELEVANT_SOURCE_FILES = sorted(CMAKE_FILES + CC_FILES + H_FILES) + + +class CMakeExtension(setuptools.Extension): + def __init__(self, name, sourcedir, sources): + setuptools.Extension.__init__(self, name, sources=sources) + self.sourcedir = os.path.abspath(sourcedir) + + +class CMakeBuild(setuptools.command.build_ext.build_ext): + def build_extension(self, ext): + import ninja + + build_temp = os.path.join(self.build_temp, ext.name) + os.makedirs(build_temp, exist_ok=True) + build_env = { + **os.environ, + 'CMAKE_LIBRARY_OUTPUT_DIRECTORY': '', + 'CMAKE_FORCE_PYBIND_CHROMOBIUS': '1', + } + + osx_cmake_flags = [] + if sys.platform.startswith("darwin"): + # Cross-compile support for macOS - respect ARCHFLAGS if set + archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", "")) + if archs: + osx_cmake_flags = ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))] + else: + import platform + arch = platform.machine() + if arch: + osx_cmake_flags = [f"-DCMAKE_OSX_ARCHITECTURES={arch}"] + + subprocess.check_call([ + "cmake", + ext.sourcedir, + f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={pathlib.Path(self.get_ext_fullpath(ext.name)).parent.absolute()}", + f"-DPYTHON_EXECUTABLE={sys.executable}", + *osx_cmake_flags, + *[ + env_arg_item + for env_arg_item in os.environ.get("CMAKE_ARGS", "").split(" ") + if env_arg_item + ], + "-GNinja", + f"-DCMAKE_MAKE_PROGRAM:FILEPATH={os.path.join(ninja.BIN_DIR, 'ninja')}", + ], cwd=build_temp, env=build_env) + + subprocess.check_call([ + "cmake", + "--build", + ".", + "--target", + "chromobius_pybind", + ], cwd=build_temp, env=build_env) + + +__version__ = '0.0.dev0' + +with open("README.md", "r", encoding="utf-8") as f: + long_description = f.read() + +# HACK: Workaround difficulties collecting data files for the package by just making a directory. +package_data_dir = pathlib.Path(__file__).parent / 'package_data' +package_data_dir.mkdir(exist_ok=True) +doc_chromobius = pathlib.Path(__file__).parent / 'doc' / 'chromobius.pyi' +if doc_chromobius.exists(): + shutil.copyfile( + pathlib.Path(__file__).parent / 'doc' / 'chromobius.pyi', + package_data_dir / 'chromobius.pyi', + ) + +setuptools.setup( + name="chromobius", + version=__version__, + author="Craig Gidney", + url="https://github.com/quantumlib/chromobius", + description="A fast implementation of the mobius color code decoder.", + long_description=long_description, + long_description_content_type='text/markdown', + ext_modules=[CMakeExtension("chromobius", sourcedir=".", sources=RELEVANT_SOURCE_FILES)], + cmdclass={"build_ext": CMakeBuild}, + python_requires=">=3.10", + setup_requires=['ninja', 'pybind11~=2.11.1'], + requires=['numpy', 'stim'], + + # Needed on Windows to avoid the default `build` colliding with Bazel's `BUILD`. + # Also, the replacement name is short to avoid blowing the 256 character path limit on windows. + options={'build': {'build_base': 'b'}}, + + # Add files in package_data_dir to the wheel. + # I don't know why it has to be so esoteric, but I tried for hours. + # This is the best I could come up with. + packages=['chromobius'], + package_dir={'chromobius': package_data_dir.name}, + package_data={'chromobius': [str(e) for e in package_data_dir.iterdir()]}, + include_package_data=True, +) diff --git a/src/chromobius.h b/src/chromobius.h new file mode 100644 index 0000000..4441d1e --- /dev/null +++ b/src/chromobius.h @@ -0,0 +1,24 @@ +#ifndef _CHROMOBIUS_H +#define _CHROMOBIUS_H +/// WARNING: THE chromobius C++ API MAKES NO COMPATIBILITY GUARANTEES. +/// It may change arbitrarily and catastrophically from minor version to minor version. +/// If you need a stable API, use chromobius's Python API. +#include "chromobius/commands/main_all.h" +#include "chromobius/commands/main_benchmark.h" +#include "chromobius/commands/main_describe_decoder.h" +#include "chromobius/commands/main_predict.h" +#include "chromobius/datatypes/atomic_error.h" +#include "chromobius/datatypes/color_basis.h" +#include "chromobius/datatypes/conf.h" +#include "chromobius/datatypes/rgb_edge.h" +#include "chromobius/decode/decoder.h" +#include "chromobius/decode/matcher_interface.h" +#include "chromobius/decode/pymatcher.h" +#include "chromobius/graph/charge_graph.h" +#include "chromobius/graph/choose_rgb_reps.h" +#include "chromobius/graph/collect_atomic_errors.h" +#include "chromobius/graph/collect_composite_errors.h" +#include "chromobius/graph/collect_nodes.h" +#include "chromobius/graph/drag_graph.h" +#include "chromobius/graph/euler_tours.h" +#endif diff --git a/src/chromobius/commands/main_all.cc b/src/chromobius/commands/main_all.cc new file mode 100644 index 0000000..eb19d0d --- /dev/null +++ b/src/chromobius/commands/main_all.cc @@ -0,0 +1,85 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/commands/main_all.h" + +#include "chromobius/commands/main_benchmark.h" +#include "chromobius/commands/main_describe_decoder.h" +#include "chromobius/commands/main_predict.h" +#include "stim.h" + +using namespace chromobius; + +int chromobius::main(int argc, const char **argv) { + const char *command = ""; + if (argc >= 2) { + command = argv[1]; + } + const char *help = R"HELP( + +Available chromobius commands: + + # Print usage information. + chromobius help + + # Predict observable flips from detection event data. + chromobius predict \ + [--dem FILEPATH] \ # where to read detector error model from + [--in] \ # where to read detection event data (defaults to stdin) + [--in_format 01|b8|...] \ # format of input detection event data + [--in_includes_appended_observables] \ # if set, input data includes observables as extra detectors to ignore + [--out FILEPATH] \ # where to write predictions to (defaults to stdout) + [--out_format 01|b8|...] # format to use when writing predictions + + # Print accuracy and timing statistics collected while decoding. + chromobius benchmark + [--dem FILEPATH] \ # where to read detector error model from + [--in] \ # where to read detection event data (defaults to stdin) + [--in_format 01|b8|...] \ # format of input detection event data + [--in_includes_appended_observables] \ # if set, observables are extra detectors in detection event data + [--obs_in FILEPATH] \ # if set, observables are read from a separate file + [--obs_in_format 01|b8|...] \ # format of separate observable data + [--out FILEPATH] # where to write results (defaults to stdout) + + # Describes the internal representations used to decode a given dem or circuit. + chromobius describe_decoder \ + [--in] \ # where to read a detector error model from (defaults to stdin) + [--circuit] \ # where to read a circuit from (overrides --in) + [--out FILEPATH] # where to write output (defaults to stdout) +)HELP"; + + if (strcmp(command, "describe_decoder") == 0) { + return main_describe_decoder(argc, argv); + } + if (strcmp(command, "predict") == 0) { + return main_predict(argc, argv); + } + if (strcmp(command, "benchmark") == 0) { + return main_benchmark(argc, argv); + } + if (strcmp(command, "help") == 0 || strcmp(command, "--help") == 0 || strcmp(command, "-help") == 0 || + strcmp(command, "-h") == 0) { + std::cout << help; + return EXIT_SUCCESS; + } + + std::stringstream ss; + if (command[0] == '\0') { + ss << "Specify a chromobius command to run.\n"; + } else { + ss << "Unrecognized chromobius command '" << command << "'.\n"; + } + ss << help; + throw std::invalid_argument(ss.str()); +} diff --git a/src/chromobius/commands/main_all.h b/src/chromobius/commands/main_all.h new file mode 100644 index 0000000..3d3bf76 --- /dev/null +++ b/src/chromobius/commands/main_all.h @@ -0,0 +1,26 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_COMMANDS_MAIN_ALL_H +#define _CHROMOBIUS_COMMANDS_MAIN_ALL_H + +namespace chromobius { + +int main(int argc, const char **argv); + +} + +#endif diff --git a/src/chromobius/commands/main_all.test.cc b/src/chromobius/commands/main_all.test.cc new file mode 100644 index 0000000..a98a619 --- /dev/null +++ b/src/chromobius/commands/main_all.test.cc @@ -0,0 +1,60 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/commands/main_all.test.h" + +#include "gtest/gtest.h" + +#include "chromobius/test_util.test.h" + +using namespace chromobius; + +std::string chromobius::result_of_running_main(const std::vector args, const std::string &input) { + std::vector argv; + argv.push_back("TEST_PROCESS"); + for (const auto &a : args) { + argv.push_back(a.c_str()); + } + RaiiTempNamedFile inp; + RaiiTempNamedFile out; + argv.push_back("--in"); + argv.push_back(inp.path.c_str()); + argv.push_back("--out"); + argv.push_back(out.path.c_str()); + FILE *f = fopen(inp.path.c_str(), "w"); + if (f == nullptr || fwrite(input.data(), 1, input.size(), f) != input.size()) { + throw std::invalid_argument("Failed to write input."); + } + fclose(f); + if (chromobius::main((int)argv.size(), argv.data()) != EXIT_SUCCESS) { + throw std::invalid_argument("Returned not EXIT_SUCCESS"); + } + f = fopen(out.path.c_str(), "rb"); + if (f == nullptr) { + throw std::invalid_argument("Failed to read output."); + } + std::string s; + while (true) { + int i = getc(f); + if (i == EOF) { + break; + } + s.push_back((char)i); + } + return s; +} + +TEST(main_all, unknown_command) { + ASSERT_THROW({ result_of_running_main({"UNKNOWN_COMMAND"}, ""); }, std::invalid_argument); +} diff --git a/src/chromobius/commands/main_all.test.h b/src/chromobius/commands/main_all.test.h new file mode 100644 index 0000000..1152aba --- /dev/null +++ b/src/chromobius/commands/main_all.test.h @@ -0,0 +1,32 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_COMMANDS_MAIN_ALL_TEST_H +#define _CHROMOBIUS_COMMANDS_MAIN_ALL_TEST_H + +#include +#include +#include + +#include "chromobius/commands/main_all.h" + +namespace chromobius { + +std::string result_of_running_main(const std::vector args, const std::string &input); + +} // namespace chromobius + +#endif diff --git a/src/chromobius/commands/main_benchmark.cc b/src/chromobius/commands/main_benchmark.cc new file mode 100644 index 0000000..b91f508 --- /dev/null +++ b/src/chromobius/commands/main_benchmark.cc @@ -0,0 +1,133 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/commands/main_benchmark.h" + +#include + +#include "chromobius/decode/decoder.h" +#include "stim.h" + +using namespace chromobius; + +int chromobius::main_benchmark(int argc, const char **argv) { + auto time_config_starts = std::chrono::steady_clock::now(); + + stim::check_for_unknown_arguments( + { + "--in", + "--in_format", + "--in_includes_appended_observables", + "--obs_in", + "--obs_in_format", + "--out", + "--dem", + }, + {}, + "benchmark", + argc, + argv); + + FILE *shots_in = stim::find_open_file_argument("--in", stdin, "rb", argc, argv); + FILE *obs_in = nullptr; + if (stim::find_argument("--obs_in", argc, argv) != nullptr) { + obs_in = stim::find_open_file_argument("--obs_in", nullptr, "rb", argc, argv); + } + FILE *stats_out = stim::find_open_file_argument("--out", stdout, "wb", argc, argv); + FILE *dem_file = stim::find_open_file_argument("--dem", nullptr, "rb", argc, argv); + stim::FileFormatData shots_in_format = + stim::find_enum_argument("--in_format", "01", stim::format_name_to_enum_map(), argc, argv); + stim::FileFormatData obs_in_format = + stim::find_enum_argument("--obs_in_format", "01", stim::format_name_to_enum_map(), argc, argv); + bool append_obs = stim::find_bool_argument("--in_includes_appended_observables", argc, argv); + if (!append_obs && obs_in == nullptr) { + throw std::invalid_argument("Must specify --in_includes_appended_observables or --obs_in."); + } + + stim::DetectorErrorModel dem = stim::DetectorErrorModel::from_file(dem_file); + fclose(dem_file); + auto num_obs = dem.count_observables(); + auto num_dets = dem.count_detectors(); + + std::unique_ptr> obs_reader; + if (obs_in != nullptr) { + obs_reader = stim::MeasureRecordReader::make(obs_in, obs_in_format.id, 0, 0, num_obs); + } + auto reader = stim::MeasureRecordReader::make( + shots_in, shots_in_format.id, 0, num_dets, append_obs * num_obs); + + size_t num_mistakes = 0; + size_t num_shots = 0; + uint64_t num_detection_events = 0; + + auto decoder = Decoder::from_dem(dem, DecoderConfigOptions{}); + stim::simd_bits buf_dets(reader->bits_per_record()); + stim::simd_bits buf_obs(num_obs); + auto time_config_ends_decoding_starts = std::chrono::steady_clock::now(); + + while (reader->start_and_read_entire_record(buf_dets)) { + if (obs_reader == nullptr) { + for (size_t k = 0; k < num_obs; k++) { + buf_obs[k] = buf_dets[num_dets + k]; + buf_dets[num_dets + k] = 0; + } + } else if (!obs_reader->start_and_read_entire_record(buf_obs)) { + throw std::invalid_argument("Obs data ended before shot data ended."); + } + num_detection_events += buf_dets.popcnt(); + auto prediction = + decoder.decode_detection_events({buf_dets.u8, buf_dets.u8 + buf_dets.num_u8_padded()}); + if (buf_obs.u64[0] != prediction) { + num_mistakes++; + } + num_shots++; + } + + auto time_decoding_ends = std::chrono::steady_clock::now(); + auto decoding_microseconds = (double)std::chrono::duration_cast( + time_decoding_ends - time_config_ends_decoding_starts) + .count(); + auto config_microseconds = (double)std::chrono::duration_cast( + time_config_ends_decoding_starts - time_config_starts) + .count(); + + auto total_detectors = (uint64_t)num_dets * (uint64_t)num_shots; + std::stringstream output; + output << " num_shots = " << num_shots << "\n"; + output << " num_mistakes = " << num_mistakes << "\n"; + output << " mistakes_per_shot = " + << (num_shots ? (double)num_mistakes / (double)num_shots : 0) << "\n"; + output << "\n"; + output << " num_detection_events = " << num_detection_events << "\n"; + output << " num_detectors_per_shot = " << num_dets << "\n"; + output << " detection_fraction = " << ((double)num_detection_events / (double)total_detectors) + << "\n"; + output << "\n"; + output << " setup_seconds = " << (config_microseconds / 1000000) << "\n"; + output << " decoding_seconds = " << (decoding_microseconds / 1000000) << "\n"; + output << " decoding_microseconds_per_shot = " << (decoding_microseconds / num_shots) << "\n"; + output << "decoding_microseconds_per_detection_event = " << (decoding_microseconds / num_detection_events) << "\n"; + fprintf(stats_out, "%s", output.str().c_str()); + if (stats_out != stdout) { + fclose(stats_out); + } + if (shots_in != stdin) { + fclose(shots_in); + } + if (obs_in != nullptr) { + fclose(obs_in); + } + + return EXIT_SUCCESS; +} diff --git a/src/chromobius/commands/main_benchmark.h b/src/chromobius/commands/main_benchmark.h new file mode 100644 index 0000000..931e47a --- /dev/null +++ b/src/chromobius/commands/main_benchmark.h @@ -0,0 +1,26 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_COMMANDS_MAIN_COUNT_MISTAKES_H +#define _CHROMOBIUS_COMMANDS_MAIN_COUNT_MISTAKES_H + +namespace chromobius { + +int main_benchmark(int argc, const char **argv); + +} + +#endif \ No newline at end of file diff --git a/src/chromobius/commands/main_benchmark.test.cc b/src/chromobius/commands/main_benchmark.test.cc new file mode 100644 index 0000000..0362fa0 --- /dev/null +++ b/src/chromobius/commands/main_benchmark.test.cc @@ -0,0 +1,58 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" + +#include "chromobius/commands/main_all.test.h" +#include "chromobius/test_util.test.h" + +using namespace chromobius; + +TEST(main_benchmark, basic) { + RaiiTempNamedFile dem; + FILE *f = fopen(dem.path.c_str(), "w"); + fprintf(f, "%s", R"DEM( + error(0.1) D0 L0 + error(0.1) D0 D1 L1 + error(0.1) D1 L2 + detector(0, 0, 0, 0) D0 + detector(0, 0, 0, 1) D1 + )DEM"); + fclose(f); + auto stdout_text = result_of_running_main( + { + "benchmark", + "--dem", + dem.path, + "--in_format", + "dets", + "--in_includes_appended_observables", + }, + R"stdin(shot L0 +shot D0 L0 +shot D1 L2 +shot D0 D1 L1)stdin"); + + std::string expected_prefix = R"OUT( + num_shots = 4 + num_mistakes = 1 + mistakes_per_shot = 0.25 + + num_detection_events = 4 + num_detectors_per_shot = 2 + detection_fraction = 0.5 + + setup_seconds =)OUT"; + ASSERT_EQ(stdout_text.substr(0, expected_prefix.size() - 1), expected_prefix.substr(1)); +} diff --git a/src/chromobius/commands/main_describe_decoder.cc b/src/chromobius/commands/main_describe_decoder.cc new file mode 100644 index 0000000..a590d52 --- /dev/null +++ b/src/chromobius/commands/main_describe_decoder.cc @@ -0,0 +1,54 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/commands/main_describe_decoder.h" + +#include "chromobius/decode/decoder.h" +#include "stim.h" + +using namespace chromobius; + +int chromobius::main_describe_decoder(int argc, const char **argv) { + stim::check_for_unknown_arguments( + { + "--in", + "--out", + "--circuit", + }, + {}, + "describe_decoder", + argc, + argv); + + auto out_file = stim::find_output_stream_argument("--out", true, argc, argv); + auto &out = out_file.stream(); + + stim::DetectorErrorModel dem; + + if (stim::find_argument("--circuit", argc, argv) != nullptr) { + FILE *circuit_in = stim::find_open_file_argument("--circuit", nullptr, "rb", argc, argv); + auto circuit = stim::Circuit::from_file(circuit_in); + fclose(circuit_in); + dem = stim::ErrorAnalyzer::circuit_to_detector_error_model(circuit, false, true, false, true, false, false); + } else { + FILE *dem_in = stim::find_open_file_argument("--in", stdin, "rb", argc, argv); + dem = stim::DetectorErrorModel::from_file(dem_in); + fclose(dem_in); + } + + auto decoder = Decoder::from_dem(dem, DecoderConfigOptions{.include_coords_in_mobius_dem=true}); + out << decoder; + out << "\n"; + return EXIT_SUCCESS; +} diff --git a/src/chromobius/commands/main_describe_decoder.h b/src/chromobius/commands/main_describe_decoder.h new file mode 100644 index 0000000..9b42db4 --- /dev/null +++ b/src/chromobius/commands/main_describe_decoder.h @@ -0,0 +1,26 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_COMMANDS_MAIN_DESCRIBE_DECODER_H +#define _CHROMOBIUS_COMMANDS_MAIN_DESCRIBE_DECODER_H + +namespace chromobius { + +int main_describe_decoder(int argc, const char **argv); + +} + +#endif diff --git a/src/chromobius/commands/main_describe_decoder.test.cc b/src/chromobius/commands/main_describe_decoder.test.cc new file mode 100644 index 0000000..2fd5844 --- /dev/null +++ b/src/chromobius/commands/main_describe_decoder.test.cc @@ -0,0 +1,73 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" + +#include "chromobius/commands/main_all.test.h" + +using namespace chromobius; + +TEST(main_describe_decoder, basic_usage) { + auto result = result_of_running_main( + {"describe_decoder"}, + R"stdin( + error(0.1) D0 L0 + error(0.1) D0 D1 L1 + error(0.1) D1 L2 + detector(0, 0, 0, 0) D0 + detector(0, 0, 0, 1) D1 + )stdin"); + ASSERT_EQ("\n" + result, R"stdout( +chromobius::Decoder{ + +.charge_graph=ChargeGraph{.nodes={ + ChargeGraphNode{.neighbors={{0,0}, {1,2}, {BOUNDARY_NODE,1}}}, // node 0 + ChargeGraphNode{.neighbors={{0,2}, {1,0}, {BOUNDARY_NODE,4}}}, // node 1 +}} + +.rgb_reps={ + RgbEdge{.red_node=0, .green_node=1, .blue_node=BOUNDARY_NODE, .obs_flip=2, .charge_flip=B} // rep 0 + RgbEdge{.red_node=0, .green_node=1, .blue_node=BOUNDARY_NODE, .obs_flip=2, .charge_flip=B} // rep 1 +} + +.drag_graph=DragGraph{.mmm={ + NEUTRAL@0:NEUTRAL@0 = 0 + NEUTRAL@0:R@0 = 1 + R@0:NEUTRAL@0 = 1 + NEUTRAL@0:NEUTRAL@1 = 0 + R@0:R@1 = 0 + R@0:G@1 = 2 + G@0:G@1 = 0 + NEUTRAL@1:NEUTRAL@0 = 0 + R@1:R@0 = 0 + G@1:R@0 = 2 + G@1:G@0 = 0 + NEUTRAL@1:NEUTRAL@1 = 0 + NEUTRAL@1:G@1 = 4 + G@1:NEUTRAL@1 = 4 +}} + +.mobius_dem=stim::DetectorErrorModel{ +detector(0, 0, 0, 0, 2) D0 +detector(0, 0, 0, 0, 3) D1 +detector(0, 0, 0, 1, 1) D2 +detector(0, 0, 0, 1, 3) D3 +error(0.01000000000000000194) D0 D1 +error(0.1000000000000000056) D0 D2 ^ D1 D3 +error(0.01000000000000000194) D2 D3 +} + +} +)stdout"); +} diff --git a/src/chromobius/commands/main_predict.cc b/src/chromobius/commands/main_predict.cc new file mode 100644 index 0000000..ff15bc4 --- /dev/null +++ b/src/chromobius/commands/main_predict.cc @@ -0,0 +1,81 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/commands/main_predict.h" + +#include "chromobius/decode/decoder.h" +#include "stim.h" + +using namespace chromobius; + +int chromobius::main_predict(int argc, const char **argv) { + stim::check_for_unknown_arguments( + { + "--in", + "--in_format", + "--in_includes_appended_observables", + "--out", + "--out_format", + "--dem", + }, + {}, + "predict", + argc, + argv); + + FILE *shots_in = stim::find_open_file_argument("--in", stdin, "rb", argc, argv); + FILE *predictions_out = stim::find_open_file_argument("--out", stdout, "wb", argc, argv); + FILE *dem_file = stim::find_open_file_argument("--dem", nullptr, "rb", argc, argv); + stim::FileFormatData shots_in_format = + stim::find_enum_argument("--in_format", "b8", stim::format_name_to_enum_map(), argc, argv); + stim::FileFormatData predictions_out_format = + stim::find_enum_argument("--out_format", "01", stim::format_name_to_enum_map(), argc, argv); + bool append_obs = stim::find_bool_argument("--in_includes_appended_observables", argc, argv); + + stim::DetectorErrorModel dem = stim::DetectorErrorModel::from_file(dem_file); + fclose(dem_file); + auto decoder = Decoder::from_dem(dem, DecoderConfigOptions{}); + + size_t num_dets = dem.count_detectors(); + size_t num_obs = dem.count_observables(); + auto reader = stim::MeasureRecordReader::make( + shots_in, shots_in_format.id, 0, dem.count_detectors(), append_obs * num_obs); + auto writer = stim::MeasureRecordWriter::make(predictions_out, predictions_out_format.id); + writer->begin_result_type('L'); + + stim::simd_bits buf_dets(reader->bits_per_record()); + while (reader->start_and_read_entire_record(buf_dets)) { + if (append_obs) { + for (size_t k = 0; k < num_obs; k++) { + buf_dets[num_dets + k] = 0; + } + } + auto prediction = + decoder.decode_detection_events({buf_dets.u8, buf_dets.u8 + buf_dets.num_u8_padded()}); + for (size_t k = 0; k < num_obs; k++) { + writer->write_bit((prediction >> k) & 1); + } + writer->write_end(); + buf_dets.clear(); + } + + if (predictions_out != stdout) { + fclose(predictions_out); + } + if (shots_in != stdin) { + fclose(shots_in); + } + + return EXIT_SUCCESS; +} diff --git a/src/chromobius/commands/main_predict.h b/src/chromobius/commands/main_predict.h new file mode 100644 index 0000000..0fb86d9 --- /dev/null +++ b/src/chromobius/commands/main_predict.h @@ -0,0 +1,26 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_COMMANDS_MAIN_PREDICT_H +#define _CHROMOBIUS_COMMANDS_MAIN_PREDICT_H + +namespace chromobius { + +int main_predict(int argc, const char **argv); + +} + +#endif \ No newline at end of file diff --git a/src/chromobius/commands/main_predict.test.cc b/src/chromobius/commands/main_predict.test.cc new file mode 100644 index 0000000..1d7bb17 --- /dev/null +++ b/src/chromobius/commands/main_predict.test.cc @@ -0,0 +1,44 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" + +#include "chromobius/commands/main_all.test.h" +#include "chromobius/test_util.test.h" + +using namespace chromobius; + +TEST(main_predict, basic) { + RaiiTempNamedFile dem; + FILE *f = fopen(dem.path.c_str(), "w"); + fprintf(f, "%s", R"DEM( + error(0.1) D0 L0 + error(0.1) D0 D1 L1 + error(0.1) D1 L2 + detector(0, 0, 0, 0) D0 + detector(0, 0, 0, 1) D1 + )DEM"); + fclose(f); + auto stdout_content = result_of_running_main( + {"predict", "--dem", dem.path, "--in_format", "dets", "--out_format", "dets"}, + R"stdin(shot +shot D0 +shot D1 +shot D0 D1)stdin"); + ASSERT_EQ(stdout_content, R"stdout(shot +shot L0 +shot L2 +shot L1 +)stdout"); +} diff --git a/src/chromobius/datatypes/atomic_error.cc b/src/chromobius/datatypes/atomic_error.cc new file mode 100644 index 0000000..7b14565 --- /dev/null +++ b/src/chromobius/datatypes/atomic_error.cc @@ -0,0 +1,63 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/datatypes/atomic_error.h" + +using namespace chromobius; + +void AtomicErrorKey::check_invariants(std::span det_types) { + Charge net_charge = Charge::NEUTRAL; + for (auto d : dets) { + if (d < det_types.size()) { + net_charge ^= det_types[d].color; + } else if (d != BOUNDARY_NODE) { + std::stringstream ss; + ss << *this << " has a too-large detector index. det_types.size() = " << det_types.size(); + throw std::invalid_argument(ss.str()); + } + } + + if (dets[0] == BOUNDARY_NODE) { + throw std::invalid_argument("Vacuous: " + str()); + } + if (dets[0] > dets[1] || dets[1] > dets[2]) { + throw std::invalid_argument("Not sorted: " + str()); + } + if (net_charge != Charge::NEUTRAL && dets[2] != BOUNDARY_NODE) { + std::stringstream ss; + ss << "Triplet " << *this << " has non-neutral charge " << net_charge; + throw std::invalid_argument(ss.str()); + } +} + +std::ostream &chromobius::operator<<(std::ostream &out, const AtomicErrorKey &val) { + out << "AtomicErrorKey{.dets={"; + for (size_t k = 0; k < 3; k++) { + if (k > 0) { + out << ", "; + } + if (val.dets[k] == BOUNDARY_NODE) { + out << "BOUNDARY_NODE"; + } else { + out << val.dets[k]; + } + } + out << "}}"; + return out; +} +std::string AtomicErrorKey::str() const { + std::stringstream ss; + ss << *this; + return ss.str(); +} diff --git a/src/chromobius/datatypes/atomic_error.h b/src/chromobius/datatypes/atomic_error.h new file mode 100644 index 0000000..bef0e51 --- /dev/null +++ b/src/chromobius/datatypes/atomic_error.h @@ -0,0 +1,138 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_ATOMIC_ERROR_H +#define _CHROMOBIUS_ATOMIC_ERROR_H + +#include + +#include "chromobius/datatypes/color_basis.h" +#include "stim.h" + +namespace chromobius { + +inline void inplace_sort2(node_offset_int &a, node_offset_int &b) { + auto cmp2 = -(a > b) & (a ^ b); + a ^= cmp2; + b ^= cmp2; +} + +inline std::array sort3(node_offset_int a, node_offset_int b, node_offset_int c) { + inplace_sort2(b, c); + inplace_sort2(a, b); + inplace_sort2(b, c); + return {a, b, c}; +} + +/// Atomic errors are the building blocks all other errors are decomposed into. +/// +/// There are four kinds of atomic error: +/// Neutral Triplet: Three detection events, each with different color. +/// Example: A bulk error in a code capacity color code. +/// Neutral Pair: Two detection events that have the same color. +/// Example: A measurement error in a phenom color code. +/// Charged Pair: Two detection events that have different colors. +/// Example: A boundary error in a code capacity color code. +/// Charged Singlet: One detection event. +/// Example: A corner error in a code capacity color code. +/// +/// Invariants: +/// sorted: 0 <= n1 <= n2 <= n3 <= BOUNDARY_NODE +/// not empty: n1 != BOUNDARY_NODE +/// neutral triplets: (n3 != BOUNDARY_NODE) ==> (net_charge == NEUTRAL) +/// single basis: len({basis[n] for n in dets if n != BOUNDARY_NODE}) == 1 +struct AtomicErrorKey { + std::array dets; + inline AtomicErrorKey(node_offset_int det1, node_offset_int det2, node_offset_int det3) + : dets(sort3(det1, det2, det3)) { + } + inline bool operator<(const AtomicErrorKey &other) const { + for (size_t k = 0; k < 3; k++) { + if (dets[k] != other.dets[k]) { + return dets[k] < other.dets[k]; + } + } + return false; + } + inline uint8_t weight() const { + return (dets[0] != BOUNDARY_NODE) + (dets[1] != BOUNDARY_NODE) + (dets[2] != BOUNDARY_NODE); + } + inline Charge net_charge(std::span node_colors) const { + Charge c = Charge::NEUTRAL; + for (auto d : dets) { + if (d != BOUNDARY_NODE) { + c ^= node_colors[d].color; + } + } + return c; + } + inline bool operator==(const AtomicErrorKey &other) const { + return dets == other.dets; + } + inline bool operator!=(const AtomicErrorKey &other) const { + return !(*this == other); + } + void check_invariants(std::span det_types); + std::string str() const; + + /// Decomposes the atomic error into edges for the mobius dem. + /// + /// Each symptom splits into two, and the symptoms then get distributed to the various mobius subgraphs. + /// The pairing of the split up symptoms is important to ensure the subgraphs are connected (and disconnected) + /// in the appropriate ways. + inline void iter_mobius_edges(std::span node_colors, const std::function &callback) const { + auto [n1, n2, n3] = dets; + if (n1 == BOUNDARY_NODE) { + // No edge. + return; + } else if (n2 == BOUNDARY_NODE) { + callback(n1 * 2 + 0, n1 * 2 + 1); + } else if (n3 == BOUNDARY_NODE) { + auto c1 = node_colors[n1].color; + auto c2 = node_colors[n2].color; + bool flip_order = (c1 ^ c2) == Charge::G; + callback(n1 * 2 + 0, (n2 * 2 + 0) ^ flip_order); + callback(n1 * 2 + 1, (n2 * 2 + 1) ^ flip_order); + } else { + assert((node_colors[n1].color ^ node_colors[n2].color ^ node_colors[n3].color) == Charge::NEUTRAL); + node_offset_int rgb[3]{BOUNDARY_NODE, BOUNDARY_NODE, BOUNDARY_NODE}; + rgb[node_colors[n1].color - 1] = n1; + rgb[node_colors[n2].color - 1] = n2; + rgb[node_colors[n3].color - 1] = n3; + auto [r, g, b] = rgb; + assert(r != BOUNDARY_NODE); + assert(g != BOUNDARY_NODE); + assert(b != BOUNDARY_NODE); + auto a0 = r * 2 + SUBGRAPH_OFFSET_Red_NotBlue; + auto b0 = g * 2 + SUBGRAPH_OFFSET_Green_NotBlue; + auto a1 = g * 2 + SUBGRAPH_OFFSET_Green_NotRed; + auto b1 = b * 2 + SUBGRAPH_OFFSET_Blue_NotRed; + auto a2 = r * 2 + SUBGRAPH_OFFSET_Red_NotGreen; + auto b2 = b * 2 + SUBGRAPH_OFFSET_Blue_NotGreen; + inplace_sort2(a0, b0); + inplace_sort2(a1, b1); + inplace_sort2(a2, b2); + callback(a0, b0); + callback(a1, b1); + callback(a2, b2); + } + } +}; +std::ostream &operator<<(std::ostream &out, const AtomicErrorKey &val); + +} // namespace chromobius + +#endif diff --git a/src/chromobius/datatypes/atomic_error.perf.cc b/src/chromobius/datatypes/atomic_error.perf.cc new file mode 100644 index 0000000..6ddfeb1 --- /dev/null +++ b/src/chromobius/datatypes/atomic_error.perf.cc @@ -0,0 +1,70 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/datatypes/atomic_error.h" + +#include "chromobius/util.perf.h" +#include "stim.h" + +using namespace chromobius; + +BENCHMARK(sort3) { + std::vector data; + std::mt19937_64 rng{0}; + for (size_t k = 0; k < 999; k++) { + data.push_back((node_offset_int)rng()); + } + + size_t v0 = 0; + size_t v1 = 0; + size_t v2 = 0; + benchmark_go([&]() { + for (size_t k = 0; k < data.size(); k += 3) { + auto abc = sort3(data[k], data[k + 1], data[k + 2]); + v0 += abc[0]; + v1 ^= abc[1]; + v2 += abc[2]; + } + }) + .goal_nanos(150) + .show_rate("Constructions", data.size() / 3); + if (v0 + v1 + v2 == 1) { + std::cerr << "data dependence"; + } +} + +BENCHMARK(sort3_known_max) { + std::vector data; + std::mt19937_64 rng{0}; + for (size_t k = 0; k < 999; k++) { + data.push_back((node_offset_int)rng()); + } + + size_t v0 = 0; + size_t v1 = 0; + size_t v2 = 0; + benchmark_go([&]() { + for (size_t k = 0; k < data.size(); k += 3) { + auto e2 = sort3(data[k], UINT32_MAX, data[k + 1]); + v0 += e2[0]; + v1 ^= e2[1]; + v2 += e2[2]; + } + }) + .goal_nanos(100) + .show_rate("Constructions", data.size() / 3); + if (v0 + v1 + v2 == 1) { + std::cerr << "data dependence"; + } +} diff --git a/src/chromobius/datatypes/atomic_error.test.cc b/src/chromobius/datatypes/atomic_error.test.cc new file mode 100644 index 0000000..579c6a4 --- /dev/null +++ b/src/chromobius/datatypes/atomic_error.test.cc @@ -0,0 +1,219 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/datatypes/atomic_error.h" + +#include "gtest/gtest.h" + +using namespace chromobius; + +TEST(atomic_error, sort3) { + std::mt19937 rng; + for (size_t k = 0; k < 1000; k++) { + uint32_t a = rng(); + uint32_t b = rng(); + uint32_t c = rng(); + std::array expected{a, b, c}; + std::sort(expected.begin(), expected.end()); + auto abc = sort3(a, b, c); + ASSERT_EQ(abc, expected) << a << ", " << b << ", " << c; + } +} + +TEST(atomic_error, atomic_error_key_basic) { + AtomicErrorKey n{2, 3, 5}; + ASSERT_EQ(n.dets[0], 2); + ASSERT_EQ(n.dets[1], 3); + ASSERT_EQ(n.dets[2], 5); + + ASSERT_TRUE(n == (AtomicErrorKey{2, 3, 5})); + ASSERT_TRUE(n == (AtomicErrorKey{3, 2, 5})); + ASSERT_TRUE(n == (AtomicErrorKey{2, 5, 3})); + ASSERT_TRUE(n == (AtomicErrorKey{3, 5, 2})); + ASSERT_TRUE(n == (AtomicErrorKey{5, 2, 3})); + ASSERT_TRUE(n == (AtomicErrorKey{5, 3, 2})); + ASSERT_FALSE(n == (AtomicErrorKey{2, 3, 7})); + ASSERT_FALSE(n != (AtomicErrorKey{2, 3, 5})); + ASSERT_TRUE(n != (AtomicErrorKey{2, 3, 7})); + + ASSERT_EQ(n.str(), "AtomicErrorKey{.dets={2, 3, 5}}"); + ASSERT_EQ((AtomicErrorKey{BOUNDARY_NODE, 2, 3}).str(), "AtomicErrorKey{.dets={2, 3, BOUNDARY_NODE}}"); +} + +TEST(atomic_error, check_invariants) { + std::vector colors{ + {Charge::R, Basis::X}, + {Charge::G, Basis::X}, + {Charge::B, Basis::X}, + {Charge::R, Basis::X}, + {Charge::R, Basis::Z}, + }; + + AtomicErrorKey k{0, 1, 2}; + k.check_invariants(colors); + + k.dets[0] = 3; + ASSERT_THROW({ k.check_invariants(colors); }, std::invalid_argument); + + k.dets[0] = 0; + k.dets[2] = 9; + ASSERT_THROW({ k.check_invariants(colors); }, std::invalid_argument); + + k.dets[2] = BOUNDARY_NODE; + k.check_invariants(colors); + + k.dets[0] = BOUNDARY_NODE; + k.dets[1] = BOUNDARY_NODE; + ASSERT_THROW({ k.check_invariants(colors); }, std::invalid_argument); + + k.dets = {0, 1, 3}; + ASSERT_THROW({ k.check_invariants(colors); }, std::invalid_argument); +} + +TEST(atomic_error, iter_mobius_edges) { + std::vector node_colors{ + ColorBasis{Charge::R, Basis::X}, + ColorBasis{Charge::G, Basis::X}, + ColorBasis{Charge::B, Basis::X}, + ColorBasis{Charge::R, Basis::X}, + ColorBasis{Charge::G, Basis::X}, + ColorBasis{Charge::B, Basis::X}, + }; + using S = std::set>; + auto collect = [&](AtomicErrorKey atom) { + S result; + atom.iter_mobius_edges(node_colors, [&](node_offset_int d1, node_offset_int d2) { + result.insert({d1, d2}); + }); + return result; + }; + + // Empty. + ASSERT_EQ(collect(AtomicErrorKey{BOUNDARY_NODE, BOUNDARY_NODE, BOUNDARY_NODE}), (S{})); + // Single. + ASSERT_EQ( + collect(AtomicErrorKey{0, BOUNDARY_NODE, BOUNDARY_NODE}), + (S{ + {0, 1}, + })); + ASSERT_EQ( + collect(AtomicErrorKey{1, BOUNDARY_NODE, BOUNDARY_NODE}), + (S{ + {2, 3}, + })); + ASSERT_EQ( + collect(AtomicErrorKey{2, BOUNDARY_NODE, BOUNDARY_NODE}), + (S{ + {4, 5}, + })); + + // Same-color Pair. + ASSERT_EQ( + collect(AtomicErrorKey{0, 3, BOUNDARY_NODE}), + (S{ + {0, 6}, + {1, 7}, + })); + ASSERT_EQ( + collect(AtomicErrorKey{1, 4, BOUNDARY_NODE}), + (S{ + {2, 8}, + {3, 9}, + })); + ASSERT_EQ( + collect(AtomicErrorKey{2, 5, BOUNDARY_NODE}), + (S{ + {4, 10}, + {5, 11}, + })); + + // RG Pair. + ASSERT_EQ( + collect(AtomicErrorKey{0, 1, BOUNDARY_NODE}), + (S{ + {0, 2}, + {1, 3}, + })); + ASSERT_EQ( + collect(AtomicErrorKey{3, 1, BOUNDARY_NODE}), + (S{ + {2, 6}, + {3, 7}, + })); + + // RG Pair. + ASSERT_EQ( + collect(AtomicErrorKey{0, 1, BOUNDARY_NODE}), + (S{ + {0 * 2 + SUBGRAPH_OFFSET_Red_NotGreen, 1 * 2 + SUBGRAPH_OFFSET_Green_NotRed}, + {0 * 2 + SUBGRAPH_OFFSET_Red_NotBlue, 1 * 2 + SUBGRAPH_OFFSET_Green_NotBlue}, + })); + ASSERT_EQ( + collect(AtomicErrorKey{3, 1, BOUNDARY_NODE}), + (S{ + {1 * 2 + SUBGRAPH_OFFSET_Green_NotRed, 3 * 2 + SUBGRAPH_OFFSET_Red_NotGreen}, + {1 * 2 + SUBGRAPH_OFFSET_Green_NotBlue, 3 * 2 + SUBGRAPH_OFFSET_Red_NotBlue}, + })); + + // RB Pair. + ASSERT_EQ( + collect(AtomicErrorKey{0, 2, BOUNDARY_NODE}), + (S{ + {0 * 2 + SUBGRAPH_OFFSET_Red_NotBlue, 2 * 2 + SUBGRAPH_OFFSET_Blue_NotRed}, + {0 * 2 + SUBGRAPH_OFFSET_Red_NotGreen, 2 * 2 + SUBGRAPH_OFFSET_Blue_NotGreen}, + })); + ASSERT_EQ( + collect(AtomicErrorKey{3, 2, BOUNDARY_NODE}), + (S{ + {2 * 2 + SUBGRAPH_OFFSET_Blue_NotRed, 3 * 2 + SUBGRAPH_OFFSET_Red_NotBlue}, + {2 * 2 + SUBGRAPH_OFFSET_Blue_NotGreen, 3 * 2 + SUBGRAPH_OFFSET_Red_NotGreen}, + })); + + // GB Pair. + ASSERT_EQ( + collect(AtomicErrorKey{1, 2, BOUNDARY_NODE}), + (S{ + {1 * 2 + SUBGRAPH_OFFSET_Green_NotBlue, 2 * 2 + SUBGRAPH_OFFSET_Blue_NotGreen}, + {1 * 2 + SUBGRAPH_OFFSET_Green_NotRed, 2 * 2 + SUBGRAPH_OFFSET_Blue_NotRed}, + })); + ASSERT_EQ( + collect(AtomicErrorKey{4, 2, BOUNDARY_NODE}), + (S{ + {2 * 2 + SUBGRAPH_OFFSET_Blue_NotGreen, 4 * 2 + SUBGRAPH_OFFSET_Green_NotBlue}, + {2 * 2 + SUBGRAPH_OFFSET_Blue_NotRed, 4 * 2 + SUBGRAPH_OFFSET_Green_NotRed}, + })); + + // RGB triplet. + ASSERT_EQ( + collect(AtomicErrorKey{0, 1, 2}), + (S{ + {0 * 2 + SUBGRAPH_OFFSET_Red_NotGreen, 2 * 2 + SUBGRAPH_OFFSET_Blue_NotGreen}, + {0 * 2 + SUBGRAPH_OFFSET_Red_NotBlue, 1 * 2 + SUBGRAPH_OFFSET_Green_NotBlue}, + {1 * 2 + SUBGRAPH_OFFSET_Green_NotRed, 2 * 2 + SUBGRAPH_OFFSET_Blue_NotRed}, + })); + ASSERT_EQ( + collect(AtomicErrorKey{1, 2, 3}), + (S{ + {2 * 2 + SUBGRAPH_OFFSET_Blue_NotGreen, 3 * 2 + SUBGRAPH_OFFSET_Red_NotGreen}, + {1 * 2 + SUBGRAPH_OFFSET_Green_NotBlue, 3 * 2 + SUBGRAPH_OFFSET_Red_NotBlue}, + {1 * 2 + SUBGRAPH_OFFSET_Green_NotRed, 2 * 2 + SUBGRAPH_OFFSET_Blue_NotRed}, + })); + ASSERT_EQ( + collect(AtomicErrorKey{2, 3, 4}), + (S{ + {2 * 2 + SUBGRAPH_OFFSET_Blue_NotGreen, 3 * 2 + SUBGRAPH_OFFSET_Red_NotGreen}, + {3 * 2 + SUBGRAPH_OFFSET_Red_NotBlue, 4 * 2 + SUBGRAPH_OFFSET_Green_NotBlue}, + {2 * 2 + SUBGRAPH_OFFSET_Blue_NotRed, 4 * 2 + SUBGRAPH_OFFSET_Green_NotRed}, + })); +} diff --git a/src/chromobius/datatypes/color_basis.cc b/src/chromobius/datatypes/color_basis.cc new file mode 100644 index 0000000..fc18664 --- /dev/null +++ b/src/chromobius/datatypes/color_basis.cc @@ -0,0 +1,152 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/datatypes/color_basis.h" + +#include + +using namespace chromobius; + +bool ColorBasis::operator==(const ColorBasis &other) const { + return color == other.color && basis == other.basis; +} + +bool ColorBasis::operator!=(const ColorBasis &other) const { + return !(*this == other); +} +std::string ColorBasis::str() const { + std::stringstream ss; + ss << *this; + return ss.str(); +} +std::ostream &chromobius::operator<<(std::ostream &out, const ColorBasis &val) { + out << "ColorBasis{.color=" << val.color << ", .basis=" << val.basis << "}"; + return out; +} + +std::ostream &chromobius::operator<<(std::ostream &out, const Basis &val) { + switch (val) { + case Basis::UNKNOWN_BASIS: + out << "UNKNOWN_BASIS"; + break; + case Basis::X: + out << "X"; + break; + case Basis::Z: + out << "Z"; + break; + default: + out << (int)val; + } + return out; +} + +std::ostream &chromobius::operator<<(std::ostream &out, const Charge &val) { + switch (val) { + case Charge::NEUTRAL: + out << "NEUTRAL"; + break; + case Charge::R: + out << "R"; + break; + case Charge::G: + out << "G"; + break; + case Charge::B: + out << "B"; + break; + default: + out << (int)val; + } + return out; +} +std::ostream &chromobius::operator<<(std::ostream &out, const SubGraphCoord &val) { + switch (val) { + case SubGraphCoord::UNKNOWN_SUBGRAPH_COORD: + out << "UNKNOWN_SUBGRAPH_COORD"; + break; + case SubGraphCoord::NotRed: + out << "NotRed"; + break; + case SubGraphCoord::NotGreen: + out << "NotGreen"; + break; + case SubGraphCoord::NotBlue: + out << "NotBlue"; + break; + default: + out << (int)val; + } + return out; +} + +ColorBasis chromobius::detector_instruction_to_color_basis( + const stim::DemInstruction &instruction, std::span coord_offsets) { + assert(instruction.type == stim::DemInstructionType::DEM_ERROR); + double c = -1; + if (instruction.arg_data.size() > 3) { + c = instruction.arg_data[3]; + if (coord_offsets.size() > 3) { + c += coord_offsets[3]; + } + } + int r = (int)c; + if (r < 0 || r >= 6 || r != c) { + throw std::invalid_argument( + "Expected all detectors to have at least 4 coordinates, with the 4th " + "identifying the basis and color " + "(RedX=0, GreenX=1, BlueX=2, RedZ=3, GreenZ=4, BlueZ=5), but got " + + instruction.str()); + } + constexpr std::array mapping{ + ColorBasis{Charge::R, Basis::X}, + ColorBasis{Charge::G, Basis::X}, + ColorBasis{Charge::B, Basis::X}, + ColorBasis{Charge::R, Basis::Z}, + ColorBasis{Charge::G, Basis::Z}, + ColorBasis{Charge::B, Basis::Z}, + }; + return mapping[r]; +} + +std::tuple chromobius::mobius_node_to_detector( + uint64_t mobius_node, std::span colors) { + auto n = mobius_node >> 1; + uint8_t g = (mobius_node & 1) + 1; + Charge c = colors[n].color; + g += (uint8_t)g >= (uint8_t)c; + return {n, c, (SubGraphCoord)g}; +} + +uint64_t chromobius::detector_to_mobius_node( + node_offset_int node, SubGraphCoord subgraph, std::span colors) { + auto c = colors[node].color; + uint8_t offset; + if (c == Charge::R && subgraph == SubGraphCoord::NotGreen) { + offset = SUBGRAPH_OFFSET_Red_NotGreen; + } else if (c == Charge::R && subgraph == SubGraphCoord::NotBlue) { + offset = SUBGRAPH_OFFSET_Red_NotBlue; + } else if (c == Charge::G && subgraph == SubGraphCoord::NotRed) { + offset = SUBGRAPH_OFFSET_Green_NotRed; + } else if (c == Charge::G && subgraph == SubGraphCoord::NotBlue) { + offset = SUBGRAPH_OFFSET_Green_NotBlue; + } else if (c == Charge::B && subgraph == SubGraphCoord::NotRed) { + offset = SUBGRAPH_OFFSET_Blue_NotRed; + } else if (c == Charge::B && subgraph == SubGraphCoord::NotGreen) { + offset = SUBGRAPH_OFFSET_Blue_NotGreen; + } else { + throw std::invalid_argument("Bad node subgraph."); + } + return node * 2 + offset; +} diff --git a/src/chromobius/datatypes/color_basis.h b/src/chromobius/datatypes/color_basis.h new file mode 100644 index 0000000..fae48fc --- /dev/null +++ b/src/chromobius/datatypes/color_basis.h @@ -0,0 +1,85 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_COLOR_BASIS_H +#define _CHROMOBIUS_COLOR_BASIS_H + +#include +#include + +#include "chromobius/datatypes/conf.h" +#include "stim.h" + +namespace chromobius { + +enum Charge : uint8_t { + NEUTRAL = 0, + R = 1, + G = 2, + B = 3, +}; +inline Charge next_non_neutral_charge(Charge c) { + return (Charge)(c % 3 + 1); +} +inline Charge operator^(Charge c1, Charge c2) { + return (Charge)((uint8_t)c1 ^ (uint8_t)c2); +} +inline Charge &operator^=(Charge &c1, Charge c2) { + c1 = (Charge)((uint8_t)c1 ^ (uint8_t)c2); + return c1; +} + +enum SubGraphCoord : uint8_t { + UNKNOWN_SUBGRAPH_COORD = 0, + NotRed = 1, + NotGreen = 2, + NotBlue = 3, +}; + +constexpr uint8_t SUBGRAPH_OFFSET_Red_NotGreen = 0; +constexpr uint8_t SUBGRAPH_OFFSET_Red_NotBlue = 1; +constexpr uint8_t SUBGRAPH_OFFSET_Green_NotRed = 0; +constexpr uint8_t SUBGRAPH_OFFSET_Green_NotBlue = 1; +constexpr uint8_t SUBGRAPH_OFFSET_Blue_NotRed = 0; +constexpr uint8_t SUBGRAPH_OFFSET_Blue_NotGreen = 1; + +enum Basis : uint8_t { + UNKNOWN_BASIS = 0, + X = 1, + Z = 2, +}; + +struct ColorBasis { + Charge color; + Basis basis; + bool operator==(const ColorBasis &other) const; + bool operator!=(const ColorBasis &other) const; + std::string str() const; +}; +std::ostream &operator<<(std::ostream &out, const ColorBasis &val); +std::ostream &operator<<(std::ostream &out, const Charge &val); +std::ostream &operator<<(std::ostream &out, const SubGraphCoord &val); +std::ostream &operator<<(std::ostream &out, const Basis &val); + +ColorBasis detector_instruction_to_color_basis( + const stim::DemInstruction &instruction, std::span coord_offsets); +std::tuple mobius_node_to_detector( + uint64_t mobius_node, std::span colors); +uint64_t detector_to_mobius_node(node_offset_int node, SubGraphCoord subgraph, std::span colors); + +} // namespace chromobius + +#endif diff --git a/src/chromobius/datatypes/color_basis.test.cc b/src/chromobius/datatypes/color_basis.test.cc new file mode 100644 index 0000000..186acc7 --- /dev/null +++ b/src/chromobius/datatypes/color_basis.test.cc @@ -0,0 +1,89 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/datatypes/color_basis.h" + +#include "gtest/gtest.h" + +using namespace chromobius; + +TEST(types, color_basis_basic) { + ColorBasis e{.color = Charge::R, .basis = Basis::X}; + + ASSERT_TRUE(e == (ColorBasis{.color = Charge::R, .basis = Basis::X})); + ASSERT_FALSE(e == (ColorBasis{.color = Charge::G, .basis = Basis::X})); + ASSERT_FALSE(e == (ColorBasis{.color = Charge::R, .basis = Basis::Z})); + + ASSERT_TRUE(e != (ColorBasis{.color = Charge::G, .basis = Basis::X})); + + ASSERT_EQ(e.str(), "ColorBasis{.color=R, .basis=X}"); +} + +TEST(atomic_error, detector_instruction_to_color_basis) { + std::vector args{-1, -1, -1, 2}; + std::vector offsets{-3, -3, -3, 3, -2}; + stim::DemInstruction instruction{ + .arg_data = args, + .target_data = {}, + .type = stim::DemInstructionType::DEM_ERROR, + }; + ASSERT_EQ(detector_instruction_to_color_basis(instruction, offsets), (ColorBasis{Charge::B, Basis::Z})); + offsets[3] = 100; + ASSERT_THROW({ detector_instruction_to_color_basis(instruction, offsets); }, std::invalid_argument); + offsets[3] = 0.5; + ASSERT_THROW({ detector_instruction_to_color_basis(instruction, offsets); }, std::invalid_argument); + args[3] = 0.5; + ASSERT_EQ(detector_instruction_to_color_basis(instruction, offsets), (ColorBasis{Charge::G, Basis::X})); +} + +TEST(atomic_error, mobius_node_to_detector_vs_detector_to_mobius_node) { + std::vector colors; + colors.resize(50); + + colors[29].color = Charge::R; + ASSERT_EQ( + mobius_node_to_detector(29 * 2 + SUBGRAPH_OFFSET_Red_NotGreen, colors), + (std::tuple(29, Charge::R, SubGraphCoord::NotGreen))); + ASSERT_EQ(detector_to_mobius_node(29, SubGraphCoord::NotGreen, colors), 29 * 2 + SUBGRAPH_OFFSET_Red_NotGreen); + + colors[31].color = Charge::R; + ASSERT_EQ( + mobius_node_to_detector(31 * 2 + SUBGRAPH_OFFSET_Red_NotBlue, colors), + (std::tuple(31, Charge::R, SubGraphCoord::NotBlue))); + ASSERT_EQ(detector_to_mobius_node(31, SubGraphCoord::NotBlue, colors), 31 * 2 + SUBGRAPH_OFFSET_Red_NotBlue); + + colors[36].color = Charge::G; + ASSERT_EQ( + mobius_node_to_detector(36 * 2 + SUBGRAPH_OFFSET_Green_NotRed, colors), + (std::tuple(36, Charge::G, SubGraphCoord::NotRed))); + ASSERT_EQ(detector_to_mobius_node(36, SubGraphCoord::NotRed, colors), 36 * 2 + SUBGRAPH_OFFSET_Green_NotRed); + + colors[41].color = Charge::G; + ASSERT_EQ( + mobius_node_to_detector(41 * 2 + SUBGRAPH_OFFSET_Green_NotBlue, colors), + (std::tuple(41, Charge::G, SubGraphCoord::NotBlue))); + ASSERT_EQ(detector_to_mobius_node(41, SubGraphCoord::NotBlue, colors), 41 * 2 + SUBGRAPH_OFFSET_Green_NotBlue); + + colors[43].color = Charge::B; + ASSERT_EQ( + mobius_node_to_detector(43 * 2 + SUBGRAPH_OFFSET_Blue_NotRed, colors), + (std::tuple(43, Charge::B, SubGraphCoord::NotRed))); + ASSERT_EQ(detector_to_mobius_node(43, SubGraphCoord::NotRed, colors), 43 * 2 + SUBGRAPH_OFFSET_Blue_NotRed); + + colors[47].color = Charge::B; + ASSERT_EQ( + mobius_node_to_detector(47 * 2 + SUBGRAPH_OFFSET_Blue_NotGreen, colors), + (std::tuple(47, Charge::B, SubGraphCoord::NotGreen))); + ASSERT_EQ(detector_to_mobius_node(47, SubGraphCoord::NotGreen, colors), 47 * 2 + SUBGRAPH_OFFSET_Blue_NotGreen); +} diff --git a/src/chromobius/datatypes/conf.h b/src/chromobius/datatypes/conf.h new file mode 100644 index 0000000..526da5d --- /dev/null +++ b/src/chromobius/datatypes/conf.h @@ -0,0 +1,31 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_TYPES_H +#define _CHROMOBIUS_TYPES_H + +#include +#include + +namespace chromobius { + +typedef uint64_t obsmask_int; +typedef uint32_t node_offset_int; +constexpr node_offset_int BOUNDARY_NODE = (node_offset_int)-1; + +} // namespace chromobius + +#endif diff --git a/src/chromobius/datatypes/rgb_edge.cc b/src/chromobius/datatypes/rgb_edge.cc new file mode 100644 index 0000000..e94a10e --- /dev/null +++ b/src/chromobius/datatypes/rgb_edge.cc @@ -0,0 +1,76 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/datatypes/rgb_edge.h" + +#include +#include + +using namespace chromobius; + +bool RgbEdge::operator==(const RgbEdge &other) const { + return red_node == other.red_node && blue_node == other.blue_node && green_node == other.green_node && + obs_flip == other.obs_flip && charge_flip == other.charge_flip; +} +bool RgbEdge::operator!=(const RgbEdge &other) const { + return !(*this == other); +} +std::string RgbEdge::str() const { + std::stringstream ss; + ss << *this; + return ss.str(); +} +std::ostream &chromobius::operator<<(std::ostream &out, const RgbEdge &val) { + out << "RgbEdge{.red_node="; + if (val.red_node == BOUNDARY_NODE) { + out << "BOUNDARY_NODE"; + } else { + out << val.red_node; + } + out << ", .green_node="; + if (val.green_node == BOUNDARY_NODE) { + out << "BOUNDARY_NODE"; + } else { + out << val.green_node; + } + out << ", .blue_node="; + if (val.blue_node == BOUNDARY_NODE) { + out << "BOUNDARY_NODE"; + } else { + out << val.blue_node; + } + out << ", .obs_flip=" << val.obs_flip; + out << ", .charge_flip=" << val.charge_flip; + out << "}"; + return out; +} +size_t RgbEdge::weight() const { + return (red_node != BOUNDARY_NODE) + (green_node != BOUNDARY_NODE) + (blue_node != BOUNDARY_NODE); +} + +bool RgbEdge::operator<(const RgbEdge &other) const { + if (red_node != other.red_node) { + return red_node < other.red_node; + } + if (green_node != other.green_node) { + return green_node < other.green_node; + } + if (blue_node != other.blue_node) { + return blue_node < other.blue_node; + } + if (obs_flip != other.obs_flip) { + return obs_flip < other.obs_flip; + } + return charge_flip < other.charge_flip; +} diff --git a/src/chromobius/datatypes/rgb_edge.h b/src/chromobius/datatypes/rgb_edge.h new file mode 100644 index 0000000..4e9f935 --- /dev/null +++ b/src/chromobius/datatypes/rgb_edge.h @@ -0,0 +1,59 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_DEM_GRAPH_H +#define _CHROMOBIUS_DEM_GRAPH_H + +#include +#include + +#include "chromobius/datatypes/atomic_error.h" +#include "chromobius/datatypes/color_basis.h" +#include "stim.h" + +namespace chromobius { + +struct RgbEdge; + +/// Represents an error with at most one symptom of each color. +struct RgbEdge { + node_offset_int red_node; + node_offset_int green_node; + node_offset_int blue_node; + obsmask_int obs_flip; + Charge charge_flip; + + inline node_offset_int color_node(Charge c) const { + if (c == 0) { + return BOUNDARY_NODE; + } + return (&red_node)[c - 1]; + } + inline node_offset_int &color_node(Charge c) { + return (&red_node)[c - 1]; + } + + size_t weight() const; + bool operator<(const RgbEdge &other) const; + bool operator==(const RgbEdge &other) const; + bool operator!=(const RgbEdge &other) const; + std::string str() const; +}; +std::ostream &operator<<(std::ostream &out, const RgbEdge &val); + +} // namespace chromobius + +#endif diff --git a/src/chromobius/datatypes/rgb_edge.test.cc b/src/chromobius/datatypes/rgb_edge.test.cc new file mode 100644 index 0000000..abce97e --- /dev/null +++ b/src/chromobius/datatypes/rgb_edge.test.cc @@ -0,0 +1,52 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/datatypes/rgb_edge.h" + +#include "gtest/gtest.h" + +using namespace chromobius; + +TEST(dem_rgb_edge, dem_rgb_edge_basics) { + RgbEdge e{.red_node = 5, .green_node = 7, .blue_node = 9, .obs_flip = 1, .charge_flip = Charge::NEUTRAL}; + + ASSERT_TRUE(e == (RgbEdge{5, 7, 9, 1, Charge::NEUTRAL})); + ASSERT_FALSE(e == (RgbEdge{4, 7, 9, 1, Charge::NEUTRAL})); + ASSERT_FALSE(e == (RgbEdge{5, 6, 9, 1, Charge::NEUTRAL})); + ASSERT_FALSE(e == (RgbEdge{5, 7, 8, 1, Charge::NEUTRAL})); + ASSERT_FALSE(e == (RgbEdge{5, 7, 9, 2, Charge::NEUTRAL})); + ASSERT_FALSE(e == (RgbEdge{5, 7, 9, 1, Charge::R})); + + ASSERT_TRUE(e != (RgbEdge{5, 7, 9, 2, Charge::NEUTRAL})); + ASSERT_FALSE(e != (RgbEdge{5, 7, 9, 1, Charge::NEUTRAL})); + + ASSERT_EQ( + e.str(), + "RgbEdge{.red_node=5, .green_node=7, .blue_node=9, .obs_flip=1, " + ".charge_flip=NEUTRAL}"); +} + +TEST(dem_rgb_edge, dem_rgb_edge_weight) { + ASSERT_EQ((RgbEdge{.red_node = 2, .green_node = 3, .blue_node = 7, .obs_flip = 5}.weight()), 3); + ASSERT_EQ((RgbEdge{.red_node = 2, .green_node = 3, .blue_node = 7, .obs_flip = 0}.weight()), 3); + ASSERT_EQ( + (RgbEdge{.red_node = BOUNDARY_NODE, .green_node = BOUNDARY_NODE, .blue_node = 7, .obs_flip = 5}.weight()), 1); + ASSERT_EQ( + (RgbEdge{.red_node = BOUNDARY_NODE, .green_node = BOUNDARY_NODE, .blue_node = BOUNDARY_NODE, .obs_flip = 5} + .weight()), + 0); + ASSERT_EQ((RgbEdge{.red_node = BOUNDARY_NODE, .green_node = 3, .blue_node = 7, .obs_flip = 5}.weight()), 2); + ASSERT_EQ((RgbEdge{.red_node = 2, .green_node = BOUNDARY_NODE, .blue_node = 7, .obs_flip = 5}.weight()), 2); + ASSERT_EQ((RgbEdge{.red_node = 2, .green_node = 5, .blue_node = BOUNDARY_NODE, .obs_flip = 5}.weight()), 2); +} diff --git a/src/chromobius/decode/decoder.cc b/src/chromobius/decode/decoder.cc new file mode 100644 index 0000000..fb3b0bd --- /dev/null +++ b/src/chromobius/decode/decoder.cc @@ -0,0 +1,288 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/decode/decoder.h" + +#include "chromobius/decode/pymatcher.h" +#include "chromobius/graph/choose_rgb_reps.h" +#include "chromobius/graph/collect_composite_errors.h" +#include "chromobius/graph/collect_nodes.h" + +using namespace chromobius; + +Decoder Decoder::from_dem(const stim::DetectorErrorModel &dem, DecoderConfigOptions options) { + Decoder result; + + // Find color of each detector, while optionally adding coordinate data to the mobius dem. + result.node_colors = collect_nodes_from_dem(dem, options.include_coords_in_mobius_dem ? &result.mobius_dem : nullptr); + + // Find the basic building-block errors that errors will be decomposed into. + result.atomic_errors = collect_atomic_errors(dem, result.node_colors); + + // Decompose all errors into the building-block errors, adding them into the mobius dem. + // To make the decomposition more robust, a composite error can split into a known building block and a remnant. + // The remnants are accumulated so they can be added to the building blocks before continuing. + std::map remnant_edges; + collect_composite_errors_and_remnants_into_mobius_dem( + dem, + result.node_colors, + result.atomic_errors, + options.drop_mobius_errors_involving_remnant_errors, + options.ignore_decomposition_failures, + &result.mobius_dem, + &remnant_edges); + for (const auto &e : remnant_edges) { + result.atomic_errors.emplace(std::move(e)); + } + if (!options.include_coords_in_mobius_dem || result.mobius_dem.count_detectors() < result.node_colors.size() * 2) { + // Ensure the number of detectors in the mobius dem is exactly correct. + result.mobius_dem.append_detector_instruction( + {}, stim::DemTarget::relative_detector_id(result.node_colors.size() * 2 - 1)); + } + + // For each node, pick nearby RGB representatives for holding charge near that node. + result.rgb_reps = choose_rgb_reps_from_atomic_errors(result.atomic_errors, result.node_colors); + + // Find the basic ways for moving charge around the graph, by combining pairs of errors to get simpler errors. + result.charge_graph = ChargeGraph::from_atomic_errors(result.atomic_errors, result.node_colors.size()); + + // Solve for how to drag charge around the graph while travelling from node to node. + result.drag_graph = DragGraph::from_charge_graph_paths_for_sub_edges_of_atomic_errors( + result.charge_graph, result.atomic_errors, result.rgb_reps, result.node_colors); + + // Prepare the matcher. + result.matcher = options.matcher_for(result.mobius_dem); + result.euler_tour_solver = EulerTourGraph(result.node_colors.size() * 2); + + return result; +} + +std::unique_ptr DecoderConfigOptions::matcher_for(const stim::DetectorErrorModel &mobius_dem) const { + if (matcher) { + return matcher->configured_for_mobius_dem(mobius_dem); + } + std::unique_ptr result; + result.reset(new PymatchingMatcher(mobius_dem)); + return result; +} + +static std::optional discharge_cycle_helper_single_start_charge_many_cur_charge( + std::span node_colors, + std::span rgb_reps, + const DragGraph &drag_graph, + std::span packed_bit_packed_detection_events, + std::span cycle, + Charge start_charge, + std::vector *used_buf) { + + used_buf->clear(); + std::array, 4> cur_states; + cur_states[start_charge] = {0}; + node_offset_int cur_loc = cycle.back() >> 1; + + for (size_t k = 0; k < cycle.size(); k++) { + node_offset_int next_loc = cycle[k] >> 1; + + bool has_detection_event_at_loc = (packed_bit_packed_detection_events[cur_loc >> 3]) & (1 << (cur_loc & 7)); + if (next_loc == cur_loc && has_detection_event_at_loc && std::find(used_buf->begin(), used_buf->end(), cur_loc) == used_buf->end()) { + // Pick up the detection event. + used_buf->push_back(cur_loc); + Charge det_charge = node_colors[cur_loc].color; + std::array, 4> states_after_det; + states_after_det[det_charge] = cur_states[Charge::NEUTRAL]; + states_after_det[Charge::NEUTRAL] = cur_states[det_charge]; + auto r = rgb_reps[cur_loc]; + if (r.weight() == 3) { + auto c1 = next_non_neutral_charge(det_charge); + auto c2 = next_non_neutral_charge(c1); + if (cur_states[c1].has_value()) { + states_after_det[c2] = *cur_states[c1] ^ r.obs_flip; + } + if (cur_states[c2].has_value()) { + states_after_det[c1] = *cur_states[c2] ^ r.obs_flip; + } + } + cur_states = states_after_det; + } else { + // Drag the current charge to near the new location, potentially switching the charge type. + std::array, 4> states_after_drag; + for (size_t cur_charge = 0; cur_charge < 4; cur_charge++) { + const auto &cur_obs_flip = cur_states[cur_charge]; + if (cur_obs_flip.has_value()) { + for (size_t next_charge = 0; next_charge < 4; next_charge++) { + auto f = drag_graph.mmm.find(ChargedEdge{ + .n1 = cur_loc, .n2 = next_loc, .c1 = (Charge)cur_charge, .c2 = (Charge)next_charge}); + if (f != drag_graph.mmm.end()) { + states_after_drag[next_charge] = *cur_obs_flip ^ f->second; + } + } + } + } + cur_states = states_after_drag; + } + cur_loc = next_loc; + } + + return cur_states[start_charge]; +} + +static std::optional discharge_cycle_helper_any_start_charge_many_cur_charge( + std::span node_colors, + std::span rgb_reps, + const DragGraph &drag_graph, + std::span packed_bit_packed_detection_events, + std::span cycle, + std::vector *used_buf) { + + for (size_t c = 0; c < 4; c++) { + auto v = discharge_cycle_helper_single_start_charge_many_cur_charge( + node_colors, + rgb_reps, + drag_graph, + packed_bit_packed_detection_events, + cycle, + (Charge)c, + used_buf); + if (v.has_value()) { + return v; + } + } + return {}; +} +obsmask_int Decoder::discharge_cycle( + std::span packed_bit_packed_detection_events, std::span cycle) { + auto result = discharge_cycle_helper_any_start_charge_many_cur_charge( + node_colors, + rgb_reps, + drag_graph, + packed_bit_packed_detection_events, + cycle, + &resolved_detection_event_buffer); + if (result.has_value()) { + return *result; + } + + std::stringstream ss; + ss << "Failed to lift a flattened edge cycle from the matcher into an explanation of the detection events in the cycle.\n"; + ss << "This error could be due to a coloring error in the model used to configure the decoder, or a bug in the decoder.\n"; + ss << "The cycle: {"; + for (auto e : cycle) { + auto d = e >> 1; + ss << "\n D" << d << "["; + ss << node_colors[d].color; + ss << node_colors[d].basis; + if (packed_bit_packed_detection_events[d >> 3] & (1 << (d & 7))) { + ss << ", triggered"; + } + ss << "]"; + } + ss << "\n}\n"; + ss << "All detection events in the shot: {"; + for (size_t k = 0; k < node_colors.size(); k++) { + if (packed_bit_packed_detection_events[k >> 3] & (1 << (k & 7))) { + ss << "\n D" << k << "["; + ss << node_colors[k].color; + ss << node_colors[k].basis; + ss << ", triggered]"; + } + } + ss << "\n}"; + + throw std::invalid_argument(ss.str()); +} + +static void check_mobius_dem_errors_are_edge_like(const Decoder &decoder) { + for (const auto &instruction : decoder.mobius_dem.instructions) { + bool instruction_valid = true; + if (instruction.type == stim::DemInstructionType::DEM_ERROR) { + for (size_t k = 0; k < instruction.target_data.size(); k += 3) { + instruction_valid &= instruction.target_data[k].is_relative_detector_id(); + } + for (size_t k = 1; k < instruction.target_data.size(); k += 3) { + instruction_valid &= instruction.target_data[k].is_relative_detector_id(); + } + for (size_t k = 2; k < instruction.target_data.size(); k += 3) { + instruction_valid &= instruction.target_data[k].is_separator(); + } + instruction_valid &= instruction.target_data.size() % 3 == 2; + } + if (!instruction_valid) { + throw std::invalid_argument( + "A mobius dem error wasn't split into pairs of detectors: " + instruction.str()); + } + } +} + +void Decoder::check_invariants() const { + check_mobius_dem_errors_are_edge_like(*this); +} + +static void detection_events_to_mobius_detection_events( + std::span bit_packed_detection_events, + std::vector *out_mobius_detection_events) { + // Derive the mobius matching problem. + for (size_t k = 0; k < bit_packed_detection_events.size(); k++) { + for (uint8_t b = bit_packed_detection_events[k], k2 = 0; b; b >>= 1, k2++) { + if (b & 1) { + auto d = k * 8 + k2; + out_mobius_detection_events->push_back(d * 2 + 0); + out_mobius_detection_events->push_back(d * 2 + 1); + } + } + } +} + +obsmask_int Decoder::decode_detection_events(std::span bit_packed_detection_events) { + // Derive and decode the mobius matching problem. + sparse_det_buffer.clear(); + matcher_edge_buf.clear(); + detection_events_to_mobius_detection_events(bit_packed_detection_events, &sparse_det_buffer); + matcher->match_edges(sparse_det_buffer, &matcher_edge_buf); + + // Write solution to stderr if requested. + if (write_mobius_match_to_std_err) { + std::cerr << "matched "; + for (size_t k = 0; k < matcher_edge_buf.size(); k += 2) { + auto [n1, c1, g1] = mobius_node_to_detector(matcher_edge_buf[k], node_colors); + auto [n2, c2, g2] = mobius_node_to_detector(matcher_edge_buf[k + 1], node_colors); + std::cerr << " [" << n1 << "," << c1 << "," << g1 << "]:[" << n2 << "," << c2 << "," << g2 << "]"; + } + std::cerr << "\n"; + } + + // Lift the solution by decomposing into disjoint Euler cycles and solving each cycle. + obsmask_int solution = 0; + euler_tour_solver.iter_euler_tours_of_interleaved_edge_list( + matcher_edge_buf, + sparse_det_buffer, + [&](std::span cycle) { + solution ^= discharge_cycle(bit_packed_detection_events, cycle); + }); + + return solution; +} + +std::ostream &chromobius::operator<<(std::ostream &out, const Decoder &val) { + out << "chromobius::Decoder{\n\n"; + out << ".charge_graph=" << val.charge_graph << "\n\n"; + out << ".rgb_reps={"; + for (size_t k = 0; k < val.rgb_reps.size(); k++) { + out << "\n " << val.rgb_reps[k] << " // rep " << k; + } + out << "\n}\n\n"; + out << ".drag_graph=" << val.drag_graph << "\n\n"; + out << ".mobius_dem=stim::DetectorErrorModel{\n" << val.mobius_dem << "\n}"; + out << "\n\n}"; + return out; +} diff --git a/src/chromobius/decode/decoder.h b/src/chromobius/decode/decoder.h new file mode 100644 index 0000000..6c4820a --- /dev/null +++ b/src/chromobius/decode/decoder.h @@ -0,0 +1,149 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_DECODER_H +#define _CHROMOBIUS_DECODER_H + +#include "chromobius/datatypes/rgb_edge.h" +#include "chromobius/graph/charge_graph.h" +#include "chromobius/graph/collect_atomic_errors.h" +#include "chromobius/graph/collect_composite_errors.h" +#include "chromobius/graph/collect_nodes.h" +#include "chromobius/graph/drag_graph.h" +#include "chromobius/graph/euler_tours.h" +#include "chromobius/decode/matcher_interface.h" + +namespace chromobius { + +/// Invariant: drain_cycle_index_1 <= drain_cycle_index_2 +struct ChargeDrain { + size_t drain_cycle_index_1; + Charge charge1; // Set to Charge::NEUTRAL to disable. + + size_t drain_cycle_index_2; + Charge charge2; // Set to Charge::NEUTRAL to disable. +}; + +struct DecoderConfigOptions { + /// Controls whether or not errors that required the introduction of a + /// remnant atomic error in order to decompose should be discarded or not. + /// Defaults to true because that seems to give the best performance in + /// the most cases. + bool drop_mobius_errors_involving_remnant_errors = true; + + /// When an error is encountered that can't be understood in terms of + /// atomic errors, this decides whether or not that error is simply + /// discarded or else if an exception is raised. + bool ignore_decomposition_failures = false; + + /// Decides whether or not the underlying mobius detector error model will + /// contain coordinate information. This can be useful when debugging or + /// printing out information. + bool include_coords_in_mobius_dem = false; + + /// Decides which matcher to use. If not set to anything, chromobius will + /// default to using PyMatching. + std::shared_ptr matcher; + + std::unique_ptr matcher_for(const stim::DetectorErrorModel &mobius_dem) const; +}; + +struct Decoder { + /// The color and basis of each node in the graph. + std::vector node_colors; + /// The basic errors that more complex errors are decomposed into. + std::map atomic_errors; + /// The doubled detector error model given to the matcher. + stim::DetectorErrorModel mobius_dem; + + ChargeGraph charge_graph; + std::vector rgb_reps; + DragGraph drag_graph; + bool write_mobius_match_to_std_err = false; + + /// The configured matcher (e.g. from pymatching) used to decode the mobius problem. + std::unique_ptr matcher; + + /// Ephemeral workspace for putting detection event data to give to the matcher. + std::vector sparse_det_buffer; + /// Ephemeral workspace for the matcher to save its results into. + std::vector matcher_edge_buf; + /// Ephemeral workspace for decomposing results from the matcher into separately solvable pieces. + EulerTourGraph euler_tour_solver{0}; + /// Ephemeral workspace for tracking which detection events have been processed (within one euler cycle). + std::vector resolved_detection_event_buffer; + + /// Creates a decoder for a DEM with annotated detector colors and bases. + /// + /// The input DEM must have each detector annotated with its basis and color. + /// The annotations use the 4th coordinate of the detector to do this. The + /// value of the 4th coordinate identifies the basis and color: + /// 0: basis=X, color=R + /// 1: basis=X, color=G + /// 2: basis=X, color=B + /// 3: basis=Z, color=R + /// 4: basis=Z, color=G + /// 5: basis=Z, color=B + /// + /// Args: + /// dem: The detector error model to configure the decoder with. + /// options: Various configuration options affecting how decoding is + /// configured and performed. See the DecoderConfigOptions class + /// for details. + /// + /// Returns: + /// The configured decoder, ready to perform decoding. + static Decoder from_dem( + const stim::DetectorErrorModel &dem, + DecoderConfigOptions options); + + void check_invariants() const; + + /// Predicts the observables flipped by errors producing the given detection + /// events. + /// + /// As part of running, this method clears the detection event data back to 0. + obsmask_int decode_detection_events(std::span bit_packed_detection_events); + + private: + /// Handles getting rid of excitation events within a cycle found by the + /// matcher. + /// + /// This method requires that either the cycle has neutral charge, or that + /// there are subgraph-crossing edges to dump the charge into + /// + /// Args: + /// packed_detection_event_data_to_clear: The detection events being + /// explained. + /// As part of running, the method will all detection events within + /// the cycle. + /// cycle: The cycle of nodes to process. The specific format here + /// alternates + /// between node indices and the charge change to the next node. So, + /// for example, the cycle might be [5, NEUTRAL, 8, NEUTRAL, 9, RED, + /// 10, NEUTRAL]. + /// + /// Returns: + /// The observables that were flipped by the errors inserted to clear out + /// the detection events. + obsmask_int discharge_cycle( + std::span packed_detection_event_data_to_clear, std::span cycle); +}; +std::ostream &operator<<(std::ostream &out, const Decoder &val); + +} // namespace chromobius + +#endif diff --git a/src/chromobius/decode/decoder.perf.cc b/src/chromobius/decode/decoder.perf.cc new file mode 100644 index 0000000..d97a975 --- /dev/null +++ b/src/chromobius/decode/decoder.perf.cc @@ -0,0 +1,206 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/decode/decoder.h" + +#include + +#include "chromobius/util.perf.h" +#include "stim.h" + +using namespace chromobius; + +FILE *open_test_data_file(const char *name) { + std::vector directories_to_check = { + "test_data/", + "../test_data/", + "../../test_data/", + }; + for (const auto &d : directories_to_check) { + std::string path = d + name; + FILE *f = fopen((d + name).c_str(), "r"); + if (f != nullptr) { + return f; + } + } + throw std::invalid_argument("Failed to find test data file " + std::string(name)); +} + +BENCHMARK(configure_midout_color_code_d25_r100_p1000) { + FILE *f = open_test_data_file("midout_color_code_d25_r100_p1000.stim"); + stim::Circuit src_circuit = stim::Circuit::from_file(f); + fclose(f); + auto src_dem = + stim::ErrorAnalyzer::circuit_to_detector_error_model(src_circuit, false, true, false, 0, false, false); + + size_t k = 0; + benchmark_go([&]() { + Decoder d = Decoder::from_dem(src_dem, DecoderConfigOptions{}); + k += d.mobius_dem.instructions.size(); + k += d.matcher_edge_buf.size(); + k += d.atomic_errors.size(); + k += d.drag_graph.mmm.size(); + }).goal_millis(1800); + if (k == 1) { + std::cerr << "data dependence"; + } +} + +BENCHMARK(configure_midout_color_code_d9_r36_p1000) { + FILE *f = open_test_data_file("midout_color_code_d9_r36_p1000.stim"); + stim::Circuit src_circuit = stim::Circuit::from_file(f); + fclose(f); + auto src_dem = + stim::ErrorAnalyzer::circuit_to_detector_error_model(src_circuit, false, true, false, 0, false, false); + + size_t k = 0; + benchmark_go([&]() { + Decoder d = Decoder::from_dem(src_dem, DecoderConfigOptions{}); + k += d.mobius_dem.instructions.size(); + k += d.matcher_edge_buf.size(); + k += d.atomic_errors.size(); + k += d.drag_graph.mmm.size(); + }).goal_millis(60); + if (k == 1) { + std::cerr << "data dependence"; + } +} + +BENCHMARK(configure_midout_color_code_d5_r10_p1000) { + FILE *f = open_test_data_file("midout_color_code_d5_r10_p1000.stim"); + stim::Circuit src_circuit = stim::Circuit::from_file(f); + fclose(f); + auto src_dem = + stim::ErrorAnalyzer::circuit_to_detector_error_model(src_circuit, false, true, false, 0, false, false); + + size_t k = 0; + benchmark_go([&]() { + Decoder d = Decoder::from_dem(src_dem, DecoderConfigOptions{}); + k += d.mobius_dem.instructions.size(); + k += d.matcher_edge_buf.size(); + k += d.atomic_errors.size(); + k += d.drag_graph.mmm.size(); + }).goal_millis(3.4); + if (k == 1) { + std::cerr << "data dependence"; + } +} + +BENCHMARK(decode_midout_color_code_d5_r10_p1000) { + FILE *f = open_test_data_file("midout_color_code_d5_r10_p1000.stim"); + stim::Circuit src_circuit = stim::Circuit::from_file(f); + fclose(f); + auto src_dem = + stim::ErrorAnalyzer::circuit_to_detector_error_model(src_circuit, false, true, false, 0, false, false); + Decoder decoder = Decoder::from_dem(src_dem, DecoderConfigOptions{}); + + size_t num_shots = 1024; + std::mt19937_64 rng{0}; + auto sample = stim::sample_batch_detection_events<64>(src_circuit, num_shots, rng); + auto &dets = sample.first; + auto &obs_actual = sample.second; + dets = dets.transposed(); + obs_actual = obs_actual.transposed(); + size_t num_dets = 0; + for (size_t k = 0; k < num_shots; k++) { + num_dets += dets[k].popcnt(); + } + + size_t mistakes = 0; + benchmark_go([&]() { + for (size_t k = 0; k < num_shots; k++) { + std::span det_data{dets[k].u8, dets[k].u8 + dets.num_minor_u8_padded()}; + auto obs_predicted = decoder.decode_detection_events(det_data); + mistakes += obs_actual[k].u64[0] != obs_predicted; + } + }) + .goal_millis(4.5) + .show_rate("shots", num_shots) + .show_rate("dets", num_dets); + if (mistakes == 1) { + std::cerr << "data dependence"; + } +} + +BENCHMARK(decode_midout_color_code_d9_r36_p1000) { + FILE *f = open_test_data_file("midout_color_code_d9_r36_p1000.stim"); + stim::Circuit src_circuit = stim::Circuit::from_file(f); + fclose(f); + auto src_dem = + stim::ErrorAnalyzer::circuit_to_detector_error_model(src_circuit, false, true, false, 0, false, false); + Decoder decoder = Decoder::from_dem(src_dem, DecoderConfigOptions{}); + + size_t num_shots = 1024; + std::mt19937_64 rng{0}; + auto sample = stim::sample_batch_detection_events<64>(src_circuit, num_shots, rng); + auto &dets = sample.first; + auto &obs_actual = sample.second; + dets = dets.transposed(); + obs_actual = obs_actual.transposed(); + size_t num_dets = 0; + for (size_t k = 0; k < num_shots; k++) { + num_dets += dets[k].popcnt(); + } + + size_t mistakes = 0; + benchmark_go([&]() { + for (size_t k = 0; k < num_shots; k++) { + std::span det_data{dets[k].u8, dets[k].u8 + dets.num_minor_u8_padded()}; + auto obs_predicted = decoder.decode_detection_events(det_data); + mistakes += obs_actual[k].u64[0] != obs_predicted; + } + }) + .goal_millis(90) + .show_rate("shots", num_shots) + .show_rate("dets", num_dets); + if (mistakes == 1) { + std::cerr << "data dependence"; + } +} + +BENCHMARK(decode_midout_color_code_d25_r100_p1000) { + FILE *f = open_test_data_file("midout_color_code_d25_r100_p1000.stim"); + stim::Circuit src_circuit = stim::Circuit::from_file(f); + fclose(f); + auto src_dem = + stim::ErrorAnalyzer::circuit_to_detector_error_model(src_circuit, false, true, false, 0, false, false); + Decoder decoder = Decoder::from_dem(src_dem, DecoderConfigOptions{}); + size_t num_shots = 128; + + std::mt19937_64 rng{0}; + auto sample = stim::sample_batch_detection_events<64>(src_circuit, num_shots, rng); + auto &dets = sample.first; + auto &obs_actual = sample.second; + dets = dets.transposed(); + obs_actual = obs_actual.transposed(); + size_t num_dets = 0; + for (size_t k = 0; k < num_shots; k++) { + num_dets += dets[k].popcnt(); + } + + size_t mistakes = 0; + benchmark_go([&]() { + for (size_t k = 0; k < num_shots; k++) { + std::span det_data{dets[k].u8, dets[k].u8 + dets.num_minor_u8_padded()}; + auto obs_predicted = decoder.decode_detection_events(det_data); + mistakes += obs_actual[k].u64[0] != obs_predicted; + } + }) + .goal_millis(420) + .show_rate("shots", num_shots) + .show_rate("dets", num_dets); + if (mistakes == 1) { + std::cerr << "data dependence"; + } +} diff --git a/src/chromobius/decode/decoder.test.cc b/src/chromobius/decode/decoder.test.cc new file mode 100644 index 0000000..dfade11 --- /dev/null +++ b/src/chromobius/decode/decoder.test.cc @@ -0,0 +1,141 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/decode/decoder.h" + +#include "gtest/gtest.h" + +#include "chromobius/test_util.test.h" + +using namespace chromobius; + +TEST(decoder, from_dem_d5_color_code_x_only) { + stim::DetectorErrorModel dem(R"DEM( + error(0.1) D0 L0 L1 + error(0.1) D0 D2 L0 + error(0.1) D2 D3 L0 + error(0.1) D3 D7 L0 + error(0.1) D7 L0 + error(0.1) D0 D1 + error(0.1) D0 D1 D2 L1 + error(0.1) D1 D2 D4 L1 + error(0.1) D1 D4 + error(0.1) D4 D6 + error(0.1) D6 + error(0.1) D6 D8 + error(0.1) D4 D5 D8 L1 + error(0.1) D2 D4 D5 + error(0.1) D3 D5 D7 + error(0.1) D5 D7 + error(0.1) D5 D8 L1 + error(0.1) D2 D3 D5 + error(0.1) D4 D6 D8 + detector(+0, 0, 0, 0) D0 + detector(+0, 2, 0, 1) D2 + detector(+0, 4, 0, 2) D5 + detector(+1, 1, 0, 2) D1 + detector(+1, 3, 0, 0) D4 + detector(+1, 5, 0, 1) D8 + detector(+2, 4, 0, 2) D6 + detector(-1, 3, 0, 0) D3 + detector(-1, 5, 0, 1) D7 + )DEM"); + Decoder decoder = Decoder::from_dem(dem, DecoderConfigOptions{}); + ASSERT_EQ( + decoder.node_colors, + (std::vector{ + {.color = Charge::R, .basis = Basis::X}, + {.color = Charge::B, .basis = Basis::X}, + {.color = Charge::G, .basis = Basis::X}, + {.color = Charge::R, .basis = Basis::X}, + {.color = Charge::R, .basis = Basis::X}, + {.color = Charge::B, .basis = Basis::X}, + {.color = Charge::B, .basis = Basis::X}, + {.color = Charge::G, .basis = Basis::X}, + {.color = Charge::G, .basis = Basis::X}})); + ASSERT_EQ( + decoder.rgb_reps, + (std::vector{ + {.red_node = 0, .green_node = 2, .blue_node = 1, .obs_flip = 0b10}, + {.red_node = 0, .green_node = 2, .blue_node = 1, .obs_flip = 0b10}, + {.red_node = 0, .green_node = 2, .blue_node = 1, .obs_flip = 0b10}, + {.red_node = 3, .green_node = 2, .blue_node = 5, .obs_flip = 0b00}, + {.red_node = 4, .green_node = 2, .blue_node = 1, .obs_flip = 0b10}, + {.red_node = 3, .green_node = 2, .blue_node = 5, .obs_flip = 0b00}, + {.red_node = 4, .green_node = 8, .blue_node = 6, .obs_flip = 0b00}, + {.red_node = 3, .green_node = 7, .blue_node = 5, .obs_flip = 0b00}, + {.red_node = 4, .green_node = 8, .blue_node = 5, .obs_flip = 0b10}, + })); + stim::DetectorErrorModel expected_mobius_dem(R"DEM( + error(0.01) D0 D1 + error(0.1) D0 D4 ^ D1 D5 + error(0.1) D4 D6 ^ D5 D7 + error(0.1) D6 D14 ^ D7 D15 + error(0.01) D14 D15 + error(0.1) D0 D3 ^ D1 D2 + error(0.1) D1 D5 ^ D2 D4 ^ D0 D3 + error(0.1) D5 D9 ^ D2 D4 ^ D3 D8 + error(0.1) D2 D9 ^ D3 D8 + error(0.1) D8 D13 ^ D9 D12 + error(0.01) D12 D13 + error(0.1) D12 D16 ^ D13 D17 + error(0.1) D9 D17 ^ D10 D16 ^ D8 D11 + error(0.1) D5 D9 ^ D4 D10 ^ D8 D11 + error(0.1) D7 D15 ^ D10 D14 ^ D6 D11 + error(0.1) D10 D14 ^ D11 D15 + error(0.1) D10 D16 ^ D11 D17 + error(0.1) D5 D7 ^ D4 D10 ^ D6 D11 + error(0.1) D9 D17 ^ D12 D16 ^ D8 D13 + detector D17 + )DEM"); + ASSERT_TRUE(decoder.mobius_dem.approx_equals(expected_mobius_dem, 1e-5)); +} + +TEST(decoder, mobius_dem) { + stim::DetectorErrorModel dem(R"DEM( + error(0.125) D0 D1 D2 + error(0.0625) D3 D4 D5 + error(0.0625) D0 D1 D2 D3 D4 D5 + error(0.25) D0 L1 + detector(0, 0, 0, 0) D0 + detector(0, 0, 0, 1) D1 + detector(0, 0, 0, 2) D2 + detector(0, 0, 0, 3) D3 + repeat 2 { + detector(0, 0, 0, 4) D4 + shift_detectors(0, 0, 0, 1) 1 + } + )DEM"); + + Decoder decoder = Decoder::from_dem(dem, DecoderConfigOptions{.include_coords_in_mobius_dem=true}); + stim::DetectorErrorModel expected(R"DEM( + detector(0, 0, 0, 0, 2) D0 + detector(0, 0, 0, 0, 3) D1 + detector(0, 0, 0, 1, 1) D2 + detector(0, 0, 0, 1, 3) D3 + detector(0, 0, 0, 2, 1) D4 + detector(0, 0, 0, 2, 2) D5 + detector(0, 0, 0, 3, 2) D6 + detector(0, 0, 0, 3, 3) D7 + detector(0, 0, 0, 4, 1) D8 + detector(0, 0, 0, 4, 3) D9 + detector(0, 0, 0, 5, 1) D10 + detector(0, 0, 0, 5, 2) D11 + error(0.125) D1 D3 ^ D2 D4 ^ D0 D5 + error(0.0625) D7 D9 ^ D8 D10 ^ D6 D11 + error(0.0625) D1 D3 ^ D2 D4 ^ D0 D5 ^ D7 D9 ^ D8 D10 ^ D6 D11 + error(0.0625) D0 D1 + )DEM"); + ASSERT_TRUE(decoder.mobius_dem.approx_equals(expected, 1e-5)); +} diff --git a/src/chromobius/decode/decoder_integration.test.cc b/src/chromobius/decode/decoder_integration.test.cc new file mode 100644 index 0000000..af21b22 --- /dev/null +++ b/src/chromobius/decode/decoder_integration.test.cc @@ -0,0 +1,175 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" + +#include "chromobius/decode/decoder.h" +#include "chromobius/test_util.test.h" + +using namespace chromobius; + +size_t count_mistakes_decoding_test_data_file(size_t shots, const char *name) { + FILE *f = open_test_data_file(name); + stim::Circuit src_circuit = stim::Circuit::from_file(f); + fclose(f); + auto src_dem = + stim::ErrorAnalyzer::circuit_to_detector_error_model(src_circuit, false, true, false, 0, false, false); + Decoder decoder = Decoder::from_dem(src_dem, DecoderConfigOptions{}); + decoder.check_invariants(); + + std::mt19937_64 rng{0}; + size_t mistakes = 0; + auto [dets, obs_actual] = stim::sample_batch_detection_events<64>(src_circuit, shots, rng); + dets = dets.transposed(); + obs_actual = obs_actual.transposed(); + for (size_t k = 0; k < shots; k++) { + std::span det_data{dets[k].u8, dets[k].u8 + dets.num_minor_u8_padded()}; + auto obs_predicted = decoder.decode_detection_events(det_data); + mistakes += obs_actual[k].u64[0] != obs_predicted; + } + return mistakes; +} + +void verify_error_resilience(const char *name) { + FILE *f = open_test_data_file(name); + stim::Circuit src_circuit = stim::Circuit::from_file(f); + fclose(f); + auto src_dem = + stim::ErrorAnalyzer::circuit_to_detector_error_model(src_circuit, false, false, false, 0, false, false); + Decoder decoder = Decoder::from_dem(src_dem, DecoderConfigOptions{}); + size_t num_dets = (size_t)src_dem.count_detectors(); + + std::set bad_error_set; + std::vector bad_errors; + stim::DemSampler sampler(src_dem, std::mt19937_64{0}, 1024); + + // Work in batches of 1024 to reduce sampling cost. + for (size_t err_start = 0; err_start < num_dets; err_start += 1024) { + for (size_t k = 0; k < 1024; k++) { + size_t err_k = err_start + k; + if (err_k < num_dets) { + sampler.err_buffer[err_k][k] = 1; + } + } + sampler.resample(true); + + auto dets = sampler.det_buffer.transposed(); + auto obs_actual = sampler.obs_buffer.transposed(); + for (size_t k = 0; k < 1024; k++) { + size_t err_k = k + err_start; + std::span det_data{dets[k].u8, dets[k].u8 + dets.num_minor_u8_padded()}; + + obsmask_int obs_predicted; + try { + obs_predicted = decoder.decode_detection_events(det_data); + if (obs_actual[k].u64[0] != obs_predicted) { + bad_errors.push_back(err_k); + bad_error_set.insert(err_k); + } + } catch (const std::exception &ex) { + dets.clear(); + bad_errors.push_back(err_k); + bad_error_set.insert(err_k); + } + } + + sampler.err_buffer.clear(); + } + + if (!bad_errors.empty()) { + std::set included_detector_indices; + for (size_t k = 0; k < num_dets; k++) { + included_detector_indices.insert(k); + } + auto coords = src_dem.get_detector_coordinates(included_detector_indices); + stim::DetectorErrorModel bad_dem; + size_t err_index = 0; + for (const auto &instruction : src_dem.instructions) { + if (instruction.type == stim::DemInstructionType::DEM_ERROR) { + if (bad_error_set.contains(err_index)) { + bad_dem.append_dem_instruction(instruction); + } + err_index++; + } + } + auto explained = stim::ErrorMatcher::explain_errors_from_circuit(src_circuit, &bad_dem, true); + std::stringstream ss; + for (size_t k = 0; k < explained.size(); k++) { + ss << "\nFailed to correct error #" << bad_errors[k] << " from " << name << ":\n"; + ss << "\n " << bad_dem.instructions[k]; + for (auto t : bad_dem.instructions[k].target_data) { + if (t.is_relative_detector_id()) { + ss << "\n " << decoder.node_colors[t.val()]; + } + } + ss << "\n " << explained[k] << "\n"; + } + EXPECT_TRUE(bad_errors.empty()) << ss.str(); + } +} + +obsmask_int decode_single(const char *name, const std::vector detection_events) { + FILE *f = open_test_data_file(name); + stim::Circuit src_circuit = stim::Circuit::from_file(f); + fclose(f); + auto src_dem = + stim::ErrorAnalyzer::circuit_to_detector_error_model(src_circuit, false, false, false, 0, false, false); + Decoder decoder = Decoder::from_dem(src_dem, DecoderConfigOptions{}); + size_t num_dets = (size_t)src_dem.count_detectors(); + + stim::simd_bits<64> dets(num_dets); + for (const auto &d : detection_events) { + dets[d] = 1; + } + std::span det_data{dets.u8, dets.u8 + dets.num_u8_padded()}; + return decoder.decode_detection_events(det_data); +} + +struct IntegrationTestData : public testing::TestWithParam> {}; +INSTANTIATE_TEST_SUITE_P( + IntegrationTests, + IntegrationTestData, + ::testing::Values( + std::tuple{"toric_superdense_color_code_epr_d12_r5_p1000.stim", 1693}, + std::tuple{"midout488_color_code_d9_r33_p1000.stim", 823}, + std::tuple{"midout_color_code_d5_r10_p1000.stim", 94}, + std::tuple{"midout_color_code_d9_r36_p1000.stim", 45}, + std::tuple{"superdense_color_code_d5_r20_p1000.stim", 329}, // Including remnant errors reduces to 273? + std::tuple{"phenom_color_code_d5_r5_p1000.stim", 0}, + std::tuple{"surface_code_d5_r5_p1000.stim", 3}, + std::tuple{"rep_code_d9_transit_p10.stim", 1}, + std::tuple{"rep_code_rg_d9_transit_p10.stim", 1}, + std::tuple{"rep_code_rbrrr_d9_transit_p10.stim", 1}, + std::tuple{"color2surface_d5_transit_p100.stim", 1}, + std::tuple{"color2surface_d7_phenom_r7_p100.stim", 12} + )); + +TEST_P(IntegrationTestData, expected_failure_count) { + auto [name, expected] = GetParam(); + auto mistakes = count_mistakes_decoding_test_data_file(8192, name); + EXPECT_EQ(mistakes, expected) << name; +} + +TEST_P(IntegrationTestData, single_error_resilience) { + auto [name, expected] = GetParam(); + verify_error_resilience(name); +} + +TEST(FixCheck, euler_tour_ordering) { + decode_single("fix_check_1.stim", {8687, 8736, 8737, 8763, 8945, 8720}); +} + +TEST(FixCheck, phenom_rgb_reps_for_last_layer) { + decode_single("fix_check_1.stim", {8915, 8914, 8890}); +} diff --git a/src/chromobius/decode/matcher_interface.h b/src/chromobius/decode/matcher_interface.h new file mode 100644 index 0000000..ca2bd1e --- /dev/null +++ b/src/chromobius/decode/matcher_interface.h @@ -0,0 +1,49 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_DECODE_MATCHER_INTERFACE_H +#define _CHROMOBIUS_DECODE_MATCHER_INTERFACE_H + +#include +#include +#include + +#include "stim.h" + +namespace chromobius { + +/// This class is used to implement polymorphism +struct MatcherInterface { + virtual ~MatcherInterface(){}; + + /// Creates a new instance of the matcher, configured for the given detector error model. + virtual std::unique_ptr configured_for_mobius_dem(const stim::DetectorErrorModel &dem) = 0; + + /// Performs matching on the given mobius dem detection events, producing edges. + /// + /// Args: + /// mobius_detection_event_indices: The detection events to decode. + /// out_edge_buffer: Where to write edges to. Edges should be rewritten in an + /// interleaved fashion, so that (out_edge_buffer[2*k], out_edge_buffer[2*k+1]) + /// is an edge. There should be no boundary edges in the result, since the mobius + /// dem is guaranteed to not contain any boundary edges. + virtual void match_edges( + const std::vector &mobius_detection_event_indices, std::vector *out_edge_buffer) = 0; +}; + +} // namespace chromobius + +#endif diff --git a/src/chromobius/decode/pymatcher.cc b/src/chromobius/decode/pymatcher.cc new file mode 100644 index 0000000..8fe9e02 --- /dev/null +++ b/src/chromobius/decode/pymatcher.cc @@ -0,0 +1,35 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/decode/pymatcher.h" + +using namespace chromobius; + +PymatchingMatcher::PymatchingMatcher() : pymatching_matcher() { +} + +PymatchingMatcher::PymatchingMatcher(const stim::DetectorErrorModel &dem) + : pymatching_matcher(pm::detector_error_model_to_mwpm(dem, 1 << 24, true)) { +} + +void PymatchingMatcher::match_edges( + const std::vector &mobius_detection_event_indices, std::vector *out_edge_buffer) { + pm::decode_detection_events_to_edges(pymatching_matcher, mobius_detection_event_indices, *out_edge_buffer); +} + +std::unique_ptr PymatchingMatcher::configured_for_mobius_dem(const stim::DetectorErrorModel &dem) { + std::unique_ptr result; + result.reset(new PymatchingMatcher(dem)); + return result; +} diff --git a/src/chromobius/decode/pymatcher.h b/src/chromobius/decode/pymatcher.h new file mode 100644 index 0000000..765507e --- /dev/null +++ b/src/chromobius/decode/pymatcher.h @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_DECODE_PYMATCHER_H +#define _CHROMOBIUS_DECODE_PYMATCHER_H + +#include "chromobius/decode/matcher_interface.h" +#include "pymatching/sparse_blossom/driver/mwpm_decoding.h" + +namespace chromobius { + +struct PymatchingMatcher : MatcherInterface { + pm::Mwpm pymatching_matcher; + + PymatchingMatcher(); + PymatchingMatcher(const stim::DetectorErrorModel &dem); + virtual ~PymatchingMatcher() = default; + + virtual std::unique_ptr configured_for_mobius_dem(const stim::DetectorErrorModel &dem) override; + + virtual void match_edges( + const std::vector &mobius_detection_event_indices, std::vector *out_edge_buffer) override; +}; + +} // namespace chromobius + +#endif diff --git a/src/chromobius/graph/charge_graph.cc b/src/chromobius/graph/charge_graph.cc new file mode 100644 index 0000000..eef80ef --- /dev/null +++ b/src/chromobius/graph/charge_graph.cc @@ -0,0 +1,157 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/charge_graph.h" + +#include +#include +#include + +using namespace chromobius; + +bool ChargeGraphNode::operator==(const ChargeGraphNode &other) const { + return neighbors == other.neighbors; +} +bool ChargeGraphNode::operator!=(const ChargeGraphNode &other) const { + return !(*this == other); +} +std::string ChargeGraphNode::str() const { + std::stringstream ss; + ss << *this; + return ss.str(); +} + +std::ostream &chromobius::operator<<(std::ostream &out, const ChargeGraphNode &val) { + out << "ChargeGraphNode{.neighbors={"; + std::vector ns; + for (const auto &p : val.neighbors) { + ns.push_back(p.first); + } + std::sort(ns.begin(), ns.end()); + for (size_t k = 0; k < ns.size(); k++) { + if (k > 0) { + out << ", "; + } + out << "{"; + if (ns[k] == BOUNDARY_NODE) { + out << "BOUNDARY_NODE"; + } else { + out << ns[k]; + } + out << "," << val.neighbors.at(ns[k]) << "}"; + } + out << "}}"; + return out; +} + +bool ChargeGraph::operator==(const ChargeGraph &other) const { + return nodes == other.nodes; +} +bool ChargeGraph::operator!=(const ChargeGraph &other) const { + return !(*this == other); +} +std::string ChargeGraph::str() const { + std::stringstream ss; + ss << *this; + return ss.str(); +} +std::ostream &chromobius::operator<<(std::ostream &out, const ChargeGraph &val) { + out << "ChargeGraph{.nodes={\n"; + for (size_t k = 0; k < val.nodes.size(); k++) { + out << " " << val.nodes[k] << ", // node " << k << "\n"; + } + out << "}}"; + return out; +} + +void ChargeGraph::add_edge(node_offset_int n1, node_offset_int n2, obsmask_int obs_flip) { + if (n1 != BOUNDARY_NODE) { + nodes[n1].neighbors[n2] = obs_flip; + } + if (n2 != BOUNDARY_NODE) { + nodes[n2].neighbors[n1] = obs_flip; + } +} + +ChargeGraph ChargeGraph::from_atomic_errors( + const std::map &atomic_errors, size_t num_nodes) { + + // Create a charge graph of the correct size. + ChargeGraph charge_graph; + charge_graph.nodes.resize(num_nodes); + for (size_t k = 0; k < num_nodes; k++) { + charge_graph.nodes[k].neighbors[k] = obsmask_int{0}; + } + + // Add all directly included edges into the charge graph. + for (const auto &[err, obs_flip] : atomic_errors) { + if (err.dets[2] == BOUNDARY_NODE) { + charge_graph.add_edge(err.dets[0], err.dets[1], obs_flip); + } + } + + // Index errors by each node touched by the error. + std::map> node2neighbors; + for (const auto &[err, obs_flip] : atomic_errors) { + for (auto n : err.dets) { + if (n != BOUNDARY_NODE) { + node2neighbors[n].push_back(err); + } + } + } + + // Form more graphlike edges by pairing overlapping errors. + stim::SparseXorVec xor_buf; + for (const auto &[_, neighbors] : node2neighbors) { + for (size_t k1 = 0; k1 < neighbors.size(); k1++) { + for (size_t k2 = k1 + 1; k2 < neighbors.size(); k2++) { + const auto &e1 = neighbors[k1]; + const auto &e2 = neighbors[k2]; + if (e1.weight() < 3 && e2.weight() < 3) { + // These errors were already graphlike. + continue; + } + + // Merge the errors. + xor_buf.clear(); + xor_buf.xor_item(e1.dets[0]); + xor_buf.xor_item(e1.dets[1]); + xor_buf.xor_item(e1.dets[2]); + xor_buf.xor_item(e2.dets[0]); + xor_buf.xor_item(e2.dets[1]); + xor_buf.xor_item(e2.dets[2]); + + // Check if the resulting error is graphlike, pulling out its symptoms. + node_offset_int a; + node_offset_int b; + if (xor_buf.sorted_items.size() == 1) { + a = xor_buf.sorted_items[0]; + b = BOUNDARY_NODE; + } else if ( + xor_buf.sorted_items.size() == 2 || + (xor_buf.sorted_items.size() == 3 && xor_buf.sorted_items.back() == BOUNDARY_NODE)) { + a = xor_buf.sorted_items[0]; + b = xor_buf.sorted_items[1]; + } else { + continue; + } + + // Add the composite graphlike error into the graph. + charge_graph.add_edge(a, b, atomic_errors.at(e1) ^ atomic_errors.at(e2)); + } + } + } + + return charge_graph; +} diff --git a/src/chromobius/graph/charge_graph.h b/src/chromobius/graph/charge_graph.h new file mode 100644 index 0000000..29be611 --- /dev/null +++ b/src/chromobius/graph/charge_graph.h @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_CHARGE_GRAPH_H +#define _CHROMOBIUS_CHARGE_GRAPH_H + +#include +#include +#include + +#include "chromobius/datatypes/rgb_edge.h" +#include "stim.h" + +namespace chromobius { + +struct ChargeGraphNode; + +/// Like the error graph, but hyperedges have been combined into normal edges. +/// +/// Every edge in the charge graph is graphlike (degree 2 or degree 1). The +/// charge graph includes edges that were in the original detector error model, +/// as well as synthetic edges that can be formed by combining pairs of RGB +/// errors from the original detector error model. +/// +/// Stored as an adjacency list graph. +struct ChargeGraph { + std::vector nodes; + + static ChargeGraph from_atomic_errors(const std::map &atomic_errors, size_t num_nodes); + + void add_edge(node_offset_int n1, node_offset_int n2, obsmask_int obs_flip); + bool operator==(const ChargeGraph &other) const; + bool operator!=(const ChargeGraph &other) const; + std::string str() const; +}; +std::ostream &operator<<(std::ostream &out, const ChargeGraph &val); + +struct ChargeGraphNode { + std::unordered_map neighbors; + + bool operator==(const ChargeGraphNode &other) const; + bool operator!=(const ChargeGraphNode &other) const; + std::string str() const; +}; +std::ostream &operator<<(std::ostream &out, const ChargeGraphNode &val); + +} // namespace chromobius + +#endif diff --git a/src/chromobius/graph/charge_graph.test.cc b/src/chromobius/graph/charge_graph.test.cc new file mode 100644 index 0000000..73fd6f9 --- /dev/null +++ b/src/chromobius/graph/charge_graph.test.cc @@ -0,0 +1,272 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/charge_graph.h" + +#include "gtest/gtest.h" + +using namespace chromobius; + +TEST(charge_graph, charge_node_basics) { + ChargeGraphNode n{.neighbors = {{5, 1}, {6, 2}}}; + + ASSERT_TRUE(n == (ChargeGraphNode{.neighbors = {{5, 1}, {6, 2}}})); + ASSERT_FALSE(n == (ChargeGraphNode{.neighbors = {{7, 1}, {6, 2}}})); + ASSERT_FALSE(n == (ChargeGraphNode{.neighbors = {}})); + ASSERT_FALSE(n != (ChargeGraphNode{.neighbors = {{5, 1}, {6, 2}}})); + + ASSERT_EQ(n.str(), "ChargeGraphNode{.neighbors={{5,1}, {6,2}}}"); +} + +TEST(charge_graph, charge_graph_basics) { + ChargeGraph g{ + .nodes = { + ChargeGraphNode{.neighbors = {{0, 0}, {1, 5}}}, + ChargeGraphNode{.neighbors = {{0, 5}, {1, 0}}}, + }}; + + ASSERT_TRUE( + g == (ChargeGraph{ + .nodes = { + ChargeGraphNode{.neighbors = {{0, 0}, {1, 5}}}, + ChargeGraphNode{.neighbors = {{0, 5}, {1, 0}}}, + }})); + ASSERT_FALSE(g == (ChargeGraph{})); + ASSERT_TRUE(g != (ChargeGraph{})); + + ASSERT_EQ(g.str(), R"GRAPH(ChargeGraph{.nodes={ + ChargeGraphNode{.neighbors={{0,0}, {1,5}}}, // node 0 + ChargeGraphNode{.neighbors={{0,5}, {1,0}}}, // node 1 +}})GRAPH"); +} + +TEST(charge_graph, from_dem_edges_basic_cases) { + ChargeGraph actual; + + actual= ChargeGraph::from_atomic_errors({ + }, 3); + ASSERT_EQ(actual, (ChargeGraph{.nodes={ + ChargeGraphNode{.neighbors={{0, 0}}}, + ChargeGraphNode{.neighbors={{1, 0}}}, + ChargeGraphNode{.neighbors={{2, 0}}}, + }})); + + actual = ChargeGraph::from_atomic_errors({ + {AtomicErrorKey{1, BOUNDARY_NODE, BOUNDARY_NODE}, 0b1}, + }, 3); + ASSERT_EQ(actual, (ChargeGraph{.nodes={ + ChargeGraphNode{.neighbors={{0, 0}}}, + ChargeGraphNode{.neighbors={{1, 0}, {BOUNDARY_NODE, 0b1}}}, + ChargeGraphNode{.neighbors={{2, 0}}}, + }})); + + actual = ChargeGraph::from_atomic_errors({ + {AtomicErrorKey{1, 2, BOUNDARY_NODE}, 0b100}, + }, 3); + ASSERT_EQ(actual, (ChargeGraph{.nodes={ + ChargeGraphNode{.neighbors={{0, 0}}}, + ChargeGraphNode{.neighbors={{1, 0}, {2, 0b100}}}, + ChargeGraphNode{.neighbors={{1, 0b100}, {2, 0}}}, + }})); + + actual = ChargeGraph::from_atomic_errors({ + {AtomicErrorKey{1, 2, 0}, 0b100}, + }, 3); + ASSERT_EQ(actual, (ChargeGraph{.nodes={ + ChargeGraphNode{.neighbors={{0, 0}}}, + ChargeGraphNode{.neighbors={{1, 0}}}, + ChargeGraphNode{.neighbors={{2, 0}}}, + }})); + + actual = ChargeGraph::from_atomic_errors({ + {AtomicErrorKey{1, 2, 0}, 0b100}, + {AtomicErrorKey{1, 2, 3}, 0b010}, + }, 4); + ASSERT_EQ(actual, (ChargeGraph{.nodes={ + ChargeGraphNode{.neighbors={{0, 0}, {3, 0b110}}}, + ChargeGraphNode{.neighbors={{1, 0}}}, + ChargeGraphNode{.neighbors={{2, 0}}}, + ChargeGraphNode{.neighbors={{0, 0b110}, {3, 0}}}, + }})); +// +// ASSERT_EQ( +// ChargeGraph::from_dem_edges( +// 4, +// (std::set{ +// DemEdge{.n1=2, .n2=3, .obs_flip=5}, +// }), +// (std::set{})), +// (ChargeGraph{.nodes={ +// ChargeGraphNode{.neighbors={{0, 0}}}, +// ChargeGraphNode{.neighbors={{1, 0}}}, +// ChargeGraphNode{.neighbors={{2, 0}, {3, 5}}}, +// ChargeGraphNode{.neighbors={{3, 0}, {2, 5}}}, +// }})); +// +// ASSERT_EQ( +// ChargeGraph::from_dem_edges( +// 3, +// (std::set{ +// DemEdge{.n1=1, .n2=2, .obs_flip=5}, +// }), +// (std::set{})), +// (ChargeGraph{.nodes={ +// ChargeGraphNode{.neighbors={{0, 0}}}, +// ChargeGraphNode{.neighbors={{1, 0}, {2, 5}}}, +// ChargeGraphNode{.neighbors={{2, 0}, {1, 5}}}, +// }})); +// +// ASSERT_EQ( +// ChargeGraph::from_dem_edges( +// 7, +// (std::set{}), +// (std::set{ +// RgbEdge{.red_node=2, .green_node=3, .blue_node=5, .obs_flip=7}, +// })), +// (ChargeGraph{.nodes={ +// ChargeGraphNode{.neighbors={{0, 0}}}, +// ChargeGraphNode{.neighbors={{1, 0}}}, +// ChargeGraphNode{.neighbors={{2, 0}}}, +// ChargeGraphNode{.neighbors={{3, 0}}}, +// ChargeGraphNode{.neighbors={{4, 0}}}, +// ChargeGraphNode{.neighbors={{5, 0}}}, +// ChargeGraphNode{.neighbors={{6, 0}}}, +// }})); +// +// ASSERT_EQ( +// ChargeGraph::from_dem_edges( +// 7, +// (std::set{}), +// (std::set{ +// RgbEdge{.red_node=2, .green_node=3, .blue_node=5, .obs_flip=7}, +// RgbEdge{.red_node=2, .green_node=3, .blue_node=4, .obs_flip=1}, +// })), +// (ChargeGraph{.nodes={ +// ChargeGraphNode{.neighbors={{0, 0}}}, +// ChargeGraphNode{.neighbors={{1, 0}}}, +// ChargeGraphNode{.neighbors={{2, 0}}}, +// ChargeGraphNode{.neighbors={{3, 0}}}, +// ChargeGraphNode{.neighbors={{4, 0}, {5, 6}}}, +// ChargeGraphNode{.neighbors={{5, 0}, {4, 6}}}, +// ChargeGraphNode{.neighbors={{6, 0}}}, +// }})); +// +// ASSERT_EQ( +// ChargeGraph::from_dem_edges( +// 7, +// (std::set{}), +// (std::set{ +// RgbEdge{.red_node=2, .green_node=3, .blue_node=5, .obs_flip=7}, +// RgbEdge{.red_node=2, .green_node=3, .blue_node=5, .obs_flip=1}, +// })), +// (ChargeGraph{.nodes={ +// ChargeGraphNode{.neighbors={{0, 0}}}, +// ChargeGraphNode{.neighbors={{1, 0}}}, +// ChargeGraphNode{.neighbors={{2, 0}}}, +// ChargeGraphNode{.neighbors={{3, 0}}}, +// ChargeGraphNode{.neighbors={{4, 0}}}, +// ChargeGraphNode{.neighbors={{5, 0}}}, +// ChargeGraphNode{.neighbors={{6, 0}}}, +// }})); +// +// ASSERT_EQ( +// ChargeGraph::from_dem_edges( +// 7, +// (std::set{}), +// (std::set{ +// RgbEdge{.red_node=2, .green_node=3, .blue_node=BOUNDARY_NODE, .obs_flip=7}, +// RgbEdge{.red_node=2, .green_node=3, .blue_node=4, .obs_flip=1}, +// })), +// (ChargeGraph{.nodes={ +// ChargeGraphNode{.neighbors={{0, 0}}}, +// ChargeGraphNode{.neighbors={{1, 0}}}, +// ChargeGraphNode{.neighbors={{2, 0}}}, +// ChargeGraphNode{.neighbors={{3, 0}}}, +// ChargeGraphNode{.neighbors={{4, 0}, {BOUNDARY_NODE, 6}}}, +// ChargeGraphNode{.neighbors={{5, 0}}}, +// ChargeGraphNode{.neighbors={{6, 0}}}, +// }})); +// +// ASSERT_EQ( +// ChargeGraph::from_dem_edges( +// 7, +// (std::set{}), +// (std::set{ +// RgbEdge{.red_node=2, .green_node=3, .blue_node=BOUNDARY_NODE, .obs_flip=7}, +// RgbEdge{.red_node=2, .green_node=BOUNDARY_NODE, .blue_node=4, .obs_flip=8}, +// })), +// (ChargeGraph{.nodes={ +// ChargeGraphNode{.neighbors={{0, 0}}}, +// ChargeGraphNode{.neighbors={{1, 0}}}, +// ChargeGraphNode{.neighbors={{2, 0}}}, +// ChargeGraphNode{.neighbors={{3, 0}, {4, 15}}}, +// ChargeGraphNode{.neighbors={{4, 0}, {3, 15}}}, +// ChargeGraphNode{.neighbors={{5, 0}}}, +// ChargeGraphNode{.neighbors={{6, 0}}}, +// }})); + } +// +// TEST(charge_graph, from_dem_edges_d5) { +// ASSERT_EQ( +// ChargeGraph::from_dem_edges( +// 10, +// (std::set{ +// DemEdge{.n1=1, .n2=BOUNDARY_NODE, .obs_flip=10}, +// DemEdge{.n1=1, .n2=3, .obs_flip=11}, +// DemEdge{.n1=1, .n2=2, .obs_flip=12}, +// DemEdge{.n1=3, .n2=4, .obs_flip=14}, +// DemEdge{.n1=2, .n2=5, .obs_flip=16}, +// DemEdge{.n1=5, .n2=7, .obs_flip=19}, +// DemEdge{.n1=4, .n2=8, .obs_flip=20}, +// DemEdge{.n1=8, .n2=BOUNDARY_NODE, .obs_flip=24}, +// DemEdge{.n1=6, .n2=8, .obs_flip=25}, +// DemEdge{.n1=6, .n2=9, .obs_flip=26}, +// DemEdge{.n1=7, .n2=9, .obs_flip=27}, +// DemEdge{.n1=7, .n2=BOUNDARY_NODE, .obs_flip=28}, +// }), +// (std::set{ +// RgbEdge{.red_node=BOUNDARY_NODE, .green_node=1, .blue_node=BOUNDARY_NODE, .obs_flip=10}, +// RgbEdge{.red_node=BOUNDARY_NODE, .green_node=1, .blue_node=3, .obs_flip=11}, +// RgbEdge{.red_node=2, .green_node=1, .blue_node=BOUNDARY_NODE, .obs_flip=12}, +// RgbEdge{.red_node=2, .green_node=1, .blue_node=3, .obs_flip=13}, +// RgbEdge{.red_node=BOUNDARY_NODE, .green_node=4, .blue_node=3, .obs_flip=14}, +// RgbEdge{.red_node=2, .green_node=5, .blue_node=3, .obs_flip=15}, +// RgbEdge{.red_node=2, .green_node=5, .blue_node=BOUNDARY_NODE, .obs_flip=16}, +// RgbEdge{.red_node=6, .green_node=4, .blue_node=3, .obs_flip=17}, +// RgbEdge{.red_node=6, .green_node=5, .blue_node=3, .obs_flip=18}, +// RgbEdge{.red_node=7, .green_node=5, .blue_node=BOUNDARY_NODE, .obs_flip=19}, +// RgbEdge{.red_node=BOUNDARY_NODE, .green_node=4, .blue_node=8, .obs_flip=20}, +// RgbEdge{.red_node=6, .green_node=4, .blue_node=8, .obs_flip=21}, +// RgbEdge{.red_node=6, .green_node=5, .blue_node=9, .obs_flip=22}, +// RgbEdge{.red_node=7, .green_node=5, .blue_node=9, .obs_flip=23}, +// RgbEdge{.red_node=BOUNDARY_NODE, .green_node=BOUNDARY_NODE, .blue_node=8, .obs_flip=24}, +// RgbEdge{.red_node=6, .green_node=BOUNDARY_NODE, .blue_node=8, .obs_flip=25}, +// RgbEdge{.red_node=6, .green_node=BOUNDARY_NODE, .blue_node=9, .obs_flip=26}, +// RgbEdge{.red_node=7, .green_node=BOUNDARY_NODE, .blue_node=9, .obs_flip=27}, +// RgbEdge{.red_node=7, .green_node=BOUNDARY_NODE, .blue_node=BOUNDARY_NODE, .obs_flip=28}, +// })), +// (ChargeGraph{.nodes={ +// ChargeGraphNode{.neighbors={{0, 0}}}, +// ChargeGraphNode{.neighbors={{1, 0}, {2, 12}, {3, 11}, {4, 11 ^ 14}, {5, 15 ^ 13}, {BOUNDARY_NODE, 10}}}, +// ChargeGraphNode{.neighbors={{2, 0}, {1, 12}, {3, 11 ^ 12}, {5, 16}, {6, 15 ^ 18}, {7, 19 ^ 16}, +// {BOUNDARY_NODE, 11 ^ 13}}}, ChargeGraphNode{.neighbors={{1,11}, {2,7}, {3,0}, {4,14}, {8,4}, {9,4}, +// {BOUNDARY_NODE,31}}}, ChargeGraphNode{.neighbors={{1,5}, {3,14}, {4,0}, {5,3}, {6,13}, {8,20}, +// {BOUNDARY_NODE,12}}}, ChargeGraphNode{.neighbors={{1,2}, {2,16}, {4,3}, {5,0}, {7,19}, {9,8}, +// {BOUNDARY_NODE,12}}}, ChargeGraphNode{.neighbors={{2,29}, {4,13}, {6,0}, {7,1}, {8,25}, {9,26}, +// {BOUNDARY_NODE,1}}}, ChargeGraphNode{.neighbors={{2,3}, {5,19}, {6,1}, {7,0}, {9,27}, +// {BOUNDARY_NODE,28}}}, ChargeGraphNode{.neighbors={{3,4}, {4,20}, {6,25}, {8,0}, {9,3}, +// {BOUNDARY_NODE,24}}}, ChargeGraphNode{.neighbors={{3,4}, {5,8}, {6,26}, {7,27}, {8,3}, {9,0}, +// {BOUNDARY_NODE,4}}}, +// }})); +// } diff --git a/src/chromobius/graph/choose_rgb_reps.cc b/src/chromobius/graph/choose_rgb_reps.cc new file mode 100644 index 0000000..b11a7ca --- /dev/null +++ b/src/chromobius/graph/choose_rgb_reps.cc @@ -0,0 +1,90 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/choose_rgb_reps.h" + +using namespace chromobius; + +std::vector chromobius::choose_rgb_reps_from_atomic_errors( + const std::map &atomic_errors, std::span node_colors) { + std::vector result; + RgbEdge empty{ + .red_node = BOUNDARY_NODE, + .green_node = BOUNDARY_NODE, + .blue_node = BOUNDARY_NODE, + .obs_flip = 0, + .charge_flip = Charge::NEUTRAL, + }; + result.resize(node_colors.size(), empty); + + // Assign node representatives from the highest weight RGB edges they are part + // of. + for (const auto &[err, obs_flip] : atomic_errors) { + RgbEdge rep{BOUNDARY_NODE, BOUNDARY_NODE, BOUNDARY_NODE, obs_flip, Charge::NEUTRAL}; + size_t weight = 0; + for (auto n : err.dets) { + if (n != BOUNDARY_NODE) { + Charge c = node_colors[n].color; + rep.color_node(c) = n; + rep.charge_flip ^= c; + weight += 1; + } + } + + if (rep.weight() != weight) { + // Color appeared more than once. + continue; + } + + for (node_offset_int n : err.dets) { + if (n != BOUNDARY_NODE && weight > result[n].weight()) { + result[n] = rep; + } + } + } + + // In a phenom circuit, the final layer of stabilizer measurements has no + // RGB errors. As a result, the detectors from this layer need to be linked + // together using RGB errors from the previous layer times a measurement error + // to the final layer. + for (const auto &[e, obs_flip] : atomic_errors) { + if (e.weight() != 2) { + continue; + } + Charge c1 = node_colors[e.dets[0]].color; + Charge c2 = node_colors[e.dets[1]].color; + if (c1 == c2) { + auto w1 = result[e.dets[0]].weight(); + auto w2 = result[e.dets[1]].weight(); + RgbEdge *r1 = &result[e.dets[0]]; + RgbEdge *r2 = &result[e.dets[1]]; + if (w1 == 0 && w2 > 0) { + *r1 = *r2; + assert(r1->color_node(c1) == e.dets[1]); + assert(r2->color_node(c1) == e.dets[1]); + r1->color_node(c1) = e.dets[0]; + r1->obs_flip ^= obs_flip; + } + if (w2 == 0 && w1 > 0) { + *r2 = *r1; + assert(r1->color_node(c2) == e.dets[0]); + assert(r2->color_node(c2) == e.dets[0]); + r2->color_node(c2) = e.dets[1]; + r2->obs_flip ^= obs_flip; + } + } + } + + return result; +} diff --git a/src/chromobius/graph/choose_rgb_reps.h b/src/chromobius/graph/choose_rgb_reps.h new file mode 100644 index 0000000..d7e3fe7 --- /dev/null +++ b/src/chromobius/graph/choose_rgb_reps.h @@ -0,0 +1,30 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_CHOOSE_RGB_REPS_H +#define _CHROMOBIUS_CHOOSE_RGB_REPS_H + +#include "chromobius/datatypes/atomic_error.h" +#include "chromobius/datatypes/rgb_edge.h" + +namespace chromobius { + +std::vector choose_rgb_reps_from_atomic_errors( + const std::map &atomic_errors, std::span node_colors); + +} // namespace chromobius + +#endif diff --git a/src/chromobius/graph/choose_rgb_reps.test.cc b/src/chromobius/graph/choose_rgb_reps.test.cc new file mode 100644 index 0000000..5249b16 --- /dev/null +++ b/src/chromobius/graph/choose_rgb_reps.test.cc @@ -0,0 +1,43 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/choose_rgb_reps.h" + +#include "gtest/gtest.h" + +using namespace chromobius; + +TEST(choose_rgb_reps, choose_rgb_reps_from_atomic_errors) { + std::vector node_colors{ + ColorBasis{.color = R, .basis = X}, + ColorBasis{.color = G, .basis = X}, + ColorBasis{.color = B, .basis = X}, + ColorBasis{.color = R, .basis = X}, + }; + std::map atomic_errors{ + {AtomicErrorKey{0, 1, 2}, 1}, + {AtomicErrorKey{2, 3, BOUNDARY_NODE}, 02}, + }; + + auto reps = choose_rgb_reps_from_atomic_errors(atomic_errors, node_colors); + ASSERT_EQ( + reps, + (std::vector{ + RgbEdge{.red_node = 0, .green_node = 1, .blue_node = 2, .obs_flip = 1, .charge_flip = Charge::NEUTRAL}, + RgbEdge{.red_node = 0, .green_node = 1, .blue_node = 2, .obs_flip = 1, .charge_flip = Charge::NEUTRAL}, + RgbEdge{.red_node = 0, .green_node = 1, .blue_node = 2, .obs_flip = 1, .charge_flip = Charge::NEUTRAL}, + RgbEdge{ + .red_node = 3, .green_node = BOUNDARY_NODE, .blue_node = 2, .obs_flip = 2, .charge_flip = Charge::G}, + })); +} diff --git a/src/chromobius/graph/collect_atomic_errors.cc b/src/chromobius/graph/collect_atomic_errors.cc new file mode 100644 index 0000000..fc917b7 --- /dev/null +++ b/src/chromobius/graph/collect_atomic_errors.cc @@ -0,0 +1,98 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/collect_atomic_errors.h" + +using namespace chromobius; + +static void extract_atomic_errors_from_dem_error_instruction_dets( + std::span dets, + obsmask_int obs_flip, + std::span node_colors, + std::map *out_atomic_errors) { + switch (dets.size()) { + case 1: { + (*out_atomic_errors)[AtomicErrorKey{dets[0], BOUNDARY_NODE, BOUNDARY_NODE}] = obs_flip; + return; + } + case 2: { + ColorBasis c0 = node_colors[dets[0]]; + ColorBasis c1 = node_colors[dets[1]]; + if (c0.basis == c1.basis) { + (*out_atomic_errors)[AtomicErrorKey{dets[0], dets[1], BOUNDARY_NODE}] = obs_flip; + } + return; + } + case 3: { + ColorBasis c0 = node_colors[dets[0]]; + ColorBasis c1 = node_colors[dets[1]]; + ColorBasis c2 = node_colors[dets[2]]; + Charge net_charge = c0.color ^ c1.color ^ c2.color; + if (net_charge == Charge::NEUTRAL && c0.basis == c1.basis && c1.basis == c2.basis) { + (*out_atomic_errors)[AtomicErrorKey{dets[0], dets[1], dets[2]}] = obs_flip; + } + return; + } + } +} + +void chromobius::extract_obs_and_dets_from_error_instruction( + stim::DemInstruction instruction, + stim::SparseXorVec *out_xor_detectors_buffer, + obsmask_int *out_obs_flip) { + out_xor_detectors_buffer->clear(); + *out_obs_flip = 0; + for (const auto &t : instruction.target_data) { + if (t.is_relative_detector_id()) { + uint64_t u = t.raw_id(); + if (u > std::numeric_limits::max()) { + std::stringstream ss; + ss << "The detector error model is too large. It has a detector with " + "index "; + ss << u; + ss << " but the max supported by chromobius is "; + ss << std::numeric_limits::max(); + throw std::invalid_argument(ss.str()); + } + out_xor_detectors_buffer->xor_item((node_offset_int)u); + } else if (t.is_observable_id()) { + if (t.raw_id() >= sizeof(obsmask_int) * 8) { + std::stringstream ss; + ss << "Max logical observable is L" << (sizeof(obsmask_int) * 8 - 1); + ss << " but a larger one appeared in '" << instruction << "'"; + throw std::invalid_argument(ss.str()); + } + *out_obs_flip ^= obsmask_int{1} << t.raw_id(); + } else if (t.is_separator()) { + // Ignored. + } else { + throw std::invalid_argument("Unrecognized target type in " + instruction.str()); + } + } +} + +std::map chromobius::collect_atomic_errors( + const stim::DetectorErrorModel &dem, std::span node_colors) { + obsmask_int obs_flip; + stim::SparseXorVec dets; + std::map result; + + dem.iter_flatten_error_instructions([&](stim::DemInstruction instruction) { + extract_obs_and_dets_from_error_instruction(instruction, &dets, &obs_flip); + + extract_atomic_errors_from_dem_error_instruction_dets(dets.sorted_items, obs_flip, node_colors, &result); + }); + + return result; +} diff --git a/src/chromobius/graph/collect_atomic_errors.h b/src/chromobius/graph/collect_atomic_errors.h new file mode 100644 index 0000000..92f8803 --- /dev/null +++ b/src/chromobius/graph/collect_atomic_errors.h @@ -0,0 +1,51 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_COLLECT_ATOMIC_EDGES_H +#define _CHROMOBIUS_COLLECT_ATOMIC_EDGES_H + +#include + +#include "chromobius/datatypes/atomic_error.h" +#include "chromobius/datatypes/color_basis.h" +#include "stim.h" + +namespace chromobius { + +/// Finds errors of known a list of color/basis data for all detectors in the dem. +/// +/// The color/basis data is read from the 4th coordinate of each detector's +/// coordinate data using the convention 0=XR 1=XG 2=XB 3=ZR 4=ZG 5=ZB. +/// +/// Args: +/// dem: The detector error model to read detector data from. +/// out_mobius_dem: Optional. If not set to null, transformed coordinate +/// data for the mobius dem's detectors is appended to this dem. +/// +/// Returns: +/// A vector containing the color and basis data, indexed by detector id. +std::map collect_atomic_errors( + const stim::DetectorErrorModel &dem, std::span node_colors); + +/// Converts a stim::DemInstruction into a list of detection events and an obs mask. +void extract_obs_and_dets_from_error_instruction( + stim::DemInstruction instruction, + stim::SparseXorVec *out_xor_detectors_buffer, + obsmask_int *out_obs_flip); + +} // namespace chromobius + +#endif diff --git a/src/chromobius/graph/collect_composite_errors.cc b/src/chromobius/graph/collect_composite_errors.cc new file mode 100644 index 0000000..ecc2bae --- /dev/null +++ b/src/chromobius/graph/collect_composite_errors.cc @@ -0,0 +1,414 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/collect_composite_errors.h" + +#include "chromobius/graph/collect_atomic_errors.h" + +using namespace chromobius; + +static inline void try_grow_decomposition( + AtomicErrorKey e1, + AtomicErrorKey e2, + std::span node_colors, + const std::map &atomic_errors, + std::vector *out_atoms, + int &best_score) { + bool c1 = atomic_errors.contains(e1); + bool c2 = atomic_errors.contains(e2); + int score = c1 + 2 * c2; + if (score <= best_score) { + return; + } + if (score == 1 && e2.weight() == 3 && e2.net_charge(node_colors) != Charge::NEUTRAL) { + return; + } + if (score == 2 && e1.weight() == 3 && e1.net_charge(node_colors) != Charge::NEUTRAL) { + return; + } + + if (best_score > 0) { + out_atoms->pop_back(); + out_atoms->pop_back(); + } + out_atoms->push_back(e1); + out_atoms->push_back(e2); + best_score = score; +} + +static inline bool try_finish_decomposition( + int best_score, + obsmask_int obs_flip, + const std::map &atomic_errors, + std::vector *out_atoms, + std::map *out_remnants) { + assert(best_score == 0 || out_atoms->size() >= 2); + if (best_score == 1) { + AtomicErrorKey cur = (*out_atoms)[out_atoms->size() - 2]; + AtomicErrorKey rem = (*out_atoms)[out_atoms->size() - 1]; + (*out_remnants)[rem] = obs_flip ^ atomic_errors.at(cur); + } else if (best_score == 2) { + AtomicErrorKey cur = (*out_atoms)[out_atoms->size() - 1]; + AtomicErrorKey rem = (*out_atoms)[out_atoms->size() - 2]; + (*out_remnants)[rem] = obs_flip ^ atomic_errors.at(cur); + } + return best_score > 0; +} + +static bool decompose_single_basis_dets_into_atoms_helper_n2( + std::span dets, + obsmask_int obs_flip, + std::span node_colors, + const std::map &atomic_errors, + std::vector *out_atoms, + std::map *out_remnants) { + // Check if it's just directly included. + AtomicErrorKey e{dets[0], dets[1], BOUNDARY_NODE}; + if (atomic_errors.contains(e)) { + out_atoms->push_back(e); + return true; + } + + int best_score = 0; + + // 1:1 decomposition. + for (size_t k1 = 0; k1 < dets.size(); k1++) { + try_grow_decomposition( + AtomicErrorKey{dets[k1], BOUNDARY_NODE, BOUNDARY_NODE}, + AtomicErrorKey{ + dets[0 + (k1 <= 0)], + BOUNDARY_NODE, + BOUNDARY_NODE, + }, + node_colors, + atomic_errors, + out_atoms, + best_score); + } + + return try_finish_decomposition(best_score, obs_flip, atomic_errors, out_atoms, out_remnants); +} + +static bool decompose_single_basis_dets_into_atoms_helper_n3( + std::span dets, + obsmask_int obs_flip, + std::span node_colors, + const std::map &atomic_errors, + std::vector *out_atoms, + std::map *out_remnants) { + // Check if it's just directly included. + AtomicErrorKey e{dets[0], dets[1], dets[2]}; + if (atomic_errors.contains(e)) { + out_atoms->push_back(e); + return true; + } + + int best_score = 0; + + // 1:2 decomposition. + for (size_t k1 = 0; k1 < dets.size(); k1++) { + try_grow_decomposition( + AtomicErrorKey{dets[k1], BOUNDARY_NODE, BOUNDARY_NODE}, + AtomicErrorKey{ + dets[0 + (k1 <= 0)], + dets[1 + (k1 <= 1)], + BOUNDARY_NODE, + }, + node_colors, + atomic_errors, + out_atoms, + best_score); + } + + return try_finish_decomposition(best_score, obs_flip, atomic_errors, out_atoms, out_remnants); +} + +static bool decompose_single_basis_dets_into_atoms_helper_n4( + std::span dets, + obsmask_int obs_flip, + std::span node_colors, + const std::map &atomic_errors, + std::vector *out_atoms, + std::map *out_remnants) { + int best_score = 0; + + // 2:2 decomposition. + for (size_t k1 = 0; k1 < dets.size() && best_score < 2; k1++) { + for (size_t k2 = k1 + 1; k2 < dets.size(); k2++) { + try_grow_decomposition( + AtomicErrorKey{dets[k1], dets[k2], BOUNDARY_NODE}, + AtomicErrorKey{ + dets[0 + (k1 <= 0) + (k2 <= 0)], + dets[1 + (k1 <= 1) + (k2 <= 1)], + BOUNDARY_NODE, + }, + node_colors, + atomic_errors, + out_atoms, + best_score); + } + } + + // 1:3 decomposition. + for (size_t k1 = 0; k1 < dets.size(); k1++) { + try_grow_decomposition( + AtomicErrorKey{dets[k1], BOUNDARY_NODE, BOUNDARY_NODE}, + AtomicErrorKey{ + dets[0 + (k1 <= 0)], + dets[1 + (k1 <= 1)], + dets[2 + (k1 <= 2)], + }, + node_colors, + atomic_errors, + out_atoms, + best_score); + } + + return try_finish_decomposition(best_score, obs_flip, atomic_errors, out_atoms, out_remnants); +} + +static bool decompose_single_basis_dets_into_atoms_helper_n5( + std::span dets, + obsmask_int obs_flip, + std::span node_colors, + const std::map &atomic_errors, + std::vector *out_atoms, + std::map *out_remnants) { + int best_score = 0; + + // 2:3 decomposition. + for (size_t k1 = 0; k1 < dets.size() && best_score < 2; k1++) { + for (size_t k2 = k1 + 1; k2 < dets.size(); k2++) { + try_grow_decomposition( + AtomicErrorKey{dets[k1], dets[k2], BOUNDARY_NODE}, + AtomicErrorKey{ + dets[0 + (k1 <= 0) + (k2 <= 0)], + dets[1 + (k1 <= 1) + (k2 <= 1)], + dets[2 + (k1 <= 2) + (k2 <= 2)], + }, + node_colors, + atomic_errors, + out_atoms, + best_score); + } + } + + return try_finish_decomposition(best_score, obs_flip, atomic_errors, out_atoms, out_remnants); +} + +static bool decompose_single_basis_dets_into_atoms_helper_n6( + std::span dets, + obsmask_int obs_flip, + std::span node_colors, + const std::map &atomic_errors, + std::vector *out_atoms, + std::map *out_remnants) { + int best_score = 0; + + // 3:3 decomposition. + for (size_t k1 = 0; k1 < dets.size() && best_score < 2; k1++) { + for (size_t k2 = k1 + 1; k2 < dets.size(); k2++) { + for (size_t k3 = k2 + 1; k3 < dets.size(); k3++) { + try_grow_decomposition( + AtomicErrorKey{dets[k1], dets[k2], dets[k3]}, + AtomicErrorKey{ + dets[0 + (k1 <= 0) + (k2 <= 0) + (k3 <= 0)], + dets[1 + (k1 <= 1) + (k2 <= 1) + (k3 <= 1)], + dets[2 + (k1 <= 2) + (k2 <= 2) + (k3 <= 2)], + }, + node_colors, + atomic_errors, + out_atoms, + best_score); + } + } + } + + return try_finish_decomposition(best_score, obs_flip, atomic_errors, out_atoms, out_remnants); +} + +static bool decompose_single_basis_dets_into_atoms( + std::span dets, + obsmask_int obs_flip, + std::span node_colors, + const std::map &atomic_errors, + std::vector *out_atoms, + std::map *out_remnants) { + switch (dets.size()) { + case 0: + return true; + case 1: + out_atoms->push_back(AtomicErrorKey{dets[0], BOUNDARY_NODE, BOUNDARY_NODE}); + return atomic_errors.contains(out_atoms->back()); + case 2: + return decompose_single_basis_dets_into_atoms_helper_n2( + dets, obs_flip, node_colors, atomic_errors, out_atoms, out_remnants); + case 3: + return decompose_single_basis_dets_into_atoms_helper_n3( + dets, obs_flip, node_colors, atomic_errors, out_atoms, out_remnants); + case 4: + return decompose_single_basis_dets_into_atoms_helper_n4( + dets, obs_flip, node_colors, atomic_errors, out_atoms, out_remnants); + case 5: + return decompose_single_basis_dets_into_atoms_helper_n5( + dets, obs_flip, node_colors, atomic_errors, out_atoms, out_remnants); + case 6: + return decompose_single_basis_dets_into_atoms_helper_n6( + dets, obs_flip, node_colors, atomic_errors, out_atoms, out_remnants); + default: + return false; + } +} + +static void decompose_dets_into_atoms( + std::span dets, + obsmask_int obs_flip, + std::span node_colors, + const std::map &atomic_errors, + bool ignore_decomposition_failures, + std::vector *buf_x_detectors, + std::vector *buf_z_detectors, + const stim::DemInstruction &instruction_for_error_message, + const stim::DetectorErrorModel *dem_for_error_message, + std::vector *out_atoms, + std::map *out_remnants) { + // Split into X and Z parts. + buf_x_detectors->clear(); + buf_z_detectors->clear(); + for (const auto &t : dets) { + auto cb = node_colors[t]; + int c = (int)cb.color - 1; + int b = (int)cb.basis - 1; + if (c < 0 || c >= 3 || b < 0 || b >= 2) { + std::stringstream ss; + ss << "Detector D" << t << " originating from instruction (after shifting) '" + << instruction_for_error_message << "'"; + ss << " is missing coordinate data indicating its color and basis.\n"; + ss << "Every detector used in an error must have a 4th coordinate in " + "[0,6) where RedX=0, GreenX=1, BlueX=2, RedZ=3, GreenZ=4, BlueZ=5."; + throw std::invalid_argument(ss.str()); + } + if (b == 0) { + buf_x_detectors->push_back(t); + } else { + buf_z_detectors->push_back(t); + } + } + + // Split into atomic errors. + out_atoms->clear(); + bool x_worked = decompose_single_basis_dets_into_atoms( + *buf_x_detectors, obs_flip, node_colors, atomic_errors, out_atoms, out_remnants); + bool z_worked = decompose_single_basis_dets_into_atoms( + *buf_z_detectors, obs_flip, node_colors, atomic_errors, out_atoms, out_remnants); + if (!(x_worked && z_worked) && !ignore_decomposition_failures) { + std::stringstream ss; + ss << "Failed to decompose a complex error instruction into basic errors.\n"; + ss << " The instruction (after shifting): " + instruction_for_error_message.str() << "\n"; + if (!x_worked) { + ss << " The undecomposed X detectors: [" << stim::comma_sep(*buf_x_detectors) << "]\n"; + } + if (!z_worked) { + ss << " The undecomposed Z detectors: [" << stim::comma_sep(*buf_z_detectors) << "]\n"; + } + ss << " Detector data:\n"; + std::set ds; + for (const auto &t : instruction_for_error_message.target_data) { + if (t.is_relative_detector_id()) { + ds.insert(t.raw_id()); + } + } + std::map> coords; + if (dem_for_error_message != nullptr) { + coords = dem_for_error_message->get_detector_coordinates(ds); + } + for (const auto &t : instruction_for_error_message.target_data) { + if (t.is_relative_detector_id()) { + auto d = t.raw_id(); + ss << " " << t << ": coords=[" << stim::comma_sep(coords[d]) << "] " << node_colors[d] << "\n"; + } + } + ss << "This problem can unfortunately be quite difficult to debug. Likely causes are:\n"; + ss << " (1) The source circuit has detectors with invalid color/basis annotations.\n"; + ss << " (2) The source circuit is producing errors too complex to decompose (e.g. more than 6 symptoms in " + "one basis).\n"; + ss << " (3) chromobius is missing logic for a corner case present in the source circuit; a corner case that " + "didn't appear in the test circuits used during development.\n"; + throw std::invalid_argument(ss.str()); + } +} + +void chromobius::collect_composite_errors_and_remnants_into_mobius_dem( + const stim::DetectorErrorModel &dem, + std::span node_colors, + const std::map &atomic_errors, + bool drop_mobius_errors_involving_remnant_errors, + bool ignore_decomposition_failures, + stim::DetectorErrorModel *out_mobius_dem, + std::map *out_remnants) { + + stim::SparseXorVec dets; + std::vector x_buf; + std::vector z_buf; + std::vector atoms_buf; + std::vector composite_error_buffer; + + dem.iter_flatten_error_instructions([&](stim::DemInstruction instruction) { + obsmask_int obs_flip; + extract_obs_and_dets_from_error_instruction(instruction, &dets, &obs_flip); + + decompose_dets_into_atoms( + dets.sorted_items, + obs_flip, + node_colors, + atomic_errors, + ignore_decomposition_failures, + &x_buf, + &z_buf, + instruction, + &dem, + &atoms_buf, + out_remnants); + + if (drop_mobius_errors_involving_remnant_errors && !out_remnants->empty()) { + atoms_buf.clear(); + out_remnants->clear(); + } + + // Convert atomic errors into mobius detection events with decomposition suggestions. + composite_error_buffer.clear(); + bool has_corner_node = false; + for (const auto &atom : atoms_buf) { + has_corner_node |= atom.dets[1] == BOUNDARY_NODE; + atom.iter_mobius_edges(node_colors, [&](node_offset_int d1, node_offset_int d2) { + composite_error_buffer.push_back(stim::DemTarget::relative_detector_id(d1)); + composite_error_buffer.push_back(stim::DemTarget::relative_detector_id(d2)); + composite_error_buffer.push_back(stim::DemTarget::separator()); + }); + } + + // Put the composite error into the mobius dem as an error instruction. + if (!composite_error_buffer.empty()) { + composite_error_buffer.pop_back(); + double p = instruction.arg_data[0]; + if (has_corner_node) { + // Corner nodes have edges to themselves that correspond to reaching the boundary in one subgraph + // and then bouncing back in another subgraph. Accounting for this correctly requires doubling the + // weight of the edge, which corresponds to squaring the probability. + p *= p; + } + out_mobius_dem->append_error_instruction(p, composite_error_buffer); + } + }); +} diff --git a/src/chromobius/graph/collect_composite_errors.h b/src/chromobius/graph/collect_composite_errors.h new file mode 100644 index 0000000..1800dbf --- /dev/null +++ b/src/chromobius/graph/collect_composite_errors.h @@ -0,0 +1,54 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_COLLECT_COMPOSITE_ERRORS_H +#define _CHROMOBIUS_COLLECT_COMPOSITE_ERRORS_H + +#include + +#include "chromobius/datatypes/atomic_error.h" +#include "chromobius/datatypes/color_basis.h" +#include "chromobius/graph/collect_atomic_errors.h" +#include "stim.h" + +namespace chromobius { + +/// Builds the mobius dem by decomposing errors from a dem into known atomic errors. +/// +/// Args: +/// dem: The detector error model to read original error instructions from. +/// node_colors: Previously collected node color and basis data. +/// atomic_errors: Previously collected basic errors to decompose into. +/// ignore_decomposition_failures: If set to True, then failing to decompose +/// an error into atomic errors causes the error to be discarded instead of +/// throwing an exception. +/// out_mobius_dem: Where to write the decomposed mobius error mechanisms. +/// out_remnants: Some errors can't be perfectly decomposed into existing atomic +/// errors, but can be decomposed into an atomic error and a leftover part that +/// would be a valid atomic error. This is where the remnants that are used +/// get written. +void collect_composite_errors_and_remnants_into_mobius_dem( + const stim::DetectorErrorModel &dem, + std::span node_colors, + const std::map &atomic_errors, + bool drop_mobius_errors_involving_remnant_errors, + bool ignore_decomposition_failures, + stim::DetectorErrorModel *out_mobius_dem, + std::map *out_remnants); + +} // namespace chromobius + +#endif diff --git a/src/chromobius/graph/collect_nodes.cc b/src/chromobius/graph/collect_nodes.cc new file mode 100644 index 0000000..4c9ee57 --- /dev/null +++ b/src/chromobius/graph/collect_nodes.cc @@ -0,0 +1,152 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/collect_nodes.h" + +using namespace chromobius; + +static void collect_nodes_from_dem_helper_process_detector_instruction( + stim::DemInstruction instruction, + std::span coord_offsets, + uint64_t det_offset, + std::vector *coord_buffer, + std::span out_node_color, + stim::DetectorErrorModel *out_mobius_dem) { + double c = -1; + if (instruction.arg_data.size() > 3) { + c = instruction.arg_data[3]; + if (coord_offsets.size() > 3) { + c += coord_offsets[3]; + } + } + int r = (int)c; + if (r < 0 || r >= 6 || r != c) { + throw std::invalid_argument( + "Expected all detectors to have at least 4 coordinates, with the 4th " + "identifying the basis and color " + "(RedX=0, GreenX=1, BlueX=2, RedZ=3, GreenZ=4, BlueZ=5), but got " + + instruction.str()); + } + constexpr std::array mapping{ + ColorBasis{Charge::R, Basis::X}, + ColorBasis{Charge::G, Basis::X}, + ColorBasis{Charge::B, Basis::X}, + ColorBasis{Charge::R, Basis::Z}, + ColorBasis{Charge::G, Basis::Z}, + ColorBasis{Charge::B, Basis::Z}, + }; + ColorBasis cb = mapping[r]; + + for (const auto &t : instruction.target_data) { + auto n = t.raw_id() + det_offset; + out_node_color[n] = cb; + + if (out_mobius_dem != nullptr) { + SubGraphCoord g0; + SubGraphCoord g1; + switch (cb.color) { + case Charge::R: + g0 = SubGraphCoord::NotGreen; + g1 = SubGraphCoord::NotBlue; + break; + case Charge::G: + g0 = SubGraphCoord::NotRed; + g1 = SubGraphCoord::NotBlue; + break; + case Charge::B: + g0 = SubGraphCoord::NotRed; + g1 = SubGraphCoord::NotGreen; + break; + default: + throw std::invalid_argument("Uncolored detection event from " + instruction.str()); + } + assert(g1 > g0); + + coord_buffer->clear(); + coord_buffer->insert(coord_buffer->begin(), instruction.arg_data.begin(), instruction.arg_data.end()); + for (size_t k = 0; k < coord_offsets.size() && k < coord_buffer->size(); k++) { + (*coord_buffer)[k] += coord_offsets[k]; + } + coord_buffer->push_back(-1); + + stim::DemTarget d0 = stim::DemTarget::relative_detector_id(n * 2 + 0); + stim::DemTarget d1 = stim::DemTarget::relative_detector_id(n * 2 + 1); + + coord_buffer->back() = (double)g0; + out_mobius_dem->append_detector_instruction(*coord_buffer, d0); + coord_buffer->back() = (double)g1; + out_mobius_dem->append_detector_instruction(*coord_buffer, d1); + } + } +} + +static void collect_nodes_from_dem_helper( + const stim::DetectorErrorModel &dem, + uint64_t *det_offset, + std::vector *coord_offsets, + std::vector *coord_buffer, + std::span out_node_color, + stim::DetectorErrorModel *out_mobius_dem) { + for (const auto &instruction : dem.instructions) { + switch (instruction.type) { + case stim::DemInstructionType::DEM_DETECTOR: { + collect_nodes_from_dem_helper_process_detector_instruction( + instruction, *coord_offsets, *det_offset, coord_buffer, out_node_color, out_mobius_dem); + break; + } + case stim::DemInstructionType::DEM_SHIFT_DETECTORS: { + if (!instruction.target_data.empty()) { + *det_offset += instruction.target_data[0].raw_id(); + } + for (size_t k = 0; k < instruction.arg_data.size(); k++) { + if (coord_offsets->size() < instruction.arg_data.size()) { + coord_offsets->push_back(0); + } + (*coord_offsets)[k] += instruction.arg_data[k]; + } + break; + } + case stim::DemInstructionType::DEM_REPEAT_BLOCK: { + const auto &block = instruction.repeat_block_body(dem); + auto reps = instruction.repeat_block_rep_count(); + for (uint64_t k = 0; k < reps; k++) { + collect_nodes_from_dem_helper( + block, det_offset, coord_offsets, coord_buffer, out_node_color, out_mobius_dem); + } + break; + } + case stim::DemInstructionType::DEM_ERROR: + // Ignored. + break; + case stim::DemInstructionType::DEM_LOGICAL_OBSERVABLE: + // Ignored. + break; + default: + throw std::invalid_argument("Unrecognized instruction type: " + instruction.str()); + } + } +} + +std::vector chromobius::collect_nodes_from_dem( + const stim::DetectorErrorModel &dem, stim::DetectorErrorModel *out_mobius_dem) { + uint64_t det_offset = 0; + std::vector coord_offsets; + std::vector coord_buffer; + std::vector result; + + uint64_t num_detectors = dem.count_detectors(); + result.resize(num_detectors); + collect_nodes_from_dem_helper(dem, &det_offset, &coord_offsets, &coord_buffer, result, out_mobius_dem); + return result; +} diff --git a/src/chromobius/graph/collect_nodes.h b/src/chromobius/graph/collect_nodes.h new file mode 100644 index 0000000..f9bb17d --- /dev/null +++ b/src/chromobius/graph/collect_nodes.h @@ -0,0 +1,45 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_COLLECT_NODES_H +#define _CHROMOBIUS_COLLECT_NODES_H + +#include + +#include "chromobius/datatypes/atomic_error.h" +#include "chromobius/datatypes/color_basis.h" +#include "stim.h" + +namespace chromobius { + +/// Creates a list of color/basis data for all detectors in the dem. +/// +/// The color/basis data is read from the 4th coordinate of each detector's +/// coordinate data using the convention 0=XR 1=XG 2=XB 3=ZR 4=ZG 5=ZB. +/// +/// Args: +/// dem: The detector error model to read detector data from. +/// out_mobius_dem: Optional. If not set to null, transformed coordinate +/// data for the mobius dem's detectors is appended to this dem. +/// +/// Returns: +/// A vector containing the color and basis data, indexed by detector id. +std::vector collect_nodes_from_dem( + const stim::DetectorErrorModel &dem, stim::DetectorErrorModel *out_mobius_dem); + +} // namespace chromobius + +#endif diff --git a/src/chromobius/graph/drag_graph.cc b/src/chromobius/graph/drag_graph.cc new file mode 100644 index 0000000..77dd61b --- /dev/null +++ b/src/chromobius/graph/drag_graph.cc @@ -0,0 +1,221 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/drag_graph.h" + +#include + +using namespace chromobius; + +/// Per-node state during a breadth first search, +struct BfsSearcher { + uint64_t next_seen_tag; + std::vector node_seen_tags; + std::vector> cur_cost_stack; + std::vector> next_cost_stack; + + BfsSearcher() = delete; + BfsSearcher(size_t num_nodes) : next_seen_tag(1), node_seen_tags(num_nodes), cur_cost_stack(), next_cost_stack() { + } + + /// Searches for a short path between node1 and node2 within the charge graph. + /// + /// Args: + /// graph: The graph to do pathfinding inside. + /// node_colors: + /// node1: One endpoint of the path. + /// node2: Other endpoint of the path. + /// tag_counter: Used to avoid having to clear the tagged buffer between + /// searches. This value will be incremented to create unique values, + /// which can then be recognized when searching in order to notice when + /// the current search has a reached a node without getting confused by + /// junk left from previous searches. + /// tagged_buffer: Used to store intermediate search state. Before the very + /// first search this should be zero'd, but it doesn't need to be zero'd + /// from search to search as long the tag counter isn't reset. + /// + /// Returns: + /// The observable flip mask of the path. + std::optional find_shortest_path_obs_flip( + const ChargeGraph &graph, + node_offset_int src, + node_offset_int dst, + size_t max_cost) { + + // Trivial case: same node. + if (src == dst) { + return 0; + } + + // Trivial case: neighbor. + if (graph.nodes[src].neighbors.contains(dst)) { + return graph.nodes[src].neighbors.at(dst); + } + + // Note: assuming never wraps around. + uint64_t tag = next_seen_tag++; + + // Meet-in-the-middle breadth first search. + cur_cost_stack.clear(); + next_cost_stack.clear(); + cur_cost_stack.push_back({src, 0}); + size_t cur_cost = 0; + while (true) { + if (cur_cost_stack.empty()) { + std::swap(cur_cost_stack, next_cost_stack); + cur_cost++; + if (cur_cost_stack.empty() || cur_cost >= max_cost) { + return {}; + } + } + auto [n, path_obs_flip] = cur_cost_stack.back(); + cur_cost_stack.pop_back(); + + for (const auto [neighbor, edge_obs_flip] : graph.nodes[n].neighbors) { + obsmask_int new_path_flip = path_obs_flip ^ edge_obs_flip; + if (neighbor == dst) { + return new_path_flip; + } + if (neighbor == BOUNDARY_NODE) { + // We're only searching in the bulk. + continue; + } + if (node_seen_tags[neighbor] == tag) { + // Already been here. + continue; + } + node_seen_tags[neighbor] = tag; + next_cost_stack.push_back({neighbor, new_path_flip}); + } + } + } +}; + +DragGraph DragGraph::from_charge_graph_paths_for_sub_edges_of_atomic_errors( + const ChargeGraph &charge_graph, + const std::map &atomic_errors, + std::span rgb_reps, + std::span node_colors) { + + constexpr size_t max_cost = 2; + + std::set decomposed_edges; + BfsSearcher searcher(node_colors.size()); + DragGraph drag_graph; + + auto add_edge = [&](node_offset_int n1, node_offset_int n2, Charge c1, Charge c2, obsmask_int flip) { + drag_graph.mmm[ChargedEdge{.n1=n1, .n2=n2, .c1=c1, .c2=c2}] = flip; + drag_graph.mmm[ChargedEdge{.n1=n2, .n2=n1, .c1=c2, .c2=c1}] = flip; + }; + + auto add_boundary_dumping_edge = [&](node_offset_int a, node_offset_int b, obsmask_int ab_obs_flip) { + if (rgb_reps[a].weight() != 3) { + return; + } + Charge ca = node_colors[a].color; + Charge cb = node_colors[b].color; + Charge c = ca ^ cb; + if (c == Charge::NEUTRAL) { + return; + } + auto r1_flip = searcher.find_shortest_path_obs_flip(charge_graph, rgb_reps[a].color_node(ca), a, max_cost); + auto r2_flip = searcher.find_shortest_path_obs_flip(charge_graph, rgb_reps[a].color_node(cb), b, max_cost); + if (r1_flip.has_value() && r2_flip.has_value()) { + add_edge(a, b, c, Charge::NEUTRAL, *r1_flip ^ *r2_flip ^ rgb_reps[a].obs_flip ^ ab_obs_flip); + } + }; + + for (const auto &[err, err_obs_flip] : atomic_errors) { + auto w = err.weight(); + if (w == 3) { + assert(err.net_charge(node_colors) == Charge::NEUTRAL); + auto [a, b, c] = err.dets; + decomposed_edges.insert(SortedPair{a, b}); + decomposed_edges.insert(SortedPair{a, c}); + decomposed_edges.insert(SortedPair{b, c}); + } else if (w == 2) { + auto a = err.dets[0]; + auto b = err.dets[1]; + Charge ca = node_colors[a].color; + Charge cb = node_colors[b].color; + obsmask_int p = charge_graph.nodes[a].neighbors.at(b); + // The boundary error turns charge on one node into charge on the other node. + add_edge(a, b, ca, cb, p); + add_edge(a, b, Charge::NEUTRAL, Charge::NEUTRAL, 0); + // The boundary error can also be used to dump the other type of charge, if it's nearby. + add_boundary_dumping_edge(a, b, err_obs_flip); + add_boundary_dumping_edge(b, a, err_obs_flip); + decomposed_edges.insert(SortedPair{a, b}); + } else if (w == 1) { + auto n = err.dets[0]; + Charge c = node_colors[n].color; + + // Applying the corner error dumps (or restores) the node's charge. + add_edge(n, n, c, Charge::NEUTRAL, err_obs_flip); + add_edge(n, n, Charge::NEUTRAL, Charge::NEUTRAL, 0); + + // The corner error, plus the node's rep error, will flip between the other two nearby charges. + auto r = rgb_reps[n]; + if (r.weight() == 3) { + auto f = r.obs_flip ^ err_obs_flip; + Charge c1 = next_non_neutral_charge(c); + Charge c2 = next_non_neutral_charge(c1); + add_edge(n, n, c1, c2, f); + } + } + } + + for (const auto &[n1, n2] : decomposed_edges) { + assert(n1 != BOUNDARY_NODE); + assert(n2 != BOUNDARY_NODE); + auto reps1 = rgb_reps[n1]; + auto reps2 = rgb_reps[n2]; + for (size_t k = 1; k < 4; k++) { + Charge c = (Charge)k; + auto r1 = reps1.color_node(c); + auto r2 = reps2.color_node(c); + if (r1 != BOUNDARY_NODE && r2 != BOUNDARY_NODE) { + // Solve for how to drag charge type c from near n1 to near n2. + auto res = searcher.find_shortest_path_obs_flip(charge_graph, r1, r2, max_cost); + if (res.has_value()) { + add_edge(n1, n2, c, c, *res); + } + } + } + // Can drag neutral charge around by doing nothing. + add_edge(n1, n2, Charge::NEUTRAL, Charge::NEUTRAL, 0); + } + + return drag_graph; +} + +bool DragGraph::operator==(const DragGraph &other) const { + return mmm == other.mmm; +} +bool DragGraph::operator!=(const DragGraph &other) const { + return !(*this == other); +} +std::string DragGraph::str() const { + std::stringstream ss; + ss << *this; + return ss.str(); +} +std::ostream &chromobius::operator<<(std::ostream &out, const DragGraph &val) { + out << "DragGraph{.mmm={\n"; + for (const auto &[k, v] : val.mmm) { + out << " " << k.c1 << "@" << k.n1 << ":" << k.c2 << "@" << k.n2 << " = " << v << "\n"; + } + out << "}}"; + return out; +} diff --git a/src/chromobius/graph/drag_graph.h b/src/chromobius/graph/drag_graph.h new file mode 100644 index 0000000..f81dc31 --- /dev/null +++ b/src/chromobius/graph/drag_graph.h @@ -0,0 +1,94 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_DRAG_GRAPH_H +#define _CHROMOBIUS_DRAG_GRAPH_H + +#include "chromobius/datatypes/color_basis.h" +#include "chromobius/graph/charge_graph.h" + +namespace chromobius { + +struct DragNode; +struct DragChange; + +struct SortedPair { + node_offset_int a; + node_offset_int b; + inline SortedPair() : a(0), b(0) { + } + inline SortedPair(node_offset_int init_a, node_offset_int init_b) : a(init_a), b(init_b) { + inplace_sort2(a, b); + } + inline bool operator<(const SortedPair &other) const { + return a != other.a ? a < other.a : b < other.b; + } + inline bool operator==(const SortedPair &other) const { + return a == other.a && b == other.b; + } +}; + +struct ChargedEdge { + node_offset_int n1; + node_offset_int n2; + Charge c1; + Charge c2; + inline bool operator<(const ChargedEdge &other) const { + if (n1 != other.n1) { + return n1 < other.n1; + } + if (n2 != other.n2) { + return n2 < other.n2; + } + if (c1 != other.c1) { + return c1 < other.c1; + } + return c2 < other.c2; + } + inline bool operator==(const ChargedEdge &other) const { + return n1 == other.n1 && n2 == other.n2 && c1 == other.c1 && c2 == other.c2; + } +}; + +/// The drag graph stores information on how to drag charge from node to node. +/// +/// When dragging charge around, the charge is always kept near the current +/// target node T. For charge of the same color as T, the charge is exactly a +/// detection event at T. Charges for colors different from T, are kept on R +/// where R is a node near T that matches the charge's color (R is called +/// the `representative` of that charge color for T). In some cases, when there +/// is no node of a color near T, charge of that color must be split into the +/// two other color charges in order to be stored near T. In that case the +/// representative for T of that color is actually two nodes (with one of them +/// being T itself). +struct DragGraph { + std::map mmm; + + static DragGraph from_charge_graph_paths_for_sub_edges_of_atomic_errors( + const ChargeGraph &charge_graph, + const std::map &atomic_errors, + std::span rgb_reps, + std::span node_colors); + + bool operator==(const DragGraph &other) const; + bool operator!=(const DragGraph &other) const; + std::string str() const; +}; +std::ostream &operator<<(std::ostream &out, const DragGraph &val); + +} // namespace chromobius + +#endif diff --git a/src/chromobius/graph/drag_graph.test.cc b/src/chromobius/graph/drag_graph.test.cc new file mode 100644 index 0000000..473ae8f --- /dev/null +++ b/src/chromobius/graph/drag_graph.test.cc @@ -0,0 +1,19 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/drag_graph.h" + +#include "gtest/gtest.h" + +using namespace chromobius; diff --git a/src/chromobius/graph/euler_tours.cc b/src/chromobius/graph/euler_tours.cc new file mode 100644 index 0000000..b52a5c4 --- /dev/null +++ b/src/chromobius/graph/euler_tours.cc @@ -0,0 +1,110 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/euler_tours.h" + +#include + +using namespace chromobius; + +void EulerTourGraph::add_edge(node_offset_int a, node_offset_int b) { + uint16_t na = (uint16_t)nodes[a].neighbors.size(); + uint16_t nb = (uint16_t)nodes[b].neighbors.size(); + nodes[a].neighbors.push_back(EulerTourNeighbor{ + .node = b, + .back_index = nb, + }); + nodes[b].neighbors.push_back(EulerTourNeighbor{ + .node = a, + .back_index = na, + }); +} + +size_t EulerTourNode::look_next_neighbor() { + while (true) { + if (next_neighbor >= neighbors.size()) { + return SIZE_MAX; + } + if (neighbors[next_neighbor].node == BOUNDARY_NODE) { + next_neighbor++; + continue; + } + return next_neighbor; + } +} +std::ostream &chromobius::operator<<(std::ostream &out, const EulerTourNode &val) { + out << "EulerTourNode{.next_neighbor=" << val.next_neighbor << ", .neighbors={"; + for (auto &e : val.neighbors) { + out << e.node << ","; + } + out << "}}"; + return out; +} + +void EulerTourGraph::hard_reset() { + for (auto &n : nodes) { + n.neighbors.clear(); + n.next_neighbor = 0; + } + cycle_buf.clear(); + cycle_buf2.clear(); +} + +void EulerTourGraph::extend_cycle_depth_first() { + while (true) { + auto &n = nodes[cycle_buf.back()]; + size_t neighbor_k = n.look_next_neighbor(); + if (neighbor_k == SIZE_MAX) { + return; + } + n.next_neighbor++; + auto &neighbor = n.neighbors[neighbor_k]; + cycle_buf.push_back(neighbor.node); + nodes[neighbor.node].neighbors[neighbor.back_index].node = BOUNDARY_NODE; + } +} + +bool EulerTourGraph::rotate_cycle_to_end_with_unfinished_node() { + if (cycle_buf.back() != cycle_buf.front()) { + hard_reset(); + throw std::invalid_argument("Graph didn't decompose into Euler tours."); + } + cycle_buf.pop_back(); + + size_t cycle_k = 1; + for (; cycle_k < cycle_buf.size() && nodes[cycle_buf[cycle_k]].look_next_neighbor() == SIZE_MAX; cycle_k++) { + } + if (cycle_k < cycle_buf.size()) { + cycle_buf2.insert(cycle_buf2.end(), cycle_buf.begin() + cycle_k, cycle_buf.end()); + cycle_buf2.insert(cycle_buf2.end(), cycle_buf.begin(), cycle_buf.begin() + cycle_k + 1); + cycle_buf.swap(cycle_buf2); + cycle_buf2.clear(); + return true; + } else { + return false; + } +} + +std::ostream &chromobius::operator<<(std::ostream &out, const EulerTourGraph &val) { + out << "EulerTourGraph{\n"; + out << " .cycle_buf={" << stim::comma_sep(val.cycle_buf) << "}\n"; + out << " .nodes.size()=" << val.nodes.size() << "\n"; + for (size_t k = 0; k < val.nodes.size(); k++) { + if (!val.nodes[k].neighbors.empty()) { + out << " .nodes[" << k << "]=" << val.nodes[k] << "\n"; + } + } + out << "}"; + return out; +} diff --git a/src/chromobius/graph/euler_tours.h b/src/chromobius/graph/euler_tours.h new file mode 100644 index 0000000..cf6eae7 --- /dev/null +++ b/src/chromobius/graph/euler_tours.h @@ -0,0 +1,118 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_EULER_TOURS_H +#define _CHROMOBIUS_EULER_TOURS_H + +#include + +#include "chromobius/datatypes/atomic_error.h" +#include "chromobius/datatypes/color_basis.h" +#include "stim.h" + +namespace chromobius { + +/// This structure is used for decomposing a graph into a set of Euler tours. +/// +/// The graph must only have even degree nodes. +/// The graph is permitted to have multiple connected components. +/// There will be one Euler tour per connected component. +struct EulerTourGraph; + +struct EulerTourNeighbor { + node_offset_int node; + uint16_t back_index; +}; + +struct EulerTourNode { + /// The list of neighbors of this node. + /// Entries with .node set to BOUNDARY_NODE are voided and should be ignored. + std::vector neighbors; + /// Tracks the neighbors that have been looked at. + size_t next_neighbor; + + /// Advances `next_neighbor` to the next uncleared neighbor and returns it. + /// If `next_neighbor` is past the end of the list, returns SIZE_MAX. + size_t look_next_neighbor(); +}; +std::ostream &operator<<(std::ostream &out, const EulerTourNode &val); + +struct EulerTourGraph; +std::ostream &operator<<(std::ostream &out, const EulerTourGraph &val); +struct EulerTourGraph { + std::vector nodes; + std::vector cycle_buf; + std::vector cycle_buf2; + + inline EulerTourGraph(size_t num_nodes) : nodes(num_nodes, {.neighbors = {}, .next_neighbor = 0}) { + } + + void add_edge(node_offset_int a, node_offset_int b); + + // Deletes all edges and buffer contents. + // + // This method takes time proportional to the number of nodes, instead of + // proportional to the number of edges. + void hard_reset(); + + private: + void extend_cycle_depth_first(); + bool rotate_cycle_to_end_with_unfinished_node(); + + template + inline void burn_component_at(node_offset_int n, const CALLBACK &callback) { + if (nodes[n].look_next_neighbor() == SIZE_MAX) { + return; + } + cycle_buf.push_back(n); + do { + extend_cycle_depth_first(); + } while (rotate_cycle_to_end_with_unfinished_node()); + assert(cycle_buf.size() > 0); + callback(std::span(cycle_buf)); + cycle_buf.clear(); + } + + public: + template + inline void iter_euler_tours_of_interleaved_edge_list( + std::span interleaved_edge_list, + std::span mobius_dets, + const CALLBACK &callback) { + const auto &ee = interleaved_edge_list; + assert(ee.size() % 2 == 0); + for (size_t k = 0; k < ee.size(); k += 2) { + assert(ee[k] != -1); + assert(ee[k + 1] != -1); + add_edge(ee[k], ee[k + 1]); + } + for (size_t k = 0; k < mobius_dets.size(); k += 2) { + add_edge(mobius_dets[k], mobius_dets[k + 1]); + } + for (auto n : interleaved_edge_list) { + burn_component_at(n, callback); + } + for (auto n : interleaved_edge_list) { + assert(nodes[n].next_neighbor == nodes[n].neighbors.size()); + nodes[n].next_neighbor = 0; + nodes[n].neighbors.clear(); + } + } +}; + +} // namespace chromobius + +#endif diff --git a/src/chromobius/graph/euler_tours.perf.cc b/src/chromobius/graph/euler_tours.perf.cc new file mode 100644 index 0000000..a80311b --- /dev/null +++ b/src/chromobius/graph/euler_tours.perf.cc @@ -0,0 +1,55 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/euler_tours.h" + +#include "chromobius/util.perf.h" +#include "stim.h" + +using namespace chromobius; + +BENCHMARK(solve_euler_tours_n10000) { + std::mt19937_64 rng{0}; + std::vector edges; + for (size_t k = 0; k < 2000; k++) { + node_offset_int a; + node_offset_int b; + node_offset_int c; + do { + a = rng() % 9999 + 1; + b = rng() % 9999 + 1; + c = rng() % 9999 + 1; + } while (a == b || b == c || a == c); + edges.push_back(a); + edges.push_back(b); + edges.push_back(b); + edges.push_back(c); + edges.push_back(a); + edges.push_back(c); + } + std::shuffle(edges.begin(), edges.end(), rng); + EulerTourGraph g(10000); + + size_t n = 0; + benchmark_go([&]() { + g.iter_euler_tours_of_interleaved_edge_list(edges, {}, [&](std::span cycle) { + n += cycle.size(); + }); + }) + .goal_micros(230) + .show_rate("edges", edges.size()); + if (n == 1) { + std::cerr << "data dependence"; + } +} diff --git a/src/chromobius/graph/euler_tours.test.cc b/src/chromobius/graph/euler_tours.test.cc new file mode 100644 index 0000000..3387a43 --- /dev/null +++ b/src/chromobius/graph/euler_tours.test.cc @@ -0,0 +1,102 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/graph/euler_tours.h" + +#include "gtest/gtest.h" + +using namespace chromobius; + +TEST(euler_tours, euler_tours_of_edge_list) { + EulerTourGraph g(10); + + auto do_case = [&](std::vector> edge_list) { + std::vector> result; + std::vector node_colors; + node_colors.resize(g.nodes.size(), ColorBasis{Charge::R, Basis::X}); + + std::vector interleaved_edges; + for (auto [a, b] : edge_list) { + interleaved_edges.push_back(a); + interleaved_edges.push_back(b); + } + + g.iter_euler_tours_of_interleaved_edge_list( + interleaved_edges, {}, [&](std::span cycle) { + result.push_back({}); + for (size_t k = 0; k < cycle.size(); k++) { + result.back().push_back(cycle[k]); + } + }); + + return result; + }; + + ASSERT_EQ((do_case({})), (std::vector>{})); + + ASSERT_THROW( + { + do_case({ + {1, 2}, + }); + }, + std::invalid_argument); + + ASSERT_EQ( + (do_case({ + {1, 2}, + {2, 1}, + })), + (std::vector>{ + {1, 2}, + })); + + ASSERT_EQ( + (do_case({ + {1, 2}, + {3, 1}, + {2, 3}, + })), + (std::vector>{ + {1, 2, 3}, + })); + + ASSERT_EQ( + (do_case({ + {1, 2}, + {4, 5}, + {2, 1}, + {5, 6}, + {6, 4}, + })), + (std::vector>{ + {1, 2}, + {4, 5, 6}, + })); + + ASSERT_EQ( + (do_case({ + {1, 2}, + {2, 1}, + {2, 3}, + {3, 2}, + {3, 4}, + {4, 3}, + {2, 5}, + {5, 2}, + })), + (std::vector>{ + {3, 2, 5, 2, 1, 2, 3, 4}, + })); +} diff --git a/src/chromobius/pybind/chromobius.pybind.cc b/src/chromobius/pybind/chromobius.pybind.cc new file mode 100644 index 0000000..dfcf547 --- /dev/null +++ b/src/chromobius/pybind/chromobius.pybind.cc @@ -0,0 +1,350 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/decode/decoder.h" +#include "chromobius/pybind/sinter_compat.pybind.h" + +#include +#include +#include +#include + +#include "stim.h" + +struct CompiledDecoder { + chromobius::Decoder decoder; + uint64_t num_detectors; + uint64_t num_detector_bytes; + uint64_t num_observable_bytes; + std::vector result_buffer; + + static CompiledDecoder from_dem(const pybind11::object &dem) { + auto type_name = pybind11::str(dem.get_type()); + if (!type_name.contains("stim.") || !type_name.contains(".DetectorErrorModel")) { + throw std::invalid_argument("dem must be a stim.DetectorErrorModel."); + } + auto dem_str = pybind11::cast(pybind11::str(dem)); + stim::DetectorErrorModel converted_dem = stim::DetectorErrorModel(dem_str.c_str()); + auto decoder = chromobius::Decoder::from_dem(converted_dem, chromobius::DecoderConfigOptions{}); + auto num_dets = converted_dem.count_detectors(); + return CompiledDecoder{ + .decoder = std::move(decoder), + .num_detectors = num_dets, + .num_detector_bytes = (num_dets + 7) / 8, + .num_observable_bytes = (converted_dem.count_observables() + 7) / 8, + .result_buffer = {}, + }; + } + + pybind11::object predict_obs_flips_from_dets_bit_packed(const pybind11::object &dets_obj) { + if (!pybind11::isinstance>(dets_obj)) { + throw std::invalid_argument("Expected bit packed detection event data, but dets.dtype wasn't np.uint8."); + } + + const pybind11::array_t &dets = pybind11::cast>(dets_obj); + size_t num_shots; + size_t shot_stride; + size_t det_shape; + if (dets.ndim() == 2) { + num_shots = dets.shape(0); + shot_stride = dets.strides(0); + det_shape = dets.shape(1); + if (dets.strides(1) != 1) { + std::stringstream ss; + ss << "Bit packed shot data must be contiguous in memory, but dets.stride[1] wasn't equal to 1.\n"; + ss << "It was " << dets.strides(1) << "."; + throw std::invalid_argument(ss.str()); + } + } else if (dets.ndim() == 1) { + num_shots = 1; + shot_stride = 0; + det_shape = dets.shape(0); + } else { + throw std::invalid_argument("dets.shape not in [1, 2]"); + } + + if (det_shape != num_detector_bytes) { + std::stringstream ss; + ss << "Expected dets.shape[1]=" << dets.shape(1); + ss << " == num_detector_bytes=" << num_detector_bytes; + ss << " because dets.shape == 2 and dets.dtype==np.uint8 indicating bit packed shots."; + throw std::invalid_argument(ss.str()); + } + + result_buffer.clear(); + for (size_t shot = 0; shot < num_shots; shot++) { + const uint8_t *data = dets.data() + shot_stride * shot; + chromobius::obsmask_int prediction = + decoder.decode_detection_events({data, data + num_detector_bytes}); + result_buffer.push_back(prediction); + } + + // Write predictions into output numpy array. + uint8_t *buffer = new uint8_t[num_observable_bytes * num_shots]; + size_t offset = 0; + for (chromobius::obsmask_int obs : result_buffer) { + for (size_t k = 0; k < num_observable_bytes; k++) { + buffer[offset++] = obs & 255; + obs >>= 8; + } + } + pybind11::capsule free_when_done(buffer, [](void *f) { + delete[] reinterpret_cast(f); + }); + if (dets.ndim() == 2) { + return pybind11::array_t( + {(pybind11::ssize_t)num_shots, (pybind11::ssize_t)num_observable_bytes}, + {(pybind11::ssize_t)num_observable_bytes, (pybind11::ssize_t)1}, + buffer, + free_when_done); + } else { + return pybind11::array_t( + {(pybind11::ssize_t)num_observable_bytes}, + {(pybind11::ssize_t)1}, + buffer, + free_when_done); + } + } +}; + +PYBIND11_MODULE(chromobius, m) { + m.attr("__version__") = "0.0.dev0"; + m.doc() = R"pbdoc( + chromobius: A fast implementation of the mobius color code decoder. + )pbdoc"; + + chromobius::pybind_sinter_compat(m); + + auto compiled_decoder = pybind11::class_( + m, + "CompiledDecoder", + stim::clean_doc_string(R"DOC( + A chromobius decoder ready to predict observable flips from detection events. + + Example: + >>> import stim + >>> import chromobius + + >>> dem = stim.Circuit(''' + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 + ... DETECTOR(0, 0, 0, 1) rec[-4] + ... DETECTOR(1, 0, 0, 2) rec[-3] + ... DETECTOR(2, 0, 0, 0) rec[-2] + ... DETECTOR(3, 0, 0, 1) rec[-1] + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''').detector_error_model() + + >>> decoder = chromobius.CompiledDecoder.from_dem(dem) + )DOC") + .data()); + + compiled_decoder.def( + "predict_obs_flips_from_dets_bit_packed", + &CompiledDecoder::predict_obs_flips_from_dets_bit_packed, + pybind11::arg("dets"), + stim::clean_doc_string(R"DOC( + @signature def predict_obs_flips_from_dets_bit_packed(dets: np.ndarray) -> np.ndarray: + Predicts observable flips from detection events. + + Args: + dets: A bit packed numpy array of detection event data. The array can either + be 1-dimensional (a single shot to decode) or 2-dimensional (multiple + shots to decode, with the first axis being the shot axis and the second + axis being the detection event byte axis). + + The array's dtype must be np.uint8. If you have an array of dtype + np.bool_, you have data that's not bit packed. You can pack it by + using `np.packbits(array, bitorder='little')`. But ideally you + should attempt to never have unpacked data in the first place, + since it's 8x larger which can be a large performance loss. For + example, stim's sampler methods all have a `bit_packed=True` argument + that cause them to return bit packed data. + + Returns: + A bit packed numpy array of observable flip data. The array will have + the same number of dimensions as the dets argument. + + If dets is a 1D array, then the result has: + shape = (math.ceil(num_obs / 8),) + dtype = np.uint8 + If dets is a 2D array, then the result has: + shape = (dets.shape[0], math.ceil(num_obs / 8),) + dtype = np.uint8 + + To determine if the observable with index k was flipped in shot s, compute: + `bool((result[s, k // 8] >> (k % 8)) & 1)` + + Example: + >>> import stim + >>> import chromobius + >>> import numpy as np + + >>> repetition_color_code = stim.Circuit(''' + ... # Apply noise. + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... # Measure three-body stabilizers to catch errors. + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 Z4*Z5*Z6 Z5*Z6*Z7 + ... + ... # Annotate detectors, with a coloring in the 4th coordinate. + ... DETECTOR(0, 0, 0, 2) rec[-6] + ... DETECTOR(1, 0, 0, 0) rec[-5] + ... DETECTOR(2, 0, 0, 1) rec[-4] + ... DETECTOR(3, 0, 0, 2) rec[-3] + ... DETECTOR(4, 0, 0, 0) rec[-2] + ... DETECTOR(5, 0, 0, 1) rec[-1] + ... + ... # Check on the message. + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''') + + >>> # Sample the circuit. + >>> shots = 4096 + >>> sampler = repetition_color_code.compile_detector_sampler() + >>> dets, actual_obs_flips = sampler.sample( + ... shots=shots, + ... separate_observables=True, + ... bit_packed=True, + ... ) + + >>> # Decode with Chromobius. + >>> dem = repetition_color_code.detector_error_model() + >>> decoder = chromobius.compile_decoder_for_dem(dem) + >>> predicted_flips = decoder.predict_obs_flips_from_dets_bit_packed(dets) + + >>> # Count mistakes. + >>> differences = np.any(predicted_flips != actual_obs_flips, axis=1) + >>> mistakes = np.count_nonzero(differences) + >>> assert mistakes < shots / 5 + )DOC") + .data()); + + m.def( + "compile_decoder_for_dem", + &CompiledDecoder::from_dem, + pybind11::arg("dem"), + stim::clean_doc_string(R"DOC( + @signature def compile_decoder_for_dem(dem: stim.DetectorErrorModel) -> chromobius.CompiledDecoder: + Compiles a decoder for a stim detector error model. + + Args: + dem: A stim detector error model. The detector error model must satisfy: + 1. Basis+Color annotations. Every detector that appears in an error + must specify coordinate data including a fourth coordinate. The 4th + coordinate indicates the basis and color of the detector with the + convention: + 0 = Red X + 1 = Green X + 2 = Blue X + 3 = Red Z + 4 = Green Z + 5 = Blue Z + 2. Rainbow triplets. Bulk errors with three symptoms in one basis should + have one symptom of each color. Errors with three symptoms that + repeat a color will cause an exception unless they can be decomposed + into other basic errors. + 3. Movable excitations. It needs to be possible to combine bulk errors + to form simpler errors with one or two symptoms that can be used to + move or destroy excitations. If bulk errors don't have this + property, decoding will fail when attempting to lift a solution + from the matcher requires dragging an excitation along a path but + there's no way to move the excitation along that path. + 4. Matchable-avoids-color. In parts of the dem that correspond to a + matchable code, at least one of the colors must be avoided. + Otherwise the matcher may be given a problem that can be solved + locally, but when lifting it needs to be solved non-locally. + + Returns: + A decoder object that can be used to predict observable flips from + detection event samples. + + Example: + >>> import stim + >>> import chromobius + + >>> dem = stim.Circuit(''' + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 + ... DETECTOR(0, 0, 0, 1) rec[-4] + ... DETECTOR(1, 0, 0, 2) rec[-3] + ... DETECTOR(2, 0, 0, 0) rec[-2] + ... DETECTOR(3, 0, 0, 1) rec[-1] + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''').detector_error_model() + + >>> decoder = chromobius.compile_decoder_for_dem(dem) + )DOC") + .data()); + + compiled_decoder.def_static( + "from_dem", + &CompiledDecoder::from_dem, + pybind11::arg("dem"), + stim::clean_doc_string(R"DOC( + @signature def from_dem(dem: stim.DetectorErrorModel) -> chromobius.CompiledDecoder: + Compiles a decoder for a stim detector error model. + + Args: + dem: A stim detector error model. The detector error model must satisfy: + 1. Basis+Color annotations. Every detector that appears in an error + must specify coordinate data including a fourth coordinate. The 4th + coordinate indicates the basis and color of the detector with the + convention: + 0 = Red X + 1 = Green X + 2 = Blue X + 3 = Red Z + 4 = Green Z + 5 = Blue Z + 2. Rainbow triplets. Bulk errors with three symptoms in one basis should + have one symptom of each color. Errors with three symptoms that + repeat a color will cause an exception unless they can be decomposed + into other basic errors. + 3. Movable excitations. It needs to be possible to combine bulk errors + to form simpler errors with one or two symptoms that can be used to + move or destroy excitations. If bulk errors don't have this + property, decoding will fail when attempting to lift a solution + from the matcher requires dragging an excitation along a path but + there's no way to move the excitation along that path. + 4. Matchable-avoids-color. In parts of the dem that correspond to a + matchable code, at least one of the colors must be avoided. + Otherwise the matcher may be given a problem that can be solved + locally, but when lifting it needs to be solved non-locally. + + Returns: + A decoder object that can be used to predict observable flips from + detection event samples. + + Example: + >>> import stim + >>> import chromobius + + >>> dem = stim.Circuit(''' + ... X_ERROR(0.1) 0 1 2 3 4 5 6 7 + ... MPP Z0*Z1*Z2 Z1*Z2*Z3 Z2*Z3*Z4 Z3*Z4*Z5 + ... DETECTOR(0, 0, 0, 1) rec[-4] + ... DETECTOR(1, 0, 0, 2) rec[-3] + ... DETECTOR(2, 0, 0, 0) rec[-2] + ... DETECTOR(3, 0, 0, 1) rec[-1] + ... M 0 + ... OBSERVABLE_INCLUDE(0) rec[-1] + ... ''').detector_error_model() + + >>> decoder = chromobius.CompiledDecoder.from_dem(dem) + )DOC") + .data()); +} diff --git a/src/chromobius/pybind/chromobius_pybind_test.py b/src/chromobius/pybind/chromobius_pybind_test.py new file mode 100644 index 0000000..7615bcc --- /dev/null +++ b/src/chromobius/pybind/chromobius_pybind_test.py @@ -0,0 +1,72 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import pytest +import stim + +import chromobius + + +def test_errors(): + with pytest.raises(ValueError, match='must be a stim.DetectorErrorModel'): + chromobius.compile_decoder_for_dem(object()) + with pytest.raises(ValueError, match='4th coordinate'): + chromobius.compile_decoder_for_dem(stim.DetectorErrorModel(""" + error(0.1) D0 + """)) + + +def test_decoding(): + color_rep_code = stim.Circuit(""" + X_ERROR(0.1) 0 1 2 3 4 5 6 7 8 + M 0 1 2 3 4 5 6 7 8 + DETECTOR(0, 0, 0, 0) rec[-9] rec[-8] rec[-7] + DETECTOR(1, 0, 0, 1) rec[-8] rec[-7] rec[-6] + DETECTOR(2, 0, 0, 2) rec[-7] rec[-6] rec[-5] + DETECTOR(3, 0, 0, 0) rec[-6] rec[-5] rec[-4] + DETECTOR(4, 0, 0, 1) rec[-5] rec[-4] rec[-3] + DETECTOR(5, 0, 0, 2) rec[-4] rec[-3] rec[-2] + DETECTOR(6, 0, 0, 0) rec[-3] rec[-2] rec[-1] + DETECTOR(7, 0, 0, 1) rec[-2] rec[-1] + OBSERVABLE_INCLUDE(0) rec[-1] + OBSERVABLE_INCLUDE(1) rec[-2] + OBSERVABLE_INCLUDE(2) rec[-3] + OBSERVABLE_INCLUDE(3) rec[-4] + OBSERVABLE_INCLUDE(4) rec[-5] + OBSERVABLE_INCLUDE(5) rec[-6] + OBSERVABLE_INCLUDE(6) rec[-7] + OBSERVABLE_INCLUDE(7) rec[-8] + OBSERVABLE_INCLUDE(8) rec[-9] + """) + + err = color_rep_code.search_for_undetectable_logical_errors( + dont_explore_detection_event_sets_with_size_above=7, + dont_explore_edges_increasing_symptom_degree=False, + dont_explore_edges_with_degree_above=10, + canonicalize_circuit_errors=True, + ) + assert len(err) == 6 + + decoder = chromobius.compile_decoder_for_dem(color_rep_code.detector_error_model()) + decoder2 = chromobius.CompiledDecoder.from_dem(color_rep_code.detector_error_model()) + shots = 1024 + dets, obs = color_rep_code.compile_detector_sampler().sample( + shots=shots, separate_observables=True, bit_packed=True + ) + predictions = decoder.predict_obs_flips_from_dets_bit_packed(dets) + predictions2 = decoder2.predict_obs_flips_from_dets_bit_packed(dets) + assert np.array_equal(predictions, predictions2) + mistakes = np.count_nonzero(np.any(predictions != obs, axis=1)) + assert mistakes < 100 diff --git a/src/chromobius/pybind/sinter_compat.pybind.cc b/src/chromobius/pybind/sinter_compat.pybind.cc new file mode 100644 index 0000000..6d17137 --- /dev/null +++ b/src/chromobius/pybind/sinter_compat.pybind.cc @@ -0,0 +1,237 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius.h" +#include "chromobius/pybind/sinter_compat.pybind.h" + +#include +#include +#include +#include + +#include "stim.h" + +struct ChromobiusSinterCompiledDecoder { + chromobius::Decoder decoder; + uint64_t num_detectors; + uint64_t num_detector_bytes; + uint64_t num_observable_bytes; + std::vector result_buffer; + + pybind11::array_t decode_shots_bit_packed( + const pybind11::array_t &bit_packed_detection_event_data) { + assert(bit_packed_detection_event_data.ndim() == 2); + assert(bit_packed_detection_event_data.strides(1) == 1); + assert(bit_packed_detection_event_data.shape(1) == num_detector_bytes); + size_t stride = bit_packed_detection_event_data.strides(0); + size_t num_shots = bit_packed_detection_event_data.shape(0); + + // Predict each shot. + result_buffer.clear(); + for (size_t shot = 0; shot < num_shots; shot++) { + const uint8_t *data = bit_packed_detection_event_data.data() + stride * shot; + + // Predict. + chromobius::obsmask_int prediction = + decoder.decode_detection_events({data, data + num_detector_bytes}); + result_buffer.push_back(prediction); + } + + // Write predictions into output numpy array. + uint8_t *buffer = new uint8_t[num_observable_bytes * num_shots]; + size_t offset = 0; + for (chromobius::obsmask_int obs : result_buffer) { + for (size_t k = 0; k < num_observable_bytes; k++) { + buffer[offset++] = obs & 255; + obs >>= 8; + } + } + pybind11::capsule free_when_done(buffer, [](void *f) { + delete[] reinterpret_cast(f); + }); + return pybind11::array_t( + {(pybind11::ssize_t)num_shots, (pybind11::ssize_t)num_observable_bytes}, + {(pybind11::ssize_t)num_observable_bytes, (pybind11::ssize_t)1}, + buffer, + free_when_done); + } +}; + +enum SubDecoder : uint8_t { + SUB_DECODER_PYMATCHING = 0, +}; + +struct ChromobiusSinterDecoder { + SubDecoder sub_decoder; + ChromobiusSinterDecoder(SubDecoder sub_decoder) : sub_decoder(sub_decoder) { + } + + bool operator==(const ChromobiusSinterDecoder &other) const { + return true; + } + bool operator!=(const ChromobiusSinterDecoder &other) const { + return !(*this == other); + } + + chromobius::DecoderConfigOptions get_options() const { + chromobius::DecoderConfigOptions options; + return options; + } + + void decode_via_files( + uint64_t num_shots, + uint64_t num_dets, + uint64_t num_obs, + const pybind11::object &dem_path, + const pybind11::object &dets_b8_in_path, + const pybind11::object &obs_predictions_b8_out_path, + const pybind11::object &tmp_dir) { + auto dem_path_str = pybind11::cast(pybind11::str(dem_path)); + auto dets_b8_in_path_str = pybind11::cast(pybind11::str(dets_b8_in_path)); + auto obs_predictions_b8_out_path_str = pybind11::cast(pybind11::str(obs_predictions_b8_out_path)); + + FILE *f_dem = fopen(dem_path_str.c_str(), "r"); + stim::DetectorErrorModel dem = stim::DetectorErrorModel::from_file(f_dem); + fclose(f_dem); + + stim::RaiiFile dets_in(dets_b8_in_path_str.c_str(), "rb"); + stim::RaiiFile obs_out(obs_predictions_b8_out_path_str.c_str(), "wb"); + + auto reader = + stim::MeasureRecordReader::make(dets_in.f, stim::SampleFormat::SAMPLE_FORMAT_B8, 0, num_dets, 0); + auto writer = stim::MeasureRecordWriter::make(obs_out.f, stim::SampleFormat::SAMPLE_FORMAT_B8); + + auto decoder = chromobius::Decoder::from_dem(dem, get_options()); + + stim::SparseShot sparse_shot; + stim::simd_bits dets(num_dets); + for (size_t shot = 0; shot < num_shots; shot++) { + reader->start_and_read_entire_record(dets); + auto result = decoder.decode_detection_events({dets.u8, dets.u8 + dets.num_u8_padded()}); + writer->begin_result_type('L'); + for (size_t k = 0; k < num_obs; k++) { + writer->write_bit((result >> k) & 1); + } + writer->write_end(); + } + } + + ChromobiusSinterCompiledDecoder compile_decoder_for_dem(const pybind11::object &dem) { + auto dem_str = pybind11::cast(pybind11::str(dem)); + stim::DetectorErrorModel converted_dem = stim::DetectorErrorModel(dem_str.c_str()); + auto decoder = chromobius::Decoder::from_dem(converted_dem, get_options()); + auto num_dets = converted_dem.count_detectors(); + return ChromobiusSinterCompiledDecoder{ + .decoder = std::move(decoder), + .num_detectors = num_dets, + .num_detector_bytes = (num_dets + 7) / 8, + .num_observable_bytes = (converted_dem.count_observables() + 7) / 8, + .result_buffer = {}, + }; + } +}; + +void chromobius::pybind_sinter_compat(pybind11::module &m) { + auto sinter_decoder = pybind11::class_( + m, + "_ChromobiusSinterDecoder", + stim::clean_doc_string(R"DOC( + An object that implements the sinter.Decoder API. + )DOC") + .data()); + + auto sinter_compiled_decoder = pybind11::class_( + m, + "_ChromobiusSinterCompiledDecoder", + stim::clean_doc_string(R"DOC( + An object that implements the sinter.CompiledDecoder API. + )DOC") + .data()); + + sinter_decoder.def(pybind11::pickle( + [](const ChromobiusSinterDecoder &self) -> pybind11::object { + return pybind11::cast((uint8_t)self.sub_decoder); + }, + [](const pybind11::object &obj) -> ChromobiusSinterDecoder { + return ChromobiusSinterDecoder((SubDecoder)pybind11::cast(obj)); + })); + sinter_decoder.def(pybind11::self == pybind11::self); + sinter_decoder.def(pybind11::self != pybind11::self); + + sinter_decoder.def( + pybind11::init([](uint8_t sub_decoder) -> ChromobiusSinterDecoder { + return ChromobiusSinterDecoder((SubDecoder)sub_decoder); + }), + stim::clean_doc_string(R"DOC( + Creates a chromobius.ChromobiusSinterDecoder. + )DOC") + .data()); + + sinter_decoder.def( + "decode_via_files", + &ChromobiusSinterDecoder::decode_via_files, + pybind11::kw_only(), + pybind11::arg("num_shots"), + pybind11::arg("num_dets"), + pybind11::arg("num_obs"), + pybind11::arg("dem_path"), + pybind11::arg("dets_b8_in_path"), + pybind11::arg("obs_predictions_b8_out_path"), + pybind11::arg("tmp_dir"), + stim::clean_doc_string(R"DOC( + Decodes data on disk, to disk. + )DOC") + .data()); + + sinter_decoder.def( + "compile_decoder_for_dem", + &ChromobiusSinterDecoder::compile_decoder_for_dem, + pybind11::kw_only(), + pybind11::arg("dem"), + stim::clean_doc_string(R"DOC( + Creates a chromobius decoder preconfigured for the given detector error model. + )DOC") + .data()); + + sinter_compiled_decoder.def( + "decode_shots_bit_packed", + &ChromobiusSinterCompiledDecoder::decode_shots_bit_packed, + pybind11::kw_only(), + pybind11::arg("bit_packed_detection_event_data"), + stim::clean_doc_string(R"DOC( + Predicts observable flips from the given detection events. + )DOC") + .data()); + + m.def( + "sinter_decoders", + []() -> pybind11::object { + auto result = pybind11::dict(); + result["chromobius"] = ChromobiusSinterDecoder(SubDecoder::SUB_DECODER_PYMATCHING); + return result; + }, + stim::clean_doc_string(R"DOC( + @signature def sinter_decoders() -> dict[str, sinter.Decoder]: + A dictionary describing chromobius to sinter. + + Giving the result of this function to the `custom_decoders` argument of + `sinter.collect` will tell sinter about the decoder 'chromobius'. On the + command line, the equivalent argument is + `--custom_decoders 'chromobius:sinter_decoders'`. + + Returns: + The dict `{'chromobius': }`. + )DOC") + .data()); +} diff --git a/src/chromobius/pybind/sinter_compat.pybind.h b/src/chromobius/pybind/sinter_compat.pybind.h new file mode 100644 index 0000000..2b2a9d8 --- /dev/null +++ b/src/chromobius/pybind/sinter_compat.pybind.h @@ -0,0 +1,29 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_PYBIND_SINTER_COMPAT_H +#define _CHROMOBIUS_PYBIND_SINTER_COMPAT_H + +#include + +namespace chromobius { + +void pybind_sinter_compat(pybind11::module &m); + +} + +#endif + diff --git a/src/chromobius/pybind/sinter_compat_pybind_test.py b/src/chromobius/pybind/sinter_compat_pybind_test.py new file mode 100644 index 0000000..2091694 --- /dev/null +++ b/src/chromobius/pybind/sinter_compat_pybind_test.py @@ -0,0 +1,21 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import chromobius + + +def test_sinter_obj_exists(): + decoder = chromobius.sinter_decoders()['chromobius'] + assert hasattr(decoder, 'compile_decoder_for_dem') + assert hasattr(decoder, 'decode_via_files') diff --git a/src/chromobius/test_util.test.cc b/src/chromobius/test_util.test.cc new file mode 100644 index 0000000..dd43325 --- /dev/null +++ b/src/chromobius/test_util.test.cc @@ -0,0 +1,88 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/test_util.test.h" + +#include "gtest/gtest.h" + +using namespace chromobius; + +FILE *chromobius::open_test_data_file(const char *name) { + std::vector directories_to_check = { + "test_data/", + "../test_data/", + "../../test_data/", + }; + for (const auto &d : directories_to_check) { + std::string path = d + name; + FILE *f = fopen((d + name).c_str(), "r"); + if (f != nullptr) { + return f; + } + } + throw std::invalid_argument("Failed to find test data file " + std::string(name)); +} + +static void init_path(RaiiTempNamedFile &self) { + char tmp_stdin_filename[] = "/tmp/stim_test_named_file_XXXXXX"; + self.descriptor = mkstemp(tmp_stdin_filename); + if (self.descriptor == -1) { + throw std::runtime_error("Failed to create temporary file."); + } + self.path = std::string(tmp_stdin_filename); +} + +RaiiTempNamedFile::RaiiTempNamedFile() { + init_path(*this); +} + +RaiiTempNamedFile::RaiiTempNamedFile(const std::string &contents) { + init_path(*this); + write_contents(contents); +} + +RaiiTempNamedFile::~RaiiTempNamedFile() { + if (!path.empty()) { + remove(path.data()); + path = ""; + } +} + +std::string RaiiTempNamedFile::read_contents() { + FILE *f = fopen(path.c_str(), "rb"); + if (f == nullptr) { + throw std::runtime_error("Failed to open temp named file " + path); + } + std::string result; + while (true) { + int c = getc(f); + if (c == EOF) { + break; + } + result.push_back(c); + } + fclose(f); + return result; +} + +void RaiiTempNamedFile::write_contents(const std::string &contents) { + FILE *f = fopen(path.c_str(), "wb"); + if (f == nullptr) { + throw std::runtime_error("Failed to open temp named file " + path); + } + for (char c : contents) { + putc(c, f); + } + fclose(f); +} diff --git a/src/chromobius/test_util.test.h b/src/chromobius/test_util.test.h new file mode 100644 index 0000000..6b584f2 --- /dev/null +++ b/src/chromobius/test_util.test.h @@ -0,0 +1,39 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_TEST_UTIL_H +#define _CHROMOBIUS_TEST_UTIL_H + +#include +#include + +namespace chromobius { + +FILE *open_test_data_file(const char *name); + +struct RaiiTempNamedFile { + int descriptor; + std::string path; + RaiiTempNamedFile(); + ~RaiiTempNamedFile(); + RaiiTempNamedFile(const std::string &contents); + std::string read_contents(); + void write_contents(const std::string &contents); +}; + +} // namespace chromobius + +#endif diff --git a/src/chromobius/util.perf.h b/src/chromobius/util.perf.h new file mode 100644 index 0000000..af7bf3e --- /dev/null +++ b/src/chromobius/util.perf.h @@ -0,0 +1,121 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CHROMOBIUS_PERF_UTIL_PERF_H +#define _CHROMOBIUS_PERF_UTIL_PERF_H + +#include +#include +#include +#include + +extern double BENCHMARK_CONFIG_TARGET_SECONDS; + +struct BenchmarkResult { + double total_seconds; + size_t total_reps; + std::vector> marginal_rates; + double goal_seconds; + + BenchmarkResult(double total_seconds, size_t total_reps) + : total_seconds(total_seconds), total_reps(total_reps), marginal_rates(), goal_seconds(-1) { + } + + BenchmarkResult &show_rate(const std::string &new_unit_name, double new_multiplier) { + marginal_rates.emplace_back(new_unit_name, new_multiplier); + return *this; + } + + BenchmarkResult &goal_nanos(double nanos) { + goal_seconds = nanos / 1000 / 1000 / 1000; + return *this; + } + + BenchmarkResult &goal_micros(double micros) { + goal_seconds = micros / 1000 / 1000; + return *this; + } + + BenchmarkResult &goal_millis(double millis) { + goal_seconds = millis / 1000; + return *this; + } +}; + +struct RegisteredBenchmark { + std::string name; + std::function func; + std::vector results; +}; +extern RegisteredBenchmark *running_benchmark; +extern std::vector *all_registered_benchmarks_data; +extern uint64_t registry_initialized; +inline void add_benchmark(RegisteredBenchmark benchmark) { + if (all_registered_benchmarks_data == nullptr || registry_initialized != 4620243525989388168ULL) { + registry_initialized = 4620243525989388168ULL; + all_registered_benchmarks_data = new std::vector(); + } + all_registered_benchmarks_data->push_back(benchmark); +} + +#define BENCHMARK(name) \ + void BENCH_##name##_METHOD(); \ + struct BENCH_STARTUP_TYPE_##name { \ + BENCH_STARTUP_TYPE_##name() { \ + add_benchmark({#name, BENCH_##name##_METHOD}); \ + } \ + }; \ + static BENCH_STARTUP_TYPE_##name BENCH_STARTUP_INSTANCE_##name; \ + void BENCH_##name##_METHOD() + +// HACK: Templating the body function type makes inlining significantly more +// likely. +template +BenchmarkResult &benchmark_go(FUNC body) { + size_t total_reps = 0; + double total_seconds = 0.0; + double target_wait_time_seconds = BENCHMARK_CONFIG_TARGET_SECONDS; + + for (size_t rep_limit = 1; total_seconds < target_wait_time_seconds; rep_limit *= 100) { + double remaining_time = target_wait_time_seconds - total_seconds; + size_t reps = rep_limit; + if (total_seconds > 0) { + reps = (size_t)(remaining_time * total_reps / total_seconds); + if (reps < total_reps * 0.1) { + break; + } + if (reps > rep_limit) { + reps = rep_limit; + } + if (reps < 1) { + reps = 1; + } + } + auto start = std::chrono::steady_clock::now(); + for (size_t rep = 0; rep < reps; rep++) { + body(); + } + auto end = std::chrono::steady_clock::now(); + auto micros = std::chrono::duration_cast(end - start).count(); + total_reps += reps; + total_seconds += (double)micros / 1000.0 / 1000.0; + } + + running_benchmark->results.push_back({total_seconds, total_reps}); + return running_benchmark->results.back(); +} + +#endif diff --git a/src/clorco/__init__.py b/src/clorco/__init__.py new file mode 100644 index 0000000..aaa2d35 --- /dev/null +++ b/src/clorco/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/clorco/_circuits_vs_chromobius_test.py b/src/clorco/_circuits_vs_chromobius_test.py new file mode 100644 index 0000000..bb6c5b6 --- /dev/null +++ b/src/clorco/_circuits_vs_chromobius_test.py @@ -0,0 +1,51 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import pytest +import sinter + +import gen +from clorco._make_circuit import CONSTRUCTIONS +from clorco._make_circuit import make_circuit +import chromobius + + +@pytest.mark.parametrize( + "style", [style for style in CONSTRUCTIONS.keys() if "mxyz_" not in style] +) +def test_constructions_are_decoded(style: str): + r = 1 if style.startswith("transit") else 6 + d = 12 if "toric_" in style else 11 + circuit = make_circuit( + style=style, + noise_model=gen.NoiseModel.uniform_depolarizing(1e-3), + noise_strength=1e-3, + rounds=r, + diameter=d, + convert_to_cz=True, + editable_extras={}, + ) + decoder = chromobius.compile_decoder_for_dem( + circuit.detector_error_model() + ) + + shots = 2048 + assert 0 < circuit.num_observables <= 8 + dets, obs = circuit.compile_detector_sampler().sample( + shots=shots, separate_observables=True, bit_packed=True + ) + predictions = decoder.predict_obs_flips_from_dets_bit_packed(dets) + mistakes = np.count_nonzero(np.any(predictions != obs, axis=1)) + assert mistakes / shots < 0.42, (mistakes, shots) diff --git a/src/clorco/_make_circuit.py b/src/clorco/_make_circuit.py new file mode 100644 index 0000000..8165eab --- /dev/null +++ b/src/clorco/_make_circuit.py @@ -0,0 +1,95 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pathlib +from typing import Union, Callable, Any + +import stim + +import gen +from clorco._make_circuit_params import Params +from clorco.color2surface_code._keyed_constructions import ( + make_named_color2surface_code_constructions, +) +from clorco.color_code import make_named_color_code_constructions +from clorco.pyramid_code._keyed_constructions import ( + make_named_pyramid_code_constructions, +) +from clorco.surface_code import make_named_surface_code_constructions +from clorco.rep_code import make_named_rep_code_constructions + + +def _make_constructions() -> dict[str, Callable[[Params], stim.Circuit]]: + constructions: dict[str, Callable[[Params], stim.Circuit]] = { + **make_named_color_code_constructions(), + **make_named_surface_code_constructions(), + **make_named_rep_code_constructions(), + **make_named_color2surface_code_constructions(), + **make_named_pyramid_code_constructions(), + } + return constructions + + +CONSTRUCTIONS = _make_constructions() + + +def make_circuit( + *, + style: str, + noise_model: gen.NoiseModel | None, + noise_strength: float, + rounds: int, + diameter: int = 0, + debug_out_dir: Union[None, str, pathlib.Path] = None, + convert_to_cz: bool = True, + editable_extras: dict[str, Any], +) -> stim.Circuit: + if debug_out_dir is not None: + debug_out_dir = pathlib.Path(debug_out_dir) + debug_out_dir.mkdir(exist_ok=True, parents=True) + + params = Params( + style=style, + rounds=rounds, + diameter=diameter, + debug_out_dir=debug_out_dir, + convert_to_cz=convert_to_cz, + noise_model=noise_model, + noise_strength=noise_strength, + editable_extras=editable_extras, + ) + construction = CONSTRUCTIONS.get(style) + if construction is None: + msg = f"Unrecognized circuit style: {style!r}.\n\nRecognized styles are:" + for k in sorted(CONSTRUCTIONS.keys()): + msg += "\n " + k + raise NotImplementedError(msg) + noisy_circuit = construction(params) + + if params.debug_out_dir is not None: + gen.write_file(params.debug_out_dir / "noisy_circuit.stim", noisy_circuit) + gen.write_file( + params.debug_out_dir / "noisy_circuit_dets_ops.svg", + noisy_circuit.without_noise().diagram("detslice-with-ops-svg"), + ) + gen.write_file( + params.debug_out_dir / "noisy_circuit_dets.svg", + noisy_circuit.without_noise().diagram("detslice-svg"), + ) + gen.write_file( + params.debug_out_dir / "noisy_circuit_slice.svg", + noisy_circuit.diagram("timeslice-svg"), + ) + + return noisy_circuit diff --git a/src/clorco/_make_circuit_params.py b/src/clorco/_make_circuit_params.py new file mode 100644 index 0000000..74c1a30 --- /dev/null +++ b/src/clorco/_make_circuit_params.py @@ -0,0 +1,31 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses +import pathlib +from typing import Any + +import gen + + +@dataclasses.dataclass +class Params: + style: str + rounds: int + diameter: int + noise_strength: float + noise_model: gen.NoiseModel | None + debug_out_dir: pathlib.Path | None + convert_to_cz: bool + editable_extras: dict[str, Any] diff --git a/src/clorco/_make_circuit_test.py b/src/clorco/_make_circuit_test.py new file mode 100644 index 0000000..0ba4666 --- /dev/null +++ b/src/clorco/_make_circuit_test.py @@ -0,0 +1,33 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gen +from clorco._make_circuit import make_circuit + + +def test_make_circuit(): + c = make_circuit( + style="phenom_color_code", + noise_model=gen.NoiseModel.uniform_depolarizing(1e-3), + noise_strength=1e-3, + diameter=5, + editable_extras={}, + rounds=7, + ) + err = c.search_for_undetectable_logical_errors( + dont_explore_edges_increasing_symptom_degree=False, + dont_explore_edges_with_degree_above=3, + dont_explore_detection_event_sets_with_size_above=3, + ) + assert len(err) == 5 diff --git a/src/clorco/color2surface_code/__init__.py b/src/clorco/color2surface_code/__init__.py new file mode 100644 index 0000000..aaa2d35 --- /dev/null +++ b/src/clorco/color2surface_code/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/clorco/color2surface_code/_color2surface_layouts.py b/src/clorco/color2surface_code/_color2surface_layouts.py new file mode 100644 index 0000000..2cef3db --- /dev/null +++ b/src/clorco/color2surface_code/_color2surface_layouts.py @@ -0,0 +1,142 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gen +from clorco.color_code._superdense_planar_color_code_circuits import ( + make_color_code_layout_for_superdense, +) +from clorco.surface_code._surface_code_layouts import make_surface_code_layout + + +def rgb2xyz(patch: gen.Patch, basis: str) -> gen.Patch: + return gen.Patch( + [ + gen.Tile( + bases="XYZXYZ"[int(tile.extra_coords[0])], + ordered_data_qubits=tile.ordered_data_qubits, + measurement_qubit=tile.measurement_qubit, + extra_coords=tile.extra_coords, + ) + for tile in patch.tiles + if tile.basis == basis + ] + ) + + +def make_color2surface_layout( + *, + base_data_width: int, +) -> gen.StabilizerCode: + color_patch = make_color_code_layout_for_superdense( + base_data_width=base_data_width, + ).patch + surface_patch = make_surface_code_layout( + width=base_data_width, + height=base_data_width, + ).patch + surface_patch = gen.Patch( + tile for tile in surface_patch.tiles if tile.measurement_qubit.imag != 0.5 + ) + surface_patch = surface_patch.with_transformed_coords( + lambda e: (e - base_data_width * 1j) * 2 + (2j - 2 if e.imag <= 0 else 0) + ) + surface_patch = gen.Patch( + tile for tile in surface_patch.tiles if tile.measurement_qubit.imag < -2 + ) + surface_patch = surface_patch.with_transformed_coords( + lambda e: e + (e.real % 4 == 2 and e.imag == 0) + ) + + # Mix up the coloring a bit to keep things interesting for the decoder. + surface_patch = gen.Patch( + gen.Tile( + measurement_qubit=tile.measurement_qubit, + ordered_data_qubits=tile.ordered_data_qubits, + bases=tile.bases, + extra_coords=tile.extra_coords + if tile.measurement_qubit.real != 5 + else [2 + 3 * (tile.basis == "Z")], + ) + for tile in surface_patch.tiles + ) + + dropped_tiles = [ + tile + for tile in color_patch.tiles + if tile.measurement_qubit.imag == 0 + if tile.basis == "X" + ] + color_patch = gen.Patch(set(color_patch.tiles) - set(dropped_tiles)) + patch = gen.Patch( + [ + *color_patch.tiles, + *surface_patch.tiles, + *[ + gen.Tile( + measurement_qubit=(m := tile.measurement_qubit) - 0.5j, + ordered_data_qubits=[ + m - 1 - 2j, + m + 1 - 2j, + m - 1, + m + 2, + m + 1j, + m + 1j + 1, + ], + bases="X", + extra_coords=[0], + ) + for tile in dropped_tiles + ], + *[ + gen.Tile( + measurement_qubit=(m := tile.measurement_qubit) - 0.75j, + ordered_data_qubits=[ + m + 1 - 2j, + m + 3 - 2j, + m + 2, + m + 3, + ], + bases="Z", + extra_coords=[5], + ) + for tile in dropped_tiles + ], + gen.Tile( + measurement_qubit=-1 - 1j, + ordered_data_qubits=[0, -2j], + bases="Z", + extra_coords=[5], + ), + ] + ) + + min_y = min(q.imag for q in patch.data_set) + max_x_per_y = {} + for q in patch.data_set: + if q.imag > 0 and q.imag % 3 == 1: + continue + cur_max = max_x_per_y.setdefault(q.imag, q.real) + if q.real > cur_max: + max_x_per_y[q.imag] = q.real + code = gen.StabilizerCode( + patch=patch, + observables_x=[ + gen.PauliString({k * 1j + v: "X" for k, v in max_x_per_y.items()}) + ], + observables_z=[ + gen.PauliString({q: "Z" for q in patch.data_set if q.imag == min_y}) + ], + ) + code = code.with_transformed_coords(lambda e: e - min_y * 1j) + return code diff --git a/src/clorco/color2surface_code/_color2surface_layouts_test.py b/src/clorco/color2surface_code/_color2surface_layouts_test.py new file mode 100644 index 0000000..4c7130d --- /dev/null +++ b/src/clorco/color2surface_code/_color2surface_layouts_test.py @@ -0,0 +1,40 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +import gen +from clorco.color2surface_code._color2surface_layouts import make_color2surface_layout +from clorco.color2surface_code._draw_mobius_graph import code_capacity_mobius_graph_svg + + +@pytest.mark.parametrize("d", [3, 5, 7, 9]) +def test_make_color2surface_layout(d: int): + code = make_color2surface_layout(base_data_width=d) + code.check_commutation_relationships() + for tile in code.patch.tiles: + assert (tile.extra_coords[0] >= 3) == (tile.basis == "Z") + err = code.make_code_capacity_circuit( + noise=1e-3 + ).search_for_undetectable_logical_errors( + dont_explore_edges_increasing_symptom_degree=False, + dont_explore_edges_with_degree_above=3, + dont_explore_detection_event_sets_with_size_above=6, + ) + assert len(err) == d + + +def test_draw_mobius_graph(): + code = make_color2surface_layout(base_data_width=13) + assert code_capacity_mobius_graph_svg(code.patch) is not None diff --git a/src/clorco/color2surface_code/_draw_mobius_graph.py b/src/clorco/color2surface_code/_draw_mobius_graph.py new file mode 100644 index 0000000..8f5f117 --- /dev/null +++ b/src/clorco/color2surface_code/_draw_mobius_graph.py @@ -0,0 +1,214 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import collections +import itertools +from typing import Callable + +import gen + + +BASIS_COLORS = { + "X": "#FF8080", + "Z": "#8080FF", + "Y": "#80FF80", + "notX": "#00FFFF", + "notY": "#FF00FF", + "notZ": "#FFFF00", + None: "gray", +} +BASIS_COLORS_DARKER = { + "X": "#BB0000", + "Z": "#0000BB", + "Y": "#0BBF00", + "notX": "#00BBBB", + "notY": "#BB00BB", + "notZ": "#BBBB00", +} + + +def _draw_tile_polygon( + tile: gen.Tile, + draw_coord: Callable[[complex], complex], + out_svg: list[str], +): + stroke_width = abs(draw_coord(0.03) - draw_coord(0)) + common_basis = tile.basis + fill_color = BASIS_COLORS[common_basis] + path_dirs = gen.svg_path_directions_for_tile( + tile=tile, + draw_coord=draw_coord, + ) + if path_dirs is not None: + out_svg.append( + f''' """ + ) + + +def code_capacity_mobius_graph_svg(patch: gen.Patch) -> str: + min_c, max_c = gen.min_max_complex(patch.used_set) + min_c -= 1 + 1j + max_c += 1 + 1j + d_c = max_c - min_c + w = d_c.real + h = d_c.imag + w *= 2 + s = 1000 / max(w, h, 1) + w *= s + h *= s + + def draw_coord_x(c: complex) -> complex: + c -= min_c + c *= s + return c + + def draw_coord_z(c: complex) -> complex: + c -= min_c + c *= s + c += w / 2 + return c + + lines = [f""""""] + + rgb_patch_x = gen.Patch( + [ + gen.Tile( + bases="XYZ"[int(tile.extra_coords[0]) % 3], + measurement_qubit=tile.measurement_qubit, + ordered_data_qubits=tile.ordered_data_qubits, + ) + for tile in patch.tiles + if tile.extra_coords[0] // 3 == 0 + ] + ) + + rgb_patch_z = gen.Patch( + [ + gen.Tile( + bases="XYZ"[int(tile.extra_coords[0]) % 3], + measurement_qubit=tile.measurement_qubit, + ordered_data_qubits=tile.ordered_data_qubits, + ) + for tile in patch.tiles + if tile.extra_coords[0] // 3 == 1 + ] + ) + + code_capacity_mobius_graph_helper_piece( + rgb_patch=rgb_patch_x, + draw_coord=draw_coord_x, + lines=lines, + ) + code_capacity_mobius_graph_helper_piece( + rgb_patch=rgb_patch_z, + draw_coord=draw_coord_z, + lines=lines, + ) + + lines.append("") + return "\n".join(lines) + + +def code_capacity_mobius_graph_helper_piece( + *, rgb_patch: gen.Patch, draw_coord: Callable[[complex], complex], lines: list[str] +): + for tile in rgb_patch.tiles: + _draw_tile_polygon(tile=tile, draw_coord=draw_coord, out_svg=lines) + + # Map tile+subgraph to draw coordinates for the node. + t2d = {} + for tile in rgb_patch.tiles: + center = sum(tile.data_set) / len(tile.data_set) + if len(tile.data_set) == 2: + center = sum(tile.used_set) / len(tile.used_set) + na = draw_coord(center + 0.4 - 0.1j) + nb = draw_coord(center - 0.4 - 0.1j) + nc = draw_coord(center + 0.4j) + if tile.basis != "X": + t2d[(tile, "notX")] = na + if tile.basis != "Y": + t2d[(tile, "notY")] = nb + if tile.basis != "Z": + t2d[(tile, "notZ")] = nc + + stroke_width = abs(draw_coord(0.03) - draw_coord(0)) + + # Index tiles by their data qubits. + q2t = collections.defaultdict(list) + for tile in rgb_patch.tiles: + for q in tile.data_set: + q2t[q].append(tile) + + # Draw edges. + for q, tiles in q2t.items(): + if len(tiles) == 1: + # Draw boundary edge. + for c1 in ["notX", "notY", "notZ"]: + for c2 in ["notX", "notY", "notZ"]: + a = t2d.get((tiles[0], c1)) + b = t2d.get((tiles[0], c2)) + if a is not None and b is not None: + lines.append( + f"""""" + ) + + used = set() + + # Draw bulk edges. + for tile1, tile2 in itertools.combinations(tiles, 2): + for c in ["notX", "notY", "notZ"]: + a = t2d.get((tile1, c)) + b = t2d.get((tile2, c)) + if a is not None and b is not None: + lines.append( + f"""""" + ) + used.add(c) + + # Draw boundary edges. + if len(tiles) == 2: + tile1, tile2 = tiles + for c1 in ["notX", "notY", "notZ"]: + for c2 in ["notX", "notY", "notZ"]: + if c1 not in used and c2 not in used: + a = t2d.get((tile1, c1)) + b = t2d.get((tile2, c2)) + if a is not None and b is not None: + if c1 == c2: + rem = c1 + else: + (rem,) = {"notX", "notY", "notZ"} - {c1, c2} + rem = rem[3:] + center1 = sum(tile1.data_set) / len(tile1.data_set) + center2 = sum(tile2.data_set) / len(tile2.data_set) + p2 = draw_coord(q) + p2 = p2 + ((a - p2) + (b - p2)) * -0.4 + if gen.is_colinear(q, center1, center2): + lines.append( + f"""""" + ) + else: + lines.append( + f"""""" + ) + + # Draw nodes. + for (tile, color), pos in t2d.items(): + lines.append( + f"""""" + ) diff --git a/src/clorco/color2surface_code/_keyed_constructions.py b/src/clorco/color2surface_code/_keyed_constructions.py new file mode 100644 index 0000000..b52fb84 --- /dev/null +++ b/src/clorco/color2surface_code/_keyed_constructions.py @@ -0,0 +1,66 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Callable + +import stim + +import gen +from clorco._make_circuit_params import Params +from clorco.color2surface_code._color2surface_layouts import make_color2surface_layout +from clorco.color2surface_code._color2surface_layouts import rgb2xyz + + +def make_named_color2surface_code_constructions() -> ( + dict[str, Callable[[Params], stim.Circuit]] +): + constructions: dict[str, Callable[[Params], stim.Circuit]] = {} + + def _make_simple_circuit( + params: Params, *, code: gen.StabilizerCode, phenom: bool + ) -> stim.Circuit: + if params.debug_out_dir is not None: + code.patch.write_svg( + params.debug_out_dir / "rgb_patch.svg", + other=[rgb2xyz(code.patch, "X"), rgb2xyz(code.patch, "Z")], + opacity=0.8, + ) + if phenom: + return code.make_phenom_circuit( + noise=params.noise_model, + rounds=params.rounds, + debug_out_dir=params.debug_out_dir, + ) + assert params.rounds == 1 + return code.make_code_capacity_circuit( + noise=params.noise_model.idle_noise, + debug_out_dir=params.debug_out_dir + ) + + constructions["transit_color2surface_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_color2surface_layout( + base_data_width=params.diameter, + ), + phenom=False, + ) + constructions["phenom_color2surface_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_color2surface_layout( + base_data_width=params.diameter, + ), + phenom=True, + ) + + return constructions diff --git a/src/clorco/color_code/__init__.py b/src/clorco/color_code/__init__.py new file mode 100644 index 0000000..03a0e7f --- /dev/null +++ b/src/clorco/color_code/__init__.py @@ -0,0 +1,22 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ._color_code_layouts import ( + make_color_code_layout, + make_color_code_layout_488, + make_toric_color_code_layout, +) +from ._keyed_constructions import ( + make_named_color_code_constructions, +) diff --git a/src/clorco/color_code/_color_code_layouts.py b/src/clorco/color_code/_color_code_layouts.py new file mode 100644 index 0000000..65c403a --- /dev/null +++ b/src/clorco/color_code/_color_code_layouts.py @@ -0,0 +1,517 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Literal + +import gen + + +def _rect_to_hex_transform(c: complex) -> complex: + r = c.real + i = c.imag + f = 0.6 + if (c.real + c.imag + 1) % 2 == 0: + r += 0.5 * f + i *= f + return r + 1j * i + + +def make_color_code_layout( + *, + base_width: int, + spurs: Literal["smooth", "midout", "midout_readout_line_constraint"], + coord_style: Literal["rect", "hex"], + single_rgb_layer_instead_of_actual_code: bool, +) -> gen.StabilizerCode: + """Creates a color code over a truncated hexagonal tiling. + + Args: + base_width: The width of the base of the triangle. + spurs: Determines if there are jagged bits sticking out the sides of the code. + 'smooth': No spurs. The normal color code. + 'midout': Include the spurs needed for the midout circuit to run cleanly. + 'midout_readout_line_constraint': Extend the midout spurs so that there is + a subgrid of qubits that can all be simultaneously measured, This is + relevant if hardware has the constraint that qubits share a readout + line and measuring one qubit on the line hurts the coherence of the + others. + coord_style: Determines the qubit layout. + 'rect': Lay qubits onto a square grid, with stabilizers forming rectangles. + 'hex': Lay qubits onto a (nearly) hexagonal grid, with stabilizers forming hexagons. + single_rgb_layer_instead_of_actual_code: When False, this method returns an actual color + code. When True, the method will instead return a single layer of stabilizers with + bases XYZ corresponding to the RGB coloring. This is not the actual code because it's + only one layer instead of two layers, but it draws a lot better. + + Returns: + A StabilizerCode object defining the stabilizers and X/Z observable pair of the code. + """ + + half = base_width // 2 - 1 + w = 2 * half + 1 + h = 3 * half + 2 + + tiles = [] + for x in range(w + 1): + if x > half: + start_y = (x - half) * 3 - 2 + else: + start_y = h - x * 3 - 2 + assert start_y >= 0 + if x % 2 or spurs == "smooth": + start_y += 2 + for y in range(start_y, h, 2): + q = x + 1j * y + order = [0, 1j, 2j, 1 + 2j, 1 + 1j, 1] + if q.real % 2 == 0: + order = [e.conjugate() + 2j for e in order] + m = q + 1 + else: + m = q + 2j + tiles.append( + gen.Tile( + bases="XYZ"[int(q.imag % 3)], + measurement_qubit=m, + ordered_data_qubits=[q + d for d in order], + extra_coords=[q.imag % 3], + ) + ) + if x % 2 == 0: + q = x + 1j * h + tiles.append( + gen.Tile( + bases="Z", + measurement_qubit=q + 1, + ordered_data_qubits=[q + d for d in [1j, 0, 1, 1 + 1j]], + extra_coords=[2], + ) + ) + q = x + 1j * start_y + if x <= half: + if spurs == "midout_readout_line_constraint": + tiles.append( + gen.Tile( + bases="Y", + measurement_qubit=q + 1j - 1, + ordered_data_qubits=[q + d for d in [0, 1j - 1, 1j, -1]], + extra_coords=[1], + ) + ) + tiles.append( + gen.Tile( + bases="X", + measurement_qubit=q - 1, + ordered_data_qubits=[q + d for d in [-1, 1j - 1]], + extra_coords=[0], + ) + ) + else: + if spurs == "midout": + tiles.append( + gen.Tile( + bases="Z", + measurement_qubit=q + 1j, + ordered_data_qubits=[q + d for d in [1j, 0]], + extra_coords=[2], + ) + ) + else: + q += 1 + if spurs == "midout": + tiles.append( + gen.Tile( + bases="X", + measurement_qubit=q + 1j, + ordered_data_qubits=[q + d for d in [0, 1j]], + extra_coords=[0], + ) + ) + if x % 2 == 1 or spurs == "smooth": + q = x + 1j * start_y - 2j + if x <= half: + tiles.append( + gen.Tile( + bases="X", + measurement_qubit=q + 2j, + ordered_data_qubits=[q + d for d in [2j, 1 + 2j, 1 + 1j, 1]], + extra_coords=[0], + ) + ) + else: + tiles.append( + gen.Tile( + bases="Y", + measurement_qubit=q + 2j, + ordered_data_qubits=[q + d for d in [0, 1j, 2j, 1 + 2j]], + extra_coords=[1], + ) + ) + patch = gen.Patch(tiles).with_transformed_coords(lambda e: h * 1j + w - e + 1 + 2j) + if coord_style == "hex": + patch = patch.with_transformed_coords(_rect_to_hex_transform) + for tile in patch.tiles: + assert "XYZ".index(tile.basis) == tile.extra_coords[0] + if not single_rgb_layer_instead_of_actual_code: + patch = gen.Patch( + gen.Tile( + bases=basis, + measurement_qubit=tile.measurement_qubit + + (0.125 if basis == "Z" else 0), + ordered_data_qubits=tile.ordered_data_qubits, + extra_coords=[tile.extra_coords[0] + (3 if basis == "Z" else 0)], + ) + for tile in patch.tiles + for basis in "XZ" + ) + + return gen.StabilizerCode( + patch=patch, + observables_x=[gen.PauliString({q: "X" for q in patch.data_set})], + observables_z=[gen.PauliString({q: "Z" for q in patch.data_set})], + ) + + +def make_toric_color_code_layout( + *, + width: int, + height: int, + ablate_into_matchable_code: bool = False, + square_coords: bool = False, +) -> gen.StabilizerCode: + """Makes a toric color code layout with two ancilla qubits per hex on a square grid.""" + assert width % 6 == 0, (width, height) + assert height % 4 == 0, (width, height) + assert width > 0 and height > 0, (width, height) + + def wrap(q: complex) -> complex: + return (q.real % width) + (q.imag % height) * 1j + + tiles = [] + for y in range(0, height, 2): + for x in range((y // 2) % 2, width, 2): + q = x + 1j * y + order = [-1j, +1, +1 + 1j, +2j, -1 + 1j, -1] + rgb = x % 3 + if rgb != 0 or not ablate_into_matchable_code: + tiles.append( + gen.Tile( + bases="X", + measurement_qubit=wrap(q + 0), + ordered_data_qubits=[wrap(q + d) for d in order], + extra_coords=[rgb], + ) + ) + if rgb != 2 or not ablate_into_matchable_code: + tiles.append( + gen.Tile( + bases="Z", + measurement_qubit=wrap(q + 1j), + ordered_data_qubits=[wrap(q + d) for d in order], + extra_coords=[rgb + 3], + ) + ) + + patch = gen.Patch(tiles) + obs_x1 = gen.PauliString({q: "X" for q in patch.data_set if q.real == 0}) + obs_z1 = gen.PauliString( + {q: "Z" for q in patch.data_set if q.imag in [1, 2] and q.real % 3 != 2} + ) + obs_x2 = gen.PauliString( + { + q: "X" + for q in patch.data_set + if q.imag in [3, 4 % height] and q.real % 3 != 0 + } + ) + obs_z2 = gen.PauliString({q: "Z" for q in patch.data_set if q.real == 2}) + + result = gen.StabilizerCode( + patch=patch, + observables_x=[obs_x1, obs_x2], + observables_z=[obs_z1, obs_z2], + ) + if square_coords: + + def hex_to_rect(c: complex): + r = c.real + i = c.imag + if i == height - 1: + i = 0 + else: + if i % 4 == 0: + i -= 1 + elif i % 4 == 1: + i += 1 + i -= i // 4 * 2 + i -= 1 + return r + 1j * i + + result = result.with_transformed_coords(hex_to_rect) + + return result + + +def _rect_to_oct_transform(c: complex) -> complex: + r = c.real + i = c.imag + r *= 2 + if (i + 1) // 2 % 2 == 0: + r -= 1 + r += (r // 2) % 2 + r += 1 + else: + r += (r // 2) % 2 + + f = 0.1 + ib = f * (+1 if i % 2 == 0 else -1) + rb = f * (+1 if r % 2 == 0 else -1) + i += ib + r += rb + return r + 1j * i + + +def make_color_code_layout_488( + *, + base_width: int, + spurs: Literal["smooth", "midout", "midout_readout_line_constraint"], + coord_style: Literal["rect", "oct"], + single_rgb_layer_instead_of_actual_code: bool, +) -> gen.StabilizerCode: + """Makes a bounded oct/square patch with some spandrels to allow the inline cycle to work. + + Args: + base_width: The width of the base of the triangle. Must be odd. + spurs: Determines if there are jagged bits sticking out the sides of the code. + 'smooth': No spurs. The normal color code. + 'midout': Include the spurs needed for the midout circuit to run cleanly. + 'midout_readout_line_constraint': Extend the midout spurs so that there is + a subgrid of qubits that can all be simultaneously measured, This is + relevant if hardware has the constraint that qubits share a readout + line and measuring one qubit on the line hurts the coherence of the + others. + coord_style: Determines the qubit layout. + 'rect': Lay qubits onto a square grid, with stabilizers forming rectangles + and squares. + 'oct': Lay qubits onto a (nearly) 488 tiling, with stabilizers forming + octagons and squares. + single_rgb_layer_instead_of_actual_code: When False, this returns an actual color code. + When True, this returns a single layer of stabilizers with bases XYZ corresponding + to the RGB coloring. This is not the actual code because it's only one layer instead + of two layers, but it draws better. + + Returns: + A StabilizerCode object defining the stabilizers and X/Z observable pair of the code. + """ + + assert base_width % 2 == 1 + w = base_width + half = w // 2 + + tiles = [] + for x in range(1, w, 2): + q = x + tiles.append( + gen.Tile( + bases="Z", + measurement_qubit=q + 0.5, + ordered_data_qubits=[q + d for d in [1j, 0, 1, 1 + 1j]], + extra_coords=[2], + ) + ) + for x in range(0, half, 2): + q = x + 2j * x + if spurs == "midout_readout_line_constraint": + tiles.append( + gen.Tile( + bases="X", + measurement_qubit=q + 2j - 0.5, + ordered_data_qubits=[q + d for d in [1j, 2j, -1 + 2j, -1 + 1j]], + extra_coords=[0], + ) + ) + tiles.append( + gen.Tile( + bases="Y", + measurement_qubit=q + 1j - 1.5, + ordered_data_qubits=[q + d for d in [-1 + 2j, -1 + 1j]], + extra_coords=[1], + ) + ) + else: + if spurs != "smooth": + tiles.append( + gen.Tile( + bases="X", + measurement_qubit=q + 2j - 0.5, + ordered_data_qubits=[q + d for d in [1j, 2j]], + extra_coords=[0], + ) + ) + tiles.append( + gen.Tile( + bases="Y", + measurement_qubit=q + 0.5 + 1j, + ordered_data_qubits=[ + q + d + for d in ( + [0, 1 + 1j, 1, 1 + 1j, 1 + 2j] + if spurs == "smooth" + else [2j, 1j, 0, 1j, 1 + 1j, 1, 1 + 1j, 1 + 2j] + ) + ], + extra_coords=[1], + ) + ) + for x in range(0, half - 1, 2): + q = w - x + 2j * x + 2j - 1 + if spurs == "midout_readout_line_constraint": + tiles.append( + gen.Tile( + bases="X", + measurement_qubit=q + 0.5 + 1j, + ordered_data_qubits=[q + d for d in [2j, 1j, 1 + 1j, 1 + 2j]], + extra_coords=[0], + ) + ) + tiles.append( + gen.Tile( + bases="Z", + measurement_qubit=q + 1.5 + 2j, + ordered_data_qubits=[q + d for d in [1 + 1j, 1 + 2j]], + extra_coords=[2], + ) + ) + elif spurs != "smooth": + tiles.append( + gen.Tile( + bases="X", + measurement_qubit=q + 1j + 0.5, + ordered_data_qubits=[q + d for d in [1j, 2j]], + extra_coords=[0], + ) + ) + q -= 1 + tiles.append( + gen.Tile( + bases="Z", + measurement_qubit=q + 2j + 0.5, + ordered_data_qubits=[ + q + d + for d in ( + [0, 1j, 2j, 1] + if spurs == "smooth" + else [0, 1j, 2j, 1 + 2j, 1 + 1j, 1] + ) + ], + extra_coords=[2], + ) + ) + + for offset in range(0, w, 2): + for x in range(0, half - offset // 2, 1): + q = x + 2j * x + 1 + 1j + offset + tiles.append( + gen.Tile( + bases="X", + measurement_qubit=q + 0.5 + ((x + 1) % 2) * 1j, + ordered_data_qubits=[ + q + d + for d in ( + [0, 1j, 1 + 1j, 1] if x % 2 == 0 else [1j, 0, 1, 1 + 1j] + ) + ], + extra_coords=[0], + ) + ) + for offset in range(0, w, 2): + for x in range(0, half - offset // 2 - 1, 2): + q = x + 2j * x + 2 + offset + tiles.append( + gen.Tile( + bases="Y", + measurement_qubit=q + 0.5 + 1j, + ordered_data_qubits=[ + q + d + for d in [3j, 2j, 1j, 0, 1j, 1 + 1j, 1, 1 + 1j, 1 + 2j, 1 + 3j] + ], + extra_coords=[1], + ) + ) + for offset in range(0, w, 2): + for x in range(0, half - offset // 2 - 2, 2): + q = x + 2j * x + 3 + 2j + offset + tiles.append( + gen.Tile( + bases="Z", + measurement_qubit=q + 2j + 0.5, + ordered_data_qubits=[ + q + d + for d in [ + 3j, + 2j, + 1j, + 0, + 1j, + 2j, + 1 + 2j, + 1 + 1j, + 1, + 1 + 1j, + 1 + 2j, + 1 + 3j, + ] + ], + extra_coords=[2], + ) + ) + + patch = gen.Patch( + [ + gen.Tile( + bases=tile.bases, + measurement_qubit=tile.measurement_qubit + + -0.5 + * ( + 1 + if (tile.measurement_qubit.real % 2 == 0.5) + ^ (spurs == "midout_readout_line_constraint") + else -1 + ), + ordered_data_qubits=tile.ordered_data_qubits, + extra_coords=tile.extra_coords, + ) + for tile in tiles + ] + ) + if coord_style == "oct": + patch = patch.with_transformed_coords(_rect_to_oct_transform) + for tile in patch.tiles: + assert "XYZ".index(tile.basis) == tile.extra_coords[0] + if not single_rgb_layer_instead_of_actual_code: + patch = gen.Patch( + gen.Tile( + bases=basis, + measurement_qubit=tile.measurement_qubit + + (0.125 if basis == "Z" else 0), + ordered_data_qubits=tile.ordered_data_qubits, + extra_coords=[tile.extra_coords[0] + (3 if basis == "Z" else 0)], + ) + for tile in patch.tiles + for basis in "XZ" + ) + return gen.StabilizerCode( + patch=patch, + observables_x=[gen.PauliString({q: "X" for q in patch.data_set})], + observables_z=[gen.PauliString({q: "Z" for q in patch.data_set})], + ) diff --git a/src/clorco/color_code/_color_code_layouts_test.py b/src/clorco/color_code/_color_code_layouts_test.py new file mode 100644 index 0000000..5fbc0cb --- /dev/null +++ b/src/clorco/color_code/_color_code_layouts_test.py @@ -0,0 +1,829 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools +import math +from typing import Literal + +import pytest +import stim + +import gen + +from clorco.color_code._color_code_layouts import ( + make_color_code_layout_488, + make_color_code_layout, + make_toric_color_code_layout, +) + + +def test_make_color_code_patch_3_6(): + patch = make_color_code_layout( + base_width=9, + spurs="midout", + coord_style="rect", + single_rgb_layer_instead_of_actual_code=True, + ).patch + assert len(patch.tiles) == 34 + patch = make_color_code_layout( + base_width=11, + spurs="midout", + coord_style="rect", + single_rgb_layer_instead_of_actual_code=True, + ).patch + assert len(patch.tiles) == 50 + + patch = make_color_code_layout( + base_width=3, + spurs="midout", + coord_style="rect", + single_rgb_layer_instead_of_actual_code=True, + ).patch + assert patch == gen.Patch( + tiles=[ + gen.Tile( + ordered_data_qubits=((1 + 3j), (1 + 2j), (1 + 1j), 1j), + measurement_qubit=(1 + 1j), + bases="Y", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=((2 + 1j), (2 + 2j), (1 + 2j), (1 + 1j)), + measurement_qubit=(1 + 2j), + bases="Z", + extra_coords=(2,), + ), + gen.Tile( + ordered_data_qubits=( + (2 + 2j), + (2 + 3j), + (2 + 4j), + (1 + 4j), + (1 + 3j), + (1 + 2j), + ), + measurement_qubit=(1 + 4j), + bases="X", + extra_coords=(0.0,), + ), + gen.Tile( + ordered_data_qubits=((2 + 3j), (2 + 4j)), + measurement_qubit=(2 + 3j), + bases="Z", + extra_coords=(2,), + ), + ] + ) + + +def test_make_color_code_patch_4_8_8(): + patch = make_color_code_layout_488( + base_width=11, + spurs="midout", + single_rgb_layer_instead_of_actual_code=True, + coord_style="rect", + ).patch + assert len(patch.tiles) == 40 + patch = make_color_code_layout_488( + base_width=11, + spurs="midout_readout_line_constraint", + single_rgb_layer_instead_of_actual_code=True, + coord_style="rect", + ).patch + assert len(patch.tiles) == 45 + patch = make_color_code_layout_488( + base_width=13, + spurs="midout", + single_rgb_layer_instead_of_actual_code=True, + coord_style="rect", + ).patch + assert len(patch.tiles) == 54 + patch = make_color_code_layout_488( + base_width=13, + spurs="midout_readout_line_constraint", + single_rgb_layer_instead_of_actual_code=True, + coord_style="rect", + ).patch + assert len(patch.tiles) == 60 + + patch = make_color_code_layout_488( + base_width=5, + spurs="midout", + single_rgb_layer_instead_of_actual_code=True, + coord_style="rect", + ).patch + assert patch == gen.Patch( + tiles=[ + gen.Tile( + ordered_data_qubits=( + 2j, + 1j, + 0j, + 1j, + (1 + 1j), + (1 + 0j), + (1 + 1j), + (1 + 2j), + ), + measurement_qubit=1j, + bases="Y", + extra_coords=[1], + ), + gen.Tile( + ordered_data_qubits=(1j, 2j), + measurement_qubit=2j, + bases="X", + extra_coords=[0], + ), + gen.Tile( + ordered_data_qubits=((1 + 1j), 1, 2, (2 + 1j)), + measurement_qubit=2.0, + bases="Z", + extra_coords=[2], + ), + gen.Tile( + ordered_data_qubits=( + (2 + 3j), + (2 + 2j), + (2 + 1j), + (2 + 0j), + (2 + 1j), + (3 + 1j), + (3 + 0j), + (3 + 1j), + (3 + 2j), + (3 + 3j), + ), + measurement_qubit=(2 + 1j), + bases="Y", + extra_coords=[1], + ), + gen.Tile( + ordered_data_qubits=((1 + 1j), (1 + 2j), (2 + 2j), (2 + 1j)), + measurement_qubit=(2 + 2j), + bases="X", + extra_coords=[0], + ), + gen.Tile( + ordered_data_qubits=((2 + 4j), (2 + 3j), (3 + 3j), (3 + 4j)), + measurement_qubit=(2 + 3j), + bases="X", + extra_coords=[0], + ), + gen.Tile( + ordered_data_qubits=((3 + 1j), 3, 4, (4 + 1j)), + measurement_qubit=4.0, + bases="Z", + extra_coords=[2], + ), + gen.Tile( + ordered_data_qubits=((3 + 1j), (3 + 2j), (4 + 2j), (4 + 1j)), + measurement_qubit=(4 + 2j), + bases="X", + extra_coords=[0], + ), + gen.Tile( + ordered_data_qubits=((4 + 3j), (4 + 4j)), + measurement_qubit=(4 + 3j), + bases="X", + extra_coords=[0], + ), + gen.Tile( + ordered_data_qubits=( + (3 + 2j), + (3 + 3j), + (3 + 4j), + (4 + 4j), + (4 + 3j), + (4 + 2j), + ), + measurement_qubit=(4 + 4j), + bases="Z", + extra_coords=[2], + ), + ] + ) + + +@pytest.mark.parametrize( + "base_width,spurs", + itertools.product( + [3, 5, 7, 9, 11, 13], + ["smooth", "midout", "midout_readout_line_constraint"], + ), +) +def test_make_color_code_patch_4_8_8_stripped_measurements( + base_width: int, + spurs: Literal["smooth", "midout", "midout_readout_line_constraint"], +): + code = make_color_code_layout_488( + base_width=base_width, + spurs=spurs, + single_rgb_layer_instead_of_actual_code=True, + coord_style="rect", + ) + code.check_commutation_relationships() + + patch = code.patch + all_columns = {c.real for c in patch.data_set} + assert len(all_columns) == base_width + ( + 0 if spurs != "midout_readout_line_constraint" else 1 if base_width == 3 else 2 + ) + measure_columns = {tile.measurement_qubit.real for tile in patch.tiles} + data_columns = {c.real for c in patch.data_set - patch.measure_set} + if spurs == "midout_readout_line_constraint": + assert data_columns.isdisjoint(measure_columns) + assert len(measure_columns) == math.ceil(len(all_columns) / 2) + + +@pytest.mark.parametrize( + "width,height,ablate_into_matchable_code", + itertools.product( + [6, 12, 18], + [4, 8, 12, 16], + [False, True], + ), +) +def test_make_toric_color_code_layout( + width: int, height: int, ablate_into_matchable_code: bool +): + code = make_toric_color_code_layout( + width=width, + height=height, + ablate_into_matchable_code=ablate_into_matchable_code, + ) + code.check_commutation_relationships() + circuit = code.make_code_capacity_circuit( + noise=gen.NoiseRule(after={"DEPOLARIZE1": 1e-3}) + ) + if ablate_into_matchable_code: + err = circuit.shortest_graphlike_error( + canonicalize_circuit_errors=True, + ) + else: + err = circuit.search_for_undetectable_logical_errors( + dont_explore_edges_with_degree_above=4, + dont_explore_edges_increasing_symptom_degree=False, + canonicalize_circuit_errors=True, + dont_explore_detection_event_sets_with_size_above=4, + ) + + expected_distance = min(width // 3 * 2, height // 2) + assert len(err) == expected_distance + + +def test_make_toric_color_code_exact(): + assert make_toric_color_code_layout( + width=6, + height=8, + ablate_into_matchable_code=True, + ) == gen.StabilizerCode( + patch=gen.Patch( + tiles=[ + gen.Tile( + ordered_data_qubits=( + 7j, + (1 + 0j), + (1 + 1j), + 2j, + (5 + 1j), + (5 + 0j), + ), + measurement_qubit=1j, + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=( + 3j, + (1 + 4j), + (1 + 5j), + 6j, + (5 + 5j), + (5 + 4j), + ), + measurement_qubit=5j, + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=( + (1 + 1j), + (2 + 2j), + (2 + 3j), + (1 + 4j), + 3j, + 2j, + ), + measurement_qubit=(1 + 2j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=( + (1 + 1j), + (2 + 2j), + (2 + 3j), + (1 + 4j), + 3j, + 2j, + ), + measurement_qubit=(1 + 3j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=( + (1 + 5j), + (2 + 6j), + (2 + 7j), + (1 + 0j), + 7j, + 6j, + ), + measurement_qubit=(1 + 6j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=( + (1 + 5j), + (2 + 6j), + (2 + 7j), + (1 + 0j), + 7j, + 6j, + ), + measurement_qubit=(1 + 7j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=( + (2 + 7j), + (3 + 0j), + (3 + 1j), + (2 + 2j), + (1 + 1j), + (1 + 0j), + ), + measurement_qubit=(2 + 0j), + bases="X", + extra_coords=(2,), + ), + gen.Tile( + ordered_data_qubits=( + (2 + 3j), + (3 + 4j), + (3 + 5j), + (2 + 6j), + (1 + 5j), + (1 + 4j), + ), + measurement_qubit=(2 + 4j), + bases="X", + extra_coords=(2,), + ), + gen.Tile( + ordered_data_qubits=( + (3 + 1j), + (4 + 2j), + (4 + 3j), + (3 + 4j), + (2 + 3j), + (2 + 2j), + ), + measurement_qubit=(3 + 3j), + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=( + (3 + 5j), + (4 + 6j), + (4 + 7j), + (3 + 0j), + (2 + 7j), + (2 + 6j), + ), + measurement_qubit=(3 + 7j), + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=( + (4 + 7j), + (5 + 0j), + (5 + 1j), + (4 + 2j), + (3 + 1j), + (3 + 0j), + ), + measurement_qubit=(4 + 0j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=( + (4 + 7j), + (5 + 0j), + (5 + 1j), + (4 + 2j), + (3 + 1j), + (3 + 0j), + ), + measurement_qubit=(4 + 1j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=( + (4 + 3j), + (5 + 4j), + (5 + 5j), + (4 + 6j), + (3 + 5j), + (3 + 4j), + ), + measurement_qubit=(4 + 4j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=( + (4 + 3j), + (5 + 4j), + (5 + 5j), + (4 + 6j), + (3 + 5j), + (3 + 4j), + ), + measurement_qubit=(4 + 5j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=( + (5 + 1j), + 2j, + 3j, + (5 + 4j), + (4 + 3j), + (4 + 2j), + ), + measurement_qubit=(5 + 2j), + bases="X", + extra_coords=(2,), + ), + gen.Tile( + ordered_data_qubits=( + (5 + 5j), + 6j, + 7j, + (5 + 0j), + (4 + 7j), + (4 + 6j), + ), + measurement_qubit=(5 + 6j), + bases="X", + extra_coords=(2,), + ), + ] + ), + observables_x=[ + gen.PauliString(qubits={2j: "X", 3j: "X", 6j: "X", 7j: "X"}), + gen.PauliString( + qubits={(1 + 4j): "X", (2 + 3j): "X", (4 + 3j): "X", (5 + 4j): "X"} + ), + ], + observables_z=[ + gen.PauliString( + qubits={2j: "Z", (1 + 1j): "Z", (3 + 1j): "Z", (4 + 2j): "Z"} + ), + gen.PauliString( + qubits={(2 + 2j): "Z", (2 + 3j): "Z", (2 + 6j): "Z", (2 + 7j): "Z"} + ), + ], + ) + + +def test_make_toric_color_code_phenom_circuit_exact(): + code = make_toric_color_code_layout( + width=6, + height=8, + ablate_into_matchable_code=True, + ) + assert code.make_code_capacity_circuit(noise=0.125) == stim.Circuit( + """ + QUBIT_COORDS(0, -1) 0 + QUBIT_COORDS(0, 2) 1 + QUBIT_COORDS(0, 3) 2 + QUBIT_COORDS(0, 6) 3 + QUBIT_COORDS(0, 7) 4 + QUBIT_COORDS(1, -1) 5 + QUBIT_COORDS(1, 0) 6 + QUBIT_COORDS(1, 1) 7 + QUBIT_COORDS(1, 4) 8 + QUBIT_COORDS(1, 5) 9 + QUBIT_COORDS(2, 2) 10 + QUBIT_COORDS(2, 3) 11 + QUBIT_COORDS(2, 6) 12 + QUBIT_COORDS(2, 7) 13 + QUBIT_COORDS(3, 0) 14 + QUBIT_COORDS(3, 1) 15 + QUBIT_COORDS(3, 4) 16 + QUBIT_COORDS(3, 5) 17 + QUBIT_COORDS(4, 2) 18 + QUBIT_COORDS(4, 3) 19 + QUBIT_COORDS(4, 6) 20 + QUBIT_COORDS(4, 7) 21 + QUBIT_COORDS(5, 0) 22 + QUBIT_COORDS(5, 1) 23 + QUBIT_COORDS(5, 4) 24 + QUBIT_COORDS(5, 5) 25 + MPP X0*X1*X2*X3*X4 + OBSERVABLE_INCLUDE(0) rec[-1] + MPP X5*X8*X11*X19*X24 + OBSERVABLE_INCLUDE(1) rec[-1] + MPP Z0*Z1*Z7*Z15*Z18 + OBSERVABLE_INCLUDE(2) rec[-1] + MPP Z5*Z10*Z11*Z12*Z13 + OBSERVABLE_INCLUDE(3) rec[-1] + MPP Z1*Z4*Z6*Z7*Z22*Z23 Z2*Z3*Z8*Z9*Z24*Z25 X1*X2*X7*X8*X10*X11 Z1*Z2*Z7*Z8*Z10*Z11 X3*X4*X6*X9*X12*X13 Z3*Z4*Z6*Z9*Z12*Z13 X6*X7*X10*X13*X14*X15 X8*X9*X11*X12*X16*X17 Z10*Z11*Z15*Z16*Z18*Z19 Z12*Z13*Z14*Z17*Z20*Z21 X14*X15*X18*X21*X22*X23 Z14*Z15*Z18*Z21*Z22*Z23 X16*X17*X19*X20*X24*X25 Z16*Z17*Z19*Z20*Z24*Z25 X1*X2*X18*X19*X23*X24 X3*X4*X20*X21*X22*X25 + TICK + DEPOLARIZE1(0.125) 1 2 3 4 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 + TICK + MPP Z1*Z4*Z6*Z7*Z22*Z23 Z2*Z3*Z8*Z9*Z24*Z25 X1*X2*X7*X8*X10*X11 Z1*Z2*Z7*Z8*Z10*Z11 X3*X4*X6*X9*X12*X13 Z3*Z4*Z6*Z9*Z12*Z13 X6*X7*X10*X13*X14*X15 X8*X9*X11*X12*X16*X17 Z10*Z11*Z15*Z16*Z18*Z19 Z12*Z13*Z14*Z17*Z20*Z21 X14*X15*X18*X21*X22*X23 Z14*Z15*Z18*Z21*Z22*Z23 X16*X17*X19*X20*X24*X25 Z16*Z17*Z19*Z20*Z24*Z25 X1*X2*X18*X19*X23*X24 X3*X4*X20*X21*X22*X25 + DETECTOR(0, 1, 0, 3) rec[-32] rec[-16] + DETECTOR(0, 5, 0, 3) rec[-31] rec[-15] + DETECTOR(1, 2, 0, 1) rec[-30] rec[-14] + DETECTOR(1, 3, 0, 4) rec[-29] rec[-13] + DETECTOR(1, 6, 0, 1) rec[-28] rec[-12] + DETECTOR(1, 7, 0, 4) rec[-27] rec[-11] + DETECTOR(2, 0, 0, 2) rec[-26] rec[-10] + DETECTOR(2, 4, 0, 2) rec[-25] rec[-9] + DETECTOR(3, 3, 0, 3) rec[-24] rec[-8] + DETECTOR(3, 7, 0, 3) rec[-23] rec[-7] + DETECTOR(4, 0, 0, 1) rec[-22] rec[-6] + DETECTOR(4, 1, 0, 4) rec[-21] rec[-5] + DETECTOR(4, 4, 0, 1) rec[-20] rec[-4] + DETECTOR(4, 5, 0, 4) rec[-19] rec[-3] + DETECTOR(5, 2, 0, 2) rec[-18] rec[-2] + DETECTOR(5, 6, 0, 2) rec[-17] rec[-1] + MPP X0*X1*X2*X3*X4 + OBSERVABLE_INCLUDE(0) rec[-1] + MPP X5*X8*X11*X19*X24 + OBSERVABLE_INCLUDE(1) rec[-1] + MPP Z0*Z1*Z7*Z15*Z18 + OBSERVABLE_INCLUDE(2) rec[-1] + MPP Z5*Z10*Z11*Z12*Z13 + OBSERVABLE_INCLUDE(3) rec[-1] + """ + ) + + +def test_make_toric_color_code_exact_square_coords(): + assert make_toric_color_code_layout( + width=6, + height=8, + ablate_into_matchable_code=True, + square_coords=True, + ) == gen.StabilizerCode( + patch=gen.Patch( + tiles=[ + gen.Tile( + ordered_data_qubits=( + 0j, + (1 + 0j), + (1 + 1j), + 1j, + (5 + 1j), + (5 + 0j), + ), + measurement_qubit=1j, + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=( + 2j, + (1 + 2j), + (1 + 3j), + 3j, + (5 + 3j), + (5 + 2j), + ), + measurement_qubit=3j, + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=( + (1 + 3j), + (2 + 3j), + (2 + 0j), + (1 + 0j), + 0j, + 3j, + ), + measurement_qubit=(1 + 0j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=( + (1 + 1j), + (2 + 1j), + (2 + 2j), + (1 + 2j), + 2j, + 1j, + ), + measurement_qubit=(1 + 1j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=( + (1 + 1j), + (2 + 1j), + (2 + 2j), + (1 + 2j), + 2j, + 1j, + ), + measurement_qubit=(1 + 2j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=( + (1 + 3j), + (2 + 3j), + (2 + 0j), + (1 + 0j), + 0j, + 3j, + ), + measurement_qubit=(1 + 3j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=( + (2 + 0j), + (3 + 0j), + (3 + 1j), + (2 + 1j), + (1 + 1j), + (1 + 0j), + ), + measurement_qubit=(2 + 0j), + bases="X", + extra_coords=(2,), + ), + gen.Tile( + ordered_data_qubits=( + (2 + 2j), + (3 + 2j), + (3 + 3j), + (2 + 3j), + (1 + 3j), + (1 + 2j), + ), + measurement_qubit=(2 + 2j), + bases="X", + extra_coords=(2,), + ), + gen.Tile( + ordered_data_qubits=( + (3 + 3j), + (4 + 3j), + (4 + 0j), + (3 + 0j), + (2 + 0j), + (2 + 3j), + ), + measurement_qubit=(3 + 0j), + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=( + (3 + 1j), + (4 + 1j), + (4 + 2j), + (3 + 2j), + (2 + 2j), + (2 + 1j), + ), + measurement_qubit=(3 + 2j), + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=( + (4 + 0j), + (5 + 0j), + (5 + 1j), + (4 + 1j), + (3 + 1j), + (3 + 0j), + ), + measurement_qubit=(4 + 0j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=( + (4 + 0j), + (5 + 0j), + (5 + 1j), + (4 + 1j), + (3 + 1j), + (3 + 0j), + ), + measurement_qubit=(4 + 1j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=( + (4 + 2j), + (5 + 2j), + (5 + 3j), + (4 + 3j), + (3 + 3j), + (3 + 2j), + ), + measurement_qubit=(4 + 2j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=( + (4 + 2j), + (5 + 2j), + (5 + 3j), + (4 + 3j), + (3 + 3j), + (3 + 2j), + ), + measurement_qubit=(4 + 3j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=( + (5 + 1j), + 1j, + 2j, + (5 + 2j), + (4 + 2j), + (4 + 1j), + ), + measurement_qubit=(5 + 1j), + bases="X", + extra_coords=(2,), + ), + gen.Tile( + ordered_data_qubits=( + (5 + 3j), + 3j, + 0j, + (5 + 0j), + (4 + 0j), + (4 + 3j), + ), + measurement_qubit=(5 + 3j), + bases="X", + extra_coords=(2,), + ), + ] + ), + observables_x=[ + gen.PauliString(qubits={0j: "X", 1j: "X", 2j: "X", 3j: "X"}), + gen.PauliString( + qubits={(1 + 2j): "X", (2 + 2j): "X", (4 + 2j): "X", (5 + 2j): "X"} + ), + ], + observables_z=[ + gen.PauliString( + qubits={1j: "Z", (1 + 1j): "Z", (3 + 1j): "Z", (4 + 1j): "Z"} + ), + gen.PauliString( + qubits={(2 + 0j): "Z", (2 + 1j): "Z", (2 + 2j): "Z", (2 + 3j): "Z"} + ), + ], + ) diff --git a/src/clorco/color_code/_keyed_constructions.py b/src/clorco/color_code/_keyed_constructions.py new file mode 100644 index 0000000..56231cc --- /dev/null +++ b/src/clorco/color_code/_keyed_constructions.py @@ -0,0 +1,429 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import functools +from typing import Callable, Any +from typing import Literal +from typing import cast + +import stim + +import gen +from clorco._make_circuit_params import Params +from clorco.color_code._color_code_layouts import ( + make_color_code_layout, + make_color_code_layout_488, + make_toric_color_code_layout, +) +from clorco.color_code._midout_planar_color_code_circuits import ( + make_midout_color_code_circuit_chunks, +) +from clorco.color_code._mxyz_color_codes import make_mxyz_color_code_from_stim_gen +from clorco.color_code._mxyz_color_codes import make_mxyz_phenom_color_code +from clorco.color_code._superdense_planar_color_code_circuits import ( + make_color_code_layout_for_superdense, +) +from clorco.color_code._superdense_planar_color_code_circuits import ( + make_superdense_color_code_circuit, +) +from clorco.color_code._toric_color_code_circuits import ( + make_toric_color_code_circuit_with_magic_time_boundaries, +) + + +def make_named_color_code_constructions() -> ( + dict[str, Callable[[Params], stim.Circuit]] +): + return { + **_midout_color_code_circuit_constructions(), + **_simplified_noise_color_code_constructions(), + **_toric_color_code_constructions(), + **_superdense_color_code_circuit_constructions(), + } + + +def _midout_color_code_circuit_constructions() -> ( + dict[str, Callable[[Params], stim.Circuit]] +): + constructions: dict[str, Callable[[Params], stim.Circuit]] = {} + + def _chunks_to_circuit(params: Params, chunks: list[gen.Chunk]) -> stim.Circuit: + circuit = gen.compile_chunks_into_circuit(chunks) + + if params.debug_out_dir is not None: + make_layout = make_color_code_layout_488 if '488' in params.style else make_color_code_layout + rgb_patch = make_layout( + base_width=params.diameter, + spurs="midout", + coord_style="rect", + single_rgb_layer_instead_of_actual_code=True, + ).patch + gen.write_file( + params.debug_out_dir / 'ideal_circuit.html', + gen.stim_circuit_html_viewer(circuit, patch=rgb_patch), + ) + + if params.convert_to_cz: + circuit = gen.transpile_to_z_basis_interaction_circuit(circuit) + circuit = circuit.with_inlined_feedback() + if params.noise_model is not None: + circuit = params.noise_model.noisy_circuit(circuit) + + if params.debug_out_dir is not None: + make_layout = make_color_code_layout_488 if '488' in params.style else make_color_code_layout + make_layout( + base_width=params.diameter, + spurs="smooth", + coord_style="rect", + single_rgb_layer_instead_of_actual_code=True, + ).patch.write_svg( + params.debug_out_dir / "rgb_patch_smooth.svg", + show_data_qubits=True, + show_order=False, + show_measure_qubits=False, + ) + make_layout( + base_width=params.diameter, + spurs="smooth", + coord_style=cast(Any, "oct" if '488' in params.style else "hex"), + single_rgb_layer_instead_of_actual_code=True, + ).patch.write_svg( + params.debug_out_dir / "rgb_patch_hex_smooth.svg", + show_data_qubits=True, + show_order=False, + show_measure_qubits=False, + ) + make_layout( + base_width=params.diameter, + spurs="midout", + coord_style=cast(Any, "oct" if '488' in params.style else "hex"), + single_rgb_layer_instead_of_actual_code=True, + ).patch.write_svg( + params.debug_out_dir / "rgb_patch_hex.svg", + show_data_qubits=True, + show_order=False, + show_measure_qubits=False, + ) + make_layout( + base_width=params.diameter, + spurs="midout_readout_line_constraint", + coord_style="rect", + single_rgb_layer_instead_of_actual_code=True, + ).patch.write_svg( + params.debug_out_dir / "rgb_patch_extra_spurs.svg", + show_data_qubits=True, + show_order=False, + show_measure_qubits=False, + ) + rgb_patch = make_layout( + base_width=params.diameter, + spurs="midout", + coord_style="rect", + single_rgb_layer_instead_of_actual_code=True, + ).patch + rgb_patch.write_svg( + params.debug_out_dir / "rgb_patch.svg", + show_data_qubits=True, + show_order=False, + show_measure_qubits=False, + ) + gen.write_file( + params.debug_out_dir / 'circuit.html', + gen.stim_circuit_html_viewer(circuit, patch=rgb_patch), + ) + + return circuit + + constructions[ + "mxyz_color_code" + ] = lambda params: make_mxyz_color_code_from_stim_gen( + distance=params.diameter, + rounds=params.rounds, + noise=params.noise_model, + convert_to_cz=params.convert_to_cz, + ) + constructions[ + "phenom_mxyz_color_code" + ] = lambda params: make_mxyz_phenom_color_code( + base_width=params.diameter, + rounds=params.rounds, + noise=params.noise_strength, + ) + + constructions["midout_color_code_Z"] = lambda params: _chunks_to_circuit( + params, + make_midout_color_code_circuit_chunks( + basis="Z", + base_width=params.diameter, + rounds=params.rounds, + use_488=False, + ), + ) + constructions["midout_color_code_X"] = lambda params: _chunks_to_circuit( + params, + make_midout_color_code_circuit_chunks( + basis="X", + base_width=params.diameter, + rounds=params.rounds, + use_488=False, + ), + ) + constructions["midout_color_code_Z"] = lambda params: _chunks_to_circuit( + params, + make_midout_color_code_circuit_chunks( + basis="Z", + base_width=params.diameter, + rounds=params.rounds, + use_488=False, + ), + ) + constructions["midout_color_code_488_X"] = lambda params: _chunks_to_circuit( + params, + make_midout_color_code_circuit_chunks( + basis="X", + base_width=params.diameter, + rounds=params.rounds, + use_488=True, + ), + ) + constructions["midout_color_code_488_Z"] = lambda params: _chunks_to_circuit( + params, + make_midout_color_code_circuit_chunks( + basis="Z", + base_width=params.diameter, + rounds=params.rounds, + use_488=True, + ), + ) + return constructions + + +def _superdense_color_code_circuit_constructions() -> ( + dict[str, Callable[[Params], stim.Circuit]] +): + constructions: dict[str, Callable[[Params], stim.Circuit]] = {} + + def _chunks_to_circuit(params: Params) -> stim.Circuit: + basis = params.style[-1] + assert basis == "X" or basis == "Z" + circuit = make_superdense_color_code_circuit( + base_data_width=params.diameter, + basis=cast(Literal["X", "Z"], basis), + rounds=params.rounds, + ) + + if params.debug_out_dir is not None: + rgb_patch = make_color_code_layout_for_superdense( + base_data_width=params.diameter, + single_rgb_layer_instead_of_actual_code=True, + ).patch + gen.write_file( + params.debug_out_dir / "ideal_circuit.html", + gen.stim_circuit_html_viewer(circuit, patch=rgb_patch), + ) + rgb_patch = make_color_code_layout_for_superdense( + base_data_width=params.diameter, + single_rgb_layer_instead_of_actual_code='double_measure_qubit', + ).patch + rgb_patch.write_svg( + params.debug_out_dir / "rgb_patch.svg", + show_order=False, + show_measure_qubits=False, + ) + rgb_patch.write_svg( + params.debug_out_dir / "rgb_patch_qubits.svg", + show_order=False, + show_measure_qubits=True, + show_data_qubits=True, + ) + make_color_code_layout_for_superdense( + base_data_width=params.diameter, + single_rgb_layer_instead_of_actual_code=False, + ).write_svg(params.debug_out_dir / "code.svg", show_measure_qubits=True) + + if params.convert_to_cz: + circuit = gen.transpile_to_z_basis_interaction_circuit(circuit) + if params.noise_model is not None: + circuit = params.noise_model.noisy_circuit(circuit) + return circuit + + constructions["superdense_color_code_X"] = _chunks_to_circuit + constructions["superdense_color_code_Z"] = _chunks_to_circuit + return constructions + + +def _simplified_noise_color_code_constructions() -> ( + dict[str, Callable[[Params], stim.Circuit]] +): + constructions: dict[str, Callable[[Params], stim.Circuit]] = {} + + def _make_simple_circuit( + params: Params, *, code: gen.StabilizerCode, phenom: bool + ) -> stim.Circuit: + if phenom: + return code.make_phenom_circuit( + noise=params.noise_model, + rounds=params.rounds, + debug_out_dir=params.debug_out_dir, + ) + assert params.rounds == 1 + return code.make_code_capacity_circuit( + noise=params.noise_model.idle_noise, + debug_out_dir=params.debug_out_dir + ) + + constructions["transit_color_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_color_code_layout( + base_width=params.diameter, + coord_style="rect", + single_rgb_layer_instead_of_actual_code=False, + spurs="smooth", + ), + phenom=False, + ) + constructions["phenom_color_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_color_code_layout( + base_width=params.diameter, + coord_style="rect", + single_rgb_layer_instead_of_actual_code=False, + spurs="smooth", + ), + phenom=True, + ) + constructions["phenom_color_code_488"] = lambda params: _make_simple_circuit( + params=params, + code=make_color_code_layout_488( + base_width=params.diameter, + coord_style="rect", + single_rgb_layer_instead_of_actual_code=False, + spurs="smooth", + ), + phenom=True, + ) + constructions["transit_color_code_488"] = lambda params: _make_simple_circuit( + params=params, + code=make_color_code_layout_488( + base_width=params.diameter, + coord_style="rect", + single_rgb_layer_instead_of_actual_code=False, + spurs="smooth", + ), + phenom=False, + ) + return constructions + + +def _toric_color_code_constructions() -> dict[str, Callable[[Params], stim.Circuit]]: + def _infer_size(params: Params): + width = params.editable_extras.get("w") + height = params.editable_extras.get("h") + if width is None: + width = params.diameter + if height is None: + height = width // 6 * 8 + params.editable_extras["w"] = width + params.editable_extras["h"] = height + return width, height + + def _make_circuit( + params: Params, *, style: Any, ablate_into_matchable_code: bool + ) -> stim.Circuit: + width, height = _infer_size(params) + circuit = make_toric_color_code_circuit_with_magic_time_boundaries( + width=width, + height=height, + noise=params.noise_model, + rounds=params.rounds, + style=style, + convert_to_cz=params.convert_to_cz, + ablate_into_matchable_code=ablate_into_matchable_code, + ) + if params.debug_out_dir is not None: + gen.write_file( + params.debug_out_dir / "circuit.html", + gen.stim_circuit_html_viewer(circuit), + ) + return circuit + + constructions = {} + constructions["toric_superdense_color_code_magicEPR"] = functools.partial( + _make_circuit, style="superdense", ablate_into_matchable_code=False + ) + constructions["toric_midout_color_code_magicEPR"] = functools.partial( + _make_circuit, style="midout", ablate_into_matchable_code=False + ) + constructions["ablated_toric_superdense_color_code_magicEPR"] = functools.partial( + _make_circuit, style="superdense", ablate_into_matchable_code=True + ) + constructions["ablated_toric_midout_color_code_magicEPR"] = functools.partial( + _make_circuit, style="midout", ablate_into_matchable_code=True + ) + + def _make_simple_circuit( + params: Params, *, ablate_into_matchable_code: bool, phenom: bool + ) -> stim.Circuit: + width, height = _infer_size(params) + code = make_toric_color_code_layout( + width=width, + height=height, + ablate_into_matchable_code=ablate_into_matchable_code, + ) + if params.debug_out_dir is not None: + code.write_svg(params.debug_out_dir / "code.svg") + code.patch.without_wraparound_tiles().write_svg( + params.debug_out_dir / "patch.svg", show_order=False + ) + code.patch.write_svg( + params.debug_out_dir / "patch_xz.svg", + other=[ + code.patch.with_only_x_tiles(), + code.patch.with_only_z_tiles(), + ], + show_order=False, + system_qubits=code.patch.data_set, + wraparound_clip=True, + ) + if phenom: + circuit = code.make_phenom_circuit( + noise=params.noise_strength, rounds=params.rounds + ) + else: + assert params.rounds == 1 + circuit = code.make_code_capacity_circuit(noise=params.noise_strength) + if params.debug_out_dir is not None: + gen.write_file( + params.debug_out_dir / "detslice.svg", circuit.diagram("detslice-svg") + ) + gen.write_file( + params.debug_out_dir / "graph.html", + circuit.diagram("match-graph-3d-html"), + ) + return circuit + + constructions["transit_toric_color_code"] = functools.partial( + _make_simple_circuit, ablate_into_matchable_code=False, phenom=False + ) + constructions["transit_ablated_toric_color_code"] = functools.partial( + _make_simple_circuit, ablate_into_matchable_code=True, phenom=False + ) + constructions["phenom_toric_color_code"] = functools.partial( + _make_simple_circuit, ablate_into_matchable_code=False, phenom=True + ) + constructions["phenom_ablated_toric_color_code"] = functools.partial( + _make_simple_circuit, ablate_into_matchable_code=True, phenom=True + ) + + return constructions diff --git a/src/clorco/color_code/_midout_planar_color_code_circuits.py b/src/clorco/color_code/_midout_planar_color_code_circuits.py new file mode 100644 index 0000000..8d57f41 --- /dev/null +++ b/src/clorco/color_code/_midout_planar_color_code_circuits.py @@ -0,0 +1,235 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Iterable, Callable + +import gen +from clorco.color_code._color_code_layouts import ( + make_color_code_layout, + make_color_code_layout_488, +) + + +def _color_code_round_chunk( + *, + base_width: int, + use_488: bool, + basis: str, + layer_parity: bool, + first_round: bool, +) -> gen.Chunk: + if use_488: + code = make_color_code_layout_488( + base_width=base_width, + spurs="midout", + coord_style="rect", + single_rgb_layer_instead_of_actual_code=True, + ) + else: + code = make_color_code_layout( + base_width=base_width, + spurs="midout", + coord_style="rect", + single_rgb_layer_instead_of_actual_code=True, + ) + patch = code.patch + + rail_b = { + (q, q + 1j) + for q in patch.data_set + if q.imag % 2 == 0 + if q + 1j in patch.data_set + } + rail_a = { + (q, q + 1j) + for q in patch.data_set + if q.imag % 2 == 1 + if q + 1j in patch.data_set + } + rung_m = { + (other, q) + for q in patch.data_set + if (q.imag + q.real) % 2 == 1 + if (other := q + 1) in patch.data_set + } + if use_488: + rung_m = rev_pairs(rung_m) + rail_b = rev_pairs(rail_b, pred=lambda a, _: a.imag % 4 == 0) + + mx = {q for q in patch.measure_set if q.imag % 2 == 1} + mz = {q for q in patch.measure_set if q.imag % 2 == 0} + m2t = {tile.measurement_qubit: tile for tile in patch.tiles} + assert len(m2t) == len(patch.tiles) + if not layer_parity: + mx, mz = mz, mx + rung_m = rev_pairs(rung_m) + rail_b = rev_pairs(rail_b) + rail_a = rev_pairs(rail_a) + + builder = gen.Builder.for_qubits(patch.data_set) + + # Fold color code state towards next measurement. + if not first_round: + builder.gate2("CX", rail_b) + builder.tick() + builder.gate2("CX", rail_a) + builder.tick() + builder.gate2("CX", rung_m) + builder.tick() + + # Measure stabilizers. + builder.measure(mx, basis="X", save_layer="solo") + builder.measure(mz, basis="Z", save_layer="solo") + builder.shift_coords(dt=1) + builder.tick() + + # Physically do a demolition measurement, but use feedback to present it as non-demolition to the control system. + builder.gate("RX", mx) + if first_round: + builder.gate(f"R{basis}", patch.data_set - mx - mz) + builder.gate("R", mz) + if not first_round: + for ms, mb in ((mx, "Z"), (mz, "X")): + for m in gen.sorted_complex(ms): + builder.classical_paulis( + control_keys=[gen.AtLayer(m, "solo")], targets=[m], basis=mb + ) + builder.tick() + + # Unfold from previous measurement to color code state. + builder.gate2("CX", rung_m) + builder.tick() + builder.gate2("CX", rail_a) + builder.tick() + builder.gate2("CX", rail_b) + + flows = [] + discarded_outputs = [] + for tile in patch.tiles: + measured_tile_basis = "X" if tile.measurement_qubit in mx else "Z" + for check_basis in "XZ": + ps = gen.PauliString({q: check_basis for q in tile.data_set}) + additional_coords = [tile.extra_coords[0] + "XZ".index(check_basis) * 3] + if first_round: + if check_basis in [basis, measured_tile_basis]: + flows.append( + gen.Flow( + end=ps, + center=tile.measurement_qubit, + additional_coords=additional_coords, + ) + ) + else: + discarded_outputs.append(ps) + else: + if check_basis == measured_tile_basis: + ms = builder.tracker.measurement_indices( + [gen.AtLayer(tile.measurement_qubit, "solo")] + ) + flows.append( + gen.Flow( + start=ps, + measurement_indices=ms, + center=tile.measurement_qubit, + additional_coords=additional_coords, + ) + ) + flows.append( + gen.Flow( + end=ps, + measurement_indices=ms, + center=tile.measurement_qubit, + additional_coords=additional_coords, + ) + ) + else: + flows.append( + gen.Flow( + start=ps, + end=ps, + center=tile.measurement_qubit, + additional_coords=additional_coords, + ) + ) + + obs = gen.PauliString({q: basis for q in patch.data_set}) + flows.append( + gen.Flow( + start=None if first_round else obs, + end=obs, + center=0, + obs_index=0, + additional_coords=(), + ) + ) + + return gen.Chunk( + circuit=builder.circuit, + q2i=builder.q2i, + flows=flows, + discarded_outputs=discarded_outputs, + ) + + +def make_midout_color_code_circuit_chunks( + *, + base_width: int, + basis: str, + rounds: int, + use_488: bool, +) -> list[gen.Chunk]: + assert rounds >= 2 + start_not_a_round = _color_code_round_chunk( + base_width=base_width, + use_488=use_488, + basis=basis, + layer_parity=False, + first_round=True, + ) + body_0, body_1 = [ + _color_code_round_chunk( + base_width=base_width, + use_488=use_488, + basis=basis, + layer_parity=b, + first_round=False, + ) + for b in [False, True] + ] + end = _color_code_round_chunk( + base_width=base_width, + use_488=use_488, + basis=basis, + layer_parity=rounds % 2 == 1, + first_round=True, + ).inverted() + + if rounds % 2 == 0: + tail = [body_1, end] + else: + tail = [end] + + return [ + start_not_a_round, + gen.ChunkLoop([body_1, body_0], repetitions=(rounds - 1) // 2), + *tail, + ] + + +def rev_pairs( + pairs: Iterable[tuple[complex, complex]], + *, + pred: Callable[[complex, complex], bool] = lambda _a, _b: True, +) -> list[tuple[complex, complex]]: + return [e[:: -1 if pred(*e) else +1] for e in pairs] diff --git a/src/clorco/color_code/_midout_planar_color_code_circuits_test.py b/src/clorco/color_code/_midout_planar_color_code_circuits_test.py new file mode 100644 index 0000000..b52e20e --- /dev/null +++ b/src/clorco/color_code/_midout_planar_color_code_circuits_test.py @@ -0,0 +1,313 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools + +import pytest +import stim + +import gen +from clorco._make_circuit import make_circuit +from clorco.color_code._midout_planar_color_code_circuits import ( + _color_code_round_chunk, + make_midout_color_code_circuit_chunks, +) + + +@pytest.mark.parametrize( + "basis,base_width,use_488,layer_parity,first_round", + itertools.product( + "XZ", + [3, 5, 7, 9, 11], + [False, True], + [False, True], + [False, True], + ), +) +def test_color_code_round_chunk( + basis: str, base_width: int, use_488: bool, layer_parity: bool, first_round: bool +): + _color_code_round_chunk( + base_width=base_width, + use_488=use_488, + basis=basis, + layer_parity=layer_parity, + first_round=first_round, + ).verify() + + +@pytest.mark.parametrize( + "basis,base_width,use_488,rounds", + itertools.product( + "XZ", + [3, 5, 7, 9], + [False, True], + [2, 3, 4, 5, 6, 7], + ), +) +def test_make_color_code_circuit_chunks( + basis: str, base_width: int, use_488: bool, rounds: int +): + chunks = make_midout_color_code_circuit_chunks( + basis=basis, + base_width=base_width, + rounds=rounds, + use_488=use_488, + ) + + circuit = gen.compile_chunks_into_circuit(chunks) + circuit.detector_error_model() + assert ( + circuit.count_determined_measurements() + == circuit.num_observables + circuit.num_detectors + ) + + noisy = gen.NoiseModel.uniform_depolarizing(1e-3).noisy_circuit( + circuit.with_inlined_feedback() + ) + if use_488: + expected_distance = base_width // 4 + 1 + else: + expected_distance = base_width // 2 + 1 - (basis == "Y" and base_width > 3) + actual_distance = len(noisy.shortest_graphlike_error()) + assert actual_distance == expected_distance + + +def test_exact_color_code_circuit(): + circuit = make_circuit( + style="midout_color_code_X", + noise_model=gen.NoiseModel.uniform_depolarizing(1e-3), + noise_strength=1e-3, + rounds=11, + diameter=3, + convert_to_cz=False, + editable_extras={}, + ) + assert circuit == stim.Circuit( + """ + QUBIT_COORDS(0, 1) 0 + QUBIT_COORDS(1, 1) 1 + QUBIT_COORDS(1, 2) 2 + QUBIT_COORDS(1, 3) 3 + QUBIT_COORDS(1, 4) 4 + QUBIT_COORDS(2, 1) 5 + QUBIT_COORDS(2, 2) 6 + QUBIT_COORDS(2, 3) 7 + QUBIT_COORDS(2, 4) 8 + RX 2 4 0 3 5 6 8 + R 1 7 + X_ERROR(0.001) 1 7 + Z_ERROR(0.001) 2 4 0 3 5 6 8 + TICK + CX 0 1 2 6 4 8 + DEPOLARIZE2(0.001) 0 1 2 6 4 8 + DEPOLARIZE1(0.001) 3 5 7 + TICK + CX 2 1 4 3 6 5 8 7 + DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 + DEPOLARIZE1(0.001) 0 + TICK + CX 3 2 7 6 + DEPOLARIZE2(0.001) 3 2 7 6 + DEPOLARIZE1(0.001) 0 1 4 5 8 + TICK + CX 2 3 6 7 + DEPOLARIZE2(0.001) 2 3 6 7 + DEPOLARIZE1(0.001) 0 1 4 5 8 + TICK + CX 1 2 3 4 5 6 7 8 + DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 + DEPOLARIZE1(0.001) 0 + TICK + CX 1 0 6 2 8 4 + DEPOLARIZE2(0.001) 1 0 6 2 8 4 + DEPOLARIZE1(0.001) 3 5 7 + TICK + MX(0.001) 1 7 + M(0.001) 2 4 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 1 7 2 4 0 3 5 6 8 + TICK + RX 1 7 + R 2 4 + OBSERVABLE_INCLUDE(0) rec[-4] + X_ERROR(0.001) 2 4 + Z_ERROR(0.001) 1 7 + DEPOLARIZE1(0.001) 0 3 5 6 8 + TICK + CX 1 0 6 2 8 4 + DEPOLARIZE2(0.001) 1 0 6 2 8 4 + DEPOLARIZE1(0.001) 3 5 7 + TICK + CX 1 2 3 4 5 6 7 8 + DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 + DEPOLARIZE1(0.001) 0 + TICK + CX 2 3 6 7 + DETECTOR(1, 1, 0, 1) rec[-4] + DETECTOR(2, 3, 0, 2) rec[-3] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 2 3 6 7 + DEPOLARIZE1(0.001) 0 1 4 5 8 + TICK + CX 3 2 7 6 + DEPOLARIZE2(0.001) 3 2 7 6 + DEPOLARIZE1(0.001) 0 1 4 5 8 + TICK + CX 2 1 4 3 6 5 8 7 + DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 + DEPOLARIZE1(0.001) 0 + TICK + CX 0 1 2 6 4 8 + DEPOLARIZE2(0.001) 0 1 2 6 4 8 + DEPOLARIZE1(0.001) 3 5 7 + TICK + MX(0.001) 2 4 + M(0.001) 1 7 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 2 4 1 7 0 3 5 6 8 + TICK + RX 2 4 + R 1 7 + OBSERVABLE_INCLUDE(0) rec[-3] + X_ERROR(0.001) 1 7 + Z_ERROR(0.001) 2 4 + DEPOLARIZE1(0.001) 0 3 5 6 8 + TICK + CX 0 1 2 6 4 8 + DEPOLARIZE2(0.001) 0 1 2 6 4 8 + DEPOLARIZE1(0.001) 3 5 7 + TICK + CX 2 1 4 3 6 5 8 7 + DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 + DEPOLARIZE1(0.001) 0 + TICK + CX 3 2 7 6 + DETECTOR(1, 1, 0, 4) rec[-2] + DETECTOR(1, 2, 0, 2) rec[-8] rec[-7] rec[-4] + DETECTOR(1, 4, 0, 0) rec[-3] + DETECTOR(2, 3, 0, 5) rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 3 2 7 6 + DEPOLARIZE1(0.001) 0 1 4 5 8 + TICK + REPEAT 4 { + CX 2 3 6 7 + DEPOLARIZE2(0.001) 2 3 6 7 + DEPOLARIZE1(0.001) 0 1 4 5 8 + TICK + CX 1 2 3 4 5 6 7 8 + DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 + DEPOLARIZE1(0.001) 0 + TICK + CX 1 0 6 2 8 4 + DEPOLARIZE2(0.001) 1 0 6 2 8 4 + DEPOLARIZE1(0.001) 3 5 7 + TICK + MX(0.001) 1 7 + M(0.001) 2 4 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 1 7 2 4 0 3 5 6 8 + TICK + RX 1 7 + R 2 4 + OBSERVABLE_INCLUDE(0) rec[-4] + X_ERROR(0.001) 2 4 + Z_ERROR(0.001) 1 7 + DEPOLARIZE1(0.001) 0 3 5 6 8 + TICK + CX 1 0 6 2 8 4 + DEPOLARIZE2(0.001) 1 0 6 2 8 4 + DEPOLARIZE1(0.001) 3 5 7 + TICK + CX 1 2 3 4 5 6 7 8 + DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 + DEPOLARIZE1(0.001) 0 + TICK + CX 2 3 6 7 + DETECTOR(1, 1, 0, 1) rec[-4] + DETECTOR(1, 2, 0, 5) rec[-6] rec[-5] rec[-2] + DETECTOR(1, 4, 0, 3) rec[-1] + DETECTOR(2, 3, 0, 2) rec[-3] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 2 3 6 7 + DEPOLARIZE1(0.001) 0 1 4 5 8 + TICK + CX 3 2 7 6 + DEPOLARIZE2(0.001) 3 2 7 6 + DEPOLARIZE1(0.001) 0 1 4 5 8 + TICK + CX 2 1 4 3 6 5 8 7 + DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 + DEPOLARIZE1(0.001) 0 + TICK + CX 0 1 2 6 4 8 + DEPOLARIZE2(0.001) 0 1 2 6 4 8 + DEPOLARIZE1(0.001) 3 5 7 + TICK + MX(0.001) 2 4 + M(0.001) 1 7 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 2 4 1 7 0 3 5 6 8 + TICK + RX 2 4 + R 1 7 + OBSERVABLE_INCLUDE(0) rec[-3] + X_ERROR(0.001) 1 7 + Z_ERROR(0.001) 2 4 + DEPOLARIZE1(0.001) 0 3 5 6 8 + TICK + CX 0 1 2 6 4 8 + DEPOLARIZE2(0.001) 0 1 2 6 4 8 + DEPOLARIZE1(0.001) 3 5 7 + TICK + CX 2 1 4 3 6 5 8 7 + DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 + DEPOLARIZE1(0.001) 0 + TICK + CX 3 2 7 6 + DETECTOR(1, 1, 0, 4) rec[-2] + DETECTOR(1, 2, 0, 2) rec[-8] rec[-7] rec[-4] + DETECTOR(1, 4, 0, 0) rec[-3] + DETECTOR(2, 3, 0, 5) rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 3 2 7 6 + DEPOLARIZE1(0.001) 0 1 4 5 8 + TICK + } + CX 6 7 2 3 + DEPOLARIZE2(0.001) 6 7 2 3 + DEPOLARIZE1(0.001) 0 1 4 5 8 + TICK + CX 7 8 5 6 3 4 1 2 + DEPOLARIZE2(0.001) 7 8 5 6 3 4 1 2 + DEPOLARIZE1(0.001) 0 + TICK + CX 8 4 6 2 1 0 + DEPOLARIZE2(0.001) 8 4 6 2 1 0 + DEPOLARIZE1(0.001) 3 5 7 + TICK + M(0.001) 4 2 + MX(0.001) 8 6 5 3 0 7 1 + DETECTOR(1, 1, 0, 1) rec[-1] + DETECTOR(1, 2, 0, 2) rec[-7] rec[-5] rec[-4] rec[-3] rec[-2] rec[-1] + DETECTOR(1, 2, 0, 5) rec[-11] rec[-10] rec[-8] + DETECTOR(1, 4, 0, 0) rec[-7] rec[-6] + DETECTOR(1, 4, 0, 3) rec[-9] + DETECTOR(2, 3, 0, 2) rec[-2] + OBSERVABLE_INCLUDE(0) rec[-7] rec[-5] rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 4 2 8 6 5 3 0 7 1 + """ + ) diff --git a/src/clorco/color_code/_mxyz_color_codes.py b/src/clorco/color_code/_mxyz_color_codes.py new file mode 100644 index 0000000..fdb2770 --- /dev/null +++ b/src/clorco/color_code/_mxyz_color_codes.py @@ -0,0 +1,158 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Literal +from typing import cast + +import stim + +import gen +from clorco.color_code._superdense_planar_color_code_circuits import ( + make_color_code_layout_for_superdense, +) + + +def make_mxyz_phenom_color_code( + *, + base_width: int, + rounds: int, + noise: float | gen.NoiseRule, +) -> stim.Circuit: + """Creates a color code that cycles between measuring X, then Y, then Z stabilizers. + + (As opposed to alternating between X and Z, as is more common.) + + Uses a phenomomenological noise model. + + Args: + base_width: Base width of the triangular patch of the color code. + rounds: Number of times each shape is measured. An XYZ cycle is + three rounds. This differs from rounds in the usual phenom + circuit which measure both X and Z in one round. + noise: Noise to apply. If this is a float, then the float is both + the between-ronud depolarization strength and the + measurement flip probability. If this is a gen.NoiseRule then + its `after` is the between-round noise and its `flip_result` is + the measurement noise. + + Returns: + Stim circuit specifying the XYZ phenom color code. + """ + if isinstance(noise, (int, float)): + noise = gen.NoiseRule(after={"DEPOLARIZE1": noise}, flip_result=noise) + + code = make_color_code_layout_for_superdense( + base_data_width=base_width, + ) + ancilla = -1 - 1j + builder = gen.Builder.for_qubits(code.patch.data_set | {ancilla}) + + builder.measure_observables_and_include( + code.entangled_observables([ancilla])[0], + ) + builder.tick() + x_tiles = gen.Patch(tile for tile in code.patch.tiles if tile.basis == "X") + y_tiles = x_tiles.after_basis_transform(lambda _: cast(Literal["X", "Y", "Z"], "Y")) + z_tiles = x_tiles.after_basis_transform(lambda _: cast(Literal["X", "Y", "Z"], "Z")) + builder.measure_patch( + y_tiles, + save_layer=-2, + ) + builder.tick() + builder.measure_patch( + z_tiles, + save_layer=-1, + ) + builder.tick() + + round_index = 0 + + def append_round(out: gen.Builder, round_noise: bool) -> None: + nonlocal round_index + tiles = [x_tiles, y_tiles, z_tiles][round_index % 3] + if round_noise: + for k, p in noise.after.items(): + out.circuit.append( + k, [builder.q2i[q] for q in gen.sorted_complex(tiles.data_set)], p + ) + out.measure_patch( + tiles, + save_layer=round_index, + noise=noise.flip_result if round_noise else None, + ) + for tile in tiles.tiles: + rgb = int(tile.extra_coords[0]) % 3 + m = tile.measurement_qubit + out.detector( + [gen.AtLayer(m, round_index + offset) for offset in [-2, -1, 0]], + pos=m, + extra_coords=[(rgb + round_index) % 3], + ) + out.shift_coords(dt=1) + out.tick() + round_index += 1 + + loop = builder.fork() + append_round(loop, True) + append_round(loop, True) + append_round(loop, True) + builder.circuit += loop.circuit * (rounds // 3) + for _ in range(rounds % 3): + append_round(builder, True) + + append_round(builder, False) + append_round(builder, False) + builder.measure_observables_and_include( + code.entangled_observables([ancilla])[0], + ) + return builder.circuit + + +def make_mxyz_color_code_from_stim_gen( + *, + distance: int, + rounds: int, + noise: gen.NoiseModel | None, + convert_to_cz: bool, +) -> stim.Circuit: + """Tweaks stim's memory_xyz color code circuits. + + Overwrites the noise model. + + Adds Chromobius basis and color annotations to each detector. + """ + + circuit = stim.Circuit.generated( + code_task="color_code:memory_xyz", + distance=distance, + rounds=rounds, + ).flattened() + + colored_circuit = stim.Circuit() + for instruction in circuit: + if instruction.name == "DETECTOR": + x, y, t = instruction.gate_args_copy() + colored_circuit.append( + "DETECTOR", instruction.targets_copy(), [x, y, t, (y + t) % 3] + ) + else: + colored_circuit.append(instruction) + + if convert_to_cz: + colored_circuit = gen.transpile_to_z_basis_interaction_circuit(colored_circuit) + + if noise is not None: + colored_circuit = noise.noisy_circuit(colored_circuit) + + return colored_circuit diff --git a/src/clorco/color_code/_mxyz_color_codes_test.py b/src/clorco/color_code/_mxyz_color_codes_test.py new file mode 100644 index 0000000..d4224df --- /dev/null +++ b/src/clorco/color_code/_mxyz_color_codes_test.py @@ -0,0 +1,378 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools + +import pytest +import stim + +import gen +from clorco.color_code._mxyz_color_codes import make_mxyz_color_code_from_stim_gen +from clorco.color_code._mxyz_color_codes import make_mxyz_phenom_color_code + + +@pytest.mark.parametrize( + "d,r", + itertools.product( + [3, 5], + [2, 3, 4], + ), +) +def test_make_mxyz_phenom_color_code(d: int, r: int): + circuit = make_mxyz_phenom_color_code( + base_width=d, + rounds=r, + noise=1e-3, + ) + assert circuit.detector_error_model() is not None + err = circuit.search_for_undetectable_logical_errors( + dont_explore_edges_increasing_symptom_degree=False, + dont_explore_edges_with_degree_above=4, + dont_explore_detection_event_sets_with_size_above=4, + canonicalize_circuit_errors=True, + ) + assert len(err) == d + + +def test_make_mxyz_phenom_color_code_exact(): + circuit = make_mxyz_phenom_color_code( + base_width=3, + rounds=100, + noise=1e-3, + ) + assert circuit == stim.Circuit( + """ + QUBIT_COORDS(-1, -1) 0 + QUBIT_COORDS(0, 0) 1 + QUBIT_COORDS(1, 1) 2 + QUBIT_COORDS(2, 1) 3 + QUBIT_COORDS(2, 3) 4 + QUBIT_COORDS(3, 0) 5 + QUBIT_COORDS(3, 2) 6 + QUBIT_COORDS(4, 0) 7 + MPP X0*X1*X2*X3*X4*X5*X6*X7 + OBSERVABLE_INCLUDE(0) rec[-1] + MPP Z0*Z1*Z5*Z7 + OBSERVABLE_INCLUDE(1) rec[-1] + TICK + MPP Y1*Y2*Y3*Y5 Y2*Y3*Y4*Y6 Y3*Y5*Y6*Y7 + TICK + MPP Z1*Z2*Z3*Z5 Z2*Z3*Z4*Z6 Z3*Z5*Z6*Z7 + TICK + REPEAT 33 { + DEPOLARIZE1(0.001) 1 2 3 4 5 6 7 + MPP(0.001) X1*X2*X3*X5 X2*X3*X4*X6 X3*X5*X6*X7 + DETECTOR(1, 0, 0, 0) rec[-9] rec[-6] rec[-3] + DETECTOR(1, 2, 0, 2) rec[-8] rec[-5] rec[-2] + DETECTOR(3, 1, 0, 1) rec[-7] rec[-4] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + DEPOLARIZE1(0.001) 1 2 3 4 5 6 7 + MPP(0.001) Y1*Y2*Y3*Y5 Y2*Y3*Y4*Y6 Y3*Y5*Y6*Y7 + DETECTOR(1, 0, 0, 1) rec[-9] rec[-6] rec[-3] + DETECTOR(1, 2, 0, 0) rec[-8] rec[-5] rec[-2] + DETECTOR(3, 1, 0, 2) rec[-7] rec[-4] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + DEPOLARIZE1(0.001) 1 2 3 4 5 6 7 + MPP(0.001) Z1*Z2*Z3*Z5 Z2*Z3*Z4*Z6 Z3*Z5*Z6*Z7 + DETECTOR(1, 0, 0, 2) rec[-9] rec[-6] rec[-3] + DETECTOR(1, 2, 0, 1) rec[-8] rec[-5] rec[-2] + DETECTOR(3, 1, 0, 0) rec[-7] rec[-4] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + } + DEPOLARIZE1(0.001) 1 2 3 4 5 6 7 + MPP(0.001) X1*X2*X3*X5 X2*X3*X4*X6 X3*X5*X6*X7 + DETECTOR(1, 0, 0, 0) rec[-9] rec[-6] rec[-3] + DETECTOR(1, 2, 0, 2) rec[-8] rec[-5] rec[-2] + DETECTOR(3, 1, 0, 1) rec[-7] rec[-4] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + MPP Y1*Y2*Y3*Y5 Y2*Y3*Y4*Y6 Y3*Y5*Y6*Y7 + DETECTOR(1, 0, 0, 1) rec[-9] rec[-6] rec[-3] + DETECTOR(1, 2, 0, 0) rec[-8] rec[-5] rec[-2] + DETECTOR(3, 1, 0, 2) rec[-7] rec[-4] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + MPP Z1*Z2*Z3*Z5 Z2*Z3*Z4*Z6 Z3*Z5*Z6*Z7 + DETECTOR(1, 0, 0, 2) rec[-9] rec[-6] rec[-3] + DETECTOR(1, 2, 0, 1) rec[-8] rec[-5] rec[-2] + DETECTOR(3, 1, 0, 0) rec[-7] rec[-4] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + MPP X0*X1*X2*X3*X4*X5*X6*X7 + OBSERVABLE_INCLUDE(0) rec[-1] + MPP Z0*Z1*Z5*Z7 + OBSERVABLE_INCLUDE(1) rec[-1] + """ + ) + + +def test_make_mxyz_color_code_from_stim_gen(): + circuit = make_mxyz_color_code_from_stim_gen( + distance=5, + rounds=5, + noise=gen.NoiseModel.uniform_depolarizing(1e-3), + convert_to_cz=False, + ) + assert ( + circuit.num_detectors + circuit.num_observables + == circuit.count_determined_measurements() + ) + assert circuit.detector_error_model() is not None + err = circuit.search_for_undetectable_logical_errors( + dont_explore_edges_increasing_symptom_degree=False, + dont_explore_edges_with_degree_above=4, + dont_explore_detection_event_sets_with_size_above=4, + canonicalize_circuit_errors=True, + ) + assert len(err) == 3 + + assert circuit == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + QUBIT_COORDS(1, 0) 1 + QUBIT_COORDS(2, 0) 2 + QUBIT_COORDS(3, 0) 3 + QUBIT_COORDS(4, 0) 4 + QUBIT_COORDS(5, 0) 5 + QUBIT_COORDS(6, 0) 6 + QUBIT_COORDS(0.5, 1) 7 + QUBIT_COORDS(1.5, 1) 8 + QUBIT_COORDS(2.5, 1) 9 + QUBIT_COORDS(3.5, 1) 10 + QUBIT_COORDS(4.5, 1) 11 + QUBIT_COORDS(5.5, 1) 12 + QUBIT_COORDS(1, 2) 13 + QUBIT_COORDS(2, 2) 14 + QUBIT_COORDS(3, 2) 15 + QUBIT_COORDS(4, 2) 16 + QUBIT_COORDS(5, 2) 17 + QUBIT_COORDS(1.5, 3) 18 + QUBIT_COORDS(2.5, 3) 19 + QUBIT_COORDS(3.5, 3) 20 + QUBIT_COORDS(4.5, 3) 21 + QUBIT_COORDS(2, 4) 22 + QUBIT_COORDS(3, 4) 23 + QUBIT_COORDS(4, 4) 24 + QUBIT_COORDS(2.5, 5) 25 + QUBIT_COORDS(3.5, 5) 26 + QUBIT_COORDS(3, 6) 27 + 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 + X_ERROR(0.001) 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 + TICK + C_XYZ 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 2 5 7 10 14 17 20 22 26 + TICK + CX 8 7 3 2 15 14 23 22 11 10 21 20 6 5 + DEPOLARIZE2(0.001) 8 7 3 2 15 14 23 22 11 10 21 20 6 5 + DEPOLARIZE1(0.001) 0 1 4 9 12 13 16 17 18 19 24 25 26 27 + TICK + CX 13 7 9 2 19 14 25 22 16 10 24 20 12 5 + DEPOLARIZE2(0.001) 13 7 9 2 19 14 25 22 16 10 24 20 12 5 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 11 15 17 18 21 23 26 27 + TICK + CX 1 7 9 14 19 22 4 10 16 20 24 26 12 17 + DEPOLARIZE2(0.001) 1 7 9 14 19 22 4 10 16 20 24 26 12 17 + DEPOLARIZE1(0.001) 0 2 3 5 6 8 11 13 15 18 21 23 25 27 + TICK + CX 1 2 13 14 9 10 19 20 25 26 4 5 16 17 + DEPOLARIZE2(0.001) 1 2 13 14 9 10 19 20 25 26 4 5 16 17 + DEPOLARIZE1(0.001) 0 3 6 7 8 11 12 15 18 21 22 23 24 27 + TICK + CX 8 2 18 14 15 10 23 20 27 26 11 5 21 17 + DEPOLARIZE2(0.001) 8 2 18 14 15 10 23 20 27 26 11 5 21 17 + DEPOLARIZE1(0.001) 0 1 3 4 6 7 9 12 13 16 19 22 24 25 + TICK + CX 0 7 8 14 18 22 3 10 15 20 23 26 11 17 + DEPOLARIZE2(0.001) 0 7 8 14 18 22 3 10 15 20 23 26 11 17 + DEPOLARIZE1(0.001) 1 2 4 5 6 9 12 13 16 19 21 24 25 27 + TICK + MR(0.001) 2 5 7 10 14 17 20 22 26 + X_ERROR(0.001) 2 5 7 10 14 17 20 22 26 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 + TICK + C_XYZ 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 2 5 7 10 14 17 20 22 26 + TICK + CX 8 7 3 2 15 14 23 22 11 10 21 20 6 5 + DEPOLARIZE2(0.001) 8 7 3 2 15 14 23 22 11 10 21 20 6 5 + DEPOLARIZE1(0.001) 0 1 4 9 12 13 16 17 18 19 24 25 26 27 + TICK + CX 13 7 9 2 19 14 25 22 16 10 24 20 12 5 + DEPOLARIZE2(0.001) 13 7 9 2 19 14 25 22 16 10 24 20 12 5 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 11 15 17 18 21 23 26 27 + TICK + CX 1 7 9 14 19 22 4 10 16 20 24 26 12 17 + DEPOLARIZE2(0.001) 1 7 9 14 19 22 4 10 16 20 24 26 12 17 + DEPOLARIZE1(0.001) 0 2 3 5 6 8 11 13 15 18 21 23 25 27 + TICK + CX 1 2 13 14 9 10 19 20 25 26 4 5 16 17 + DEPOLARIZE2(0.001) 1 2 13 14 9 10 19 20 25 26 4 5 16 17 + DEPOLARIZE1(0.001) 0 3 6 7 8 11 12 15 18 21 22 23 24 27 + TICK + CX 8 2 18 14 15 10 23 20 27 26 11 5 21 17 + DEPOLARIZE2(0.001) 8 2 18 14 15 10 23 20 27 26 11 5 21 17 + DEPOLARIZE1(0.001) 0 1 3 4 6 7 9 12 13 16 19 22 24 25 + TICK + CX 0 7 8 14 18 22 3 10 15 20 23 26 11 17 + DEPOLARIZE2(0.001) 0 7 8 14 18 22 3 10 15 20 23 26 11 17 + DEPOLARIZE1(0.001) 1 2 4 5 6 9 12 13 16 19 21 24 25 27 + TICK + MR(0.001) 2 5 7 10 14 17 20 22 26 + DETECTOR(2, 0, 0, 0) rec[-9] rec[-18] + DETECTOR(5, 0, 0, 0) rec[-8] rec[-17] + DETECTOR(0.5, 1, 0, 1) rec[-7] rec[-16] + DETECTOR(3.5, 1, 0, 1) rec[-6] rec[-15] + DETECTOR(2, 2, 0, 2) rec[-5] rec[-14] + DETECTOR(5, 2, 0, 2) rec[-4] rec[-13] + DETECTOR(3.5, 3, 0, 0) rec[-3] rec[-12] + DETECTOR(2, 4, 0, 1) rec[-2] rec[-11] + DETECTOR(3.5, 5, 0, 2) rec[-1] rec[-10] + X_ERROR(0.001) 2 5 7 10 14 17 20 22 26 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 + TICK + C_XYZ 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 2 5 7 10 14 17 20 22 26 + TICK + CX 8 7 3 2 15 14 23 22 11 10 21 20 6 5 + DEPOLARIZE2(0.001) 8 7 3 2 15 14 23 22 11 10 21 20 6 5 + DEPOLARIZE1(0.001) 0 1 4 9 12 13 16 17 18 19 24 25 26 27 + TICK + CX 13 7 9 2 19 14 25 22 16 10 24 20 12 5 + DEPOLARIZE2(0.001) 13 7 9 2 19 14 25 22 16 10 24 20 12 5 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 11 15 17 18 21 23 26 27 + TICK + CX 1 7 9 14 19 22 4 10 16 20 24 26 12 17 + DEPOLARIZE2(0.001) 1 7 9 14 19 22 4 10 16 20 24 26 12 17 + DEPOLARIZE1(0.001) 0 2 3 5 6 8 11 13 15 18 21 23 25 27 + TICK + CX 1 2 13 14 9 10 19 20 25 26 4 5 16 17 + DEPOLARIZE2(0.001) 1 2 13 14 9 10 19 20 25 26 4 5 16 17 + DEPOLARIZE1(0.001) 0 3 6 7 8 11 12 15 18 21 22 23 24 27 + TICK + CX 8 2 18 14 15 10 23 20 27 26 11 5 21 17 + DEPOLARIZE2(0.001) 8 2 18 14 15 10 23 20 27 26 11 5 21 17 + DEPOLARIZE1(0.001) 0 1 3 4 6 7 9 12 13 16 19 22 24 25 + TICK + CX 0 7 8 14 18 22 3 10 15 20 23 26 11 17 + DEPOLARIZE2(0.001) 0 7 8 14 18 22 3 10 15 20 23 26 11 17 + DEPOLARIZE1(0.001) 1 2 4 5 6 9 12 13 16 19 21 24 25 27 + TICK + MR(0.001) 2 5 7 10 14 17 20 22 26 + DETECTOR(2, 0, 1, 1) rec[-9] rec[-18] rec[-27] + DETECTOR(5, 0, 1, 1) rec[-8] rec[-17] rec[-26] + DETECTOR(0.5, 1, 1, 2) rec[-7] rec[-16] rec[-25] + DETECTOR(3.5, 1, 1, 2) rec[-6] rec[-15] rec[-24] + DETECTOR(2, 2, 1, 0) rec[-5] rec[-14] rec[-23] + DETECTOR(5, 2, 1, 0) rec[-4] rec[-13] rec[-22] + DETECTOR(3.5, 3, 1, 1) rec[-3] rec[-12] rec[-21] + DETECTOR(2, 4, 1, 2) rec[-2] rec[-11] rec[-20] + DETECTOR(3.5, 5, 1, 0) rec[-1] rec[-10] rec[-19] + X_ERROR(0.001) 2 5 7 10 14 17 20 22 26 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 + TICK + C_XYZ 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 2 5 7 10 14 17 20 22 26 + TICK + CX 8 7 3 2 15 14 23 22 11 10 21 20 6 5 + DEPOLARIZE2(0.001) 8 7 3 2 15 14 23 22 11 10 21 20 6 5 + DEPOLARIZE1(0.001) 0 1 4 9 12 13 16 17 18 19 24 25 26 27 + TICK + CX 13 7 9 2 19 14 25 22 16 10 24 20 12 5 + DEPOLARIZE2(0.001) 13 7 9 2 19 14 25 22 16 10 24 20 12 5 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 11 15 17 18 21 23 26 27 + TICK + CX 1 7 9 14 19 22 4 10 16 20 24 26 12 17 + DEPOLARIZE2(0.001) 1 7 9 14 19 22 4 10 16 20 24 26 12 17 + DEPOLARIZE1(0.001) 0 2 3 5 6 8 11 13 15 18 21 23 25 27 + TICK + CX 1 2 13 14 9 10 19 20 25 26 4 5 16 17 + DEPOLARIZE2(0.001) 1 2 13 14 9 10 19 20 25 26 4 5 16 17 + DEPOLARIZE1(0.001) 0 3 6 7 8 11 12 15 18 21 22 23 24 27 + TICK + CX 8 2 18 14 15 10 23 20 27 26 11 5 21 17 + DEPOLARIZE2(0.001) 8 2 18 14 15 10 23 20 27 26 11 5 21 17 + DEPOLARIZE1(0.001) 0 1 3 4 6 7 9 12 13 16 19 22 24 25 + TICK + CX 0 7 8 14 18 22 3 10 15 20 23 26 11 17 + DEPOLARIZE2(0.001) 0 7 8 14 18 22 3 10 15 20 23 26 11 17 + DEPOLARIZE1(0.001) 1 2 4 5 6 9 12 13 16 19 21 24 25 27 + TICK + MR(0.001) 2 5 7 10 14 17 20 22 26 + DETECTOR(2, 0, 2, 2) rec[-9] rec[-18] rec[-27] + DETECTOR(5, 0, 2, 2) rec[-8] rec[-17] rec[-26] + DETECTOR(0.5, 1, 2, 0) rec[-7] rec[-16] rec[-25] + DETECTOR(3.5, 1, 2, 0) rec[-6] rec[-15] rec[-24] + DETECTOR(2, 2, 2, 1) rec[-5] rec[-14] rec[-23] + DETECTOR(5, 2, 2, 1) rec[-4] rec[-13] rec[-22] + DETECTOR(3.5, 3, 2, 2) rec[-3] rec[-12] rec[-21] + DETECTOR(2, 4, 2, 0) rec[-2] rec[-11] rec[-20] + DETECTOR(3.5, 5, 2, 1) rec[-1] rec[-10] rec[-19] + X_ERROR(0.001) 2 5 7 10 14 17 20 22 26 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 + TICK + C_XYZ 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 2 5 7 10 14 17 20 22 26 + TICK + CX 8 7 3 2 15 14 23 22 11 10 21 20 6 5 + DEPOLARIZE2(0.001) 8 7 3 2 15 14 23 22 11 10 21 20 6 5 + DEPOLARIZE1(0.001) 0 1 4 9 12 13 16 17 18 19 24 25 26 27 + TICK + CX 13 7 9 2 19 14 25 22 16 10 24 20 12 5 + DEPOLARIZE2(0.001) 13 7 9 2 19 14 25 22 16 10 24 20 12 5 + DEPOLARIZE1(0.001) 0 1 3 4 6 8 11 15 17 18 21 23 26 27 + TICK + CX 1 7 9 14 19 22 4 10 16 20 24 26 12 17 + DEPOLARIZE2(0.001) 1 7 9 14 19 22 4 10 16 20 24 26 12 17 + DEPOLARIZE1(0.001) 0 2 3 5 6 8 11 13 15 18 21 23 25 27 + TICK + CX 1 2 13 14 9 10 19 20 25 26 4 5 16 17 + DEPOLARIZE2(0.001) 1 2 13 14 9 10 19 20 25 26 4 5 16 17 + DEPOLARIZE1(0.001) 0 3 6 7 8 11 12 15 18 21 22 23 24 27 + TICK + CX 8 2 18 14 15 10 23 20 27 26 11 5 21 17 + DEPOLARIZE2(0.001) 8 2 18 14 15 10 23 20 27 26 11 5 21 17 + DEPOLARIZE1(0.001) 0 1 3 4 6 7 9 12 13 16 19 22 24 25 + TICK + CX 0 7 8 14 18 22 3 10 15 20 23 26 11 17 + DEPOLARIZE2(0.001) 0 7 8 14 18 22 3 10 15 20 23 26 11 17 + DEPOLARIZE1(0.001) 1 2 4 5 6 9 12 13 16 19 21 24 25 27 + TICK + MR(0.001) 2 5 7 10 14 17 20 22 26 + DETECTOR(2, 0, 3, 0) rec[-9] rec[-18] rec[-27] + DETECTOR(5, 0, 3, 0) rec[-8] rec[-17] rec[-26] + DETECTOR(0.5, 1, 3, 1) rec[-7] rec[-16] rec[-25] + DETECTOR(3.5, 1, 3, 1) rec[-6] rec[-15] rec[-24] + DETECTOR(2, 2, 3, 2) rec[-5] rec[-14] rec[-23] + DETECTOR(5, 2, 3, 2) rec[-4] rec[-13] rec[-22] + DETECTOR(3.5, 3, 3, 0) rec[-3] rec[-12] rec[-21] + DETECTOR(2, 4, 3, 1) rec[-2] rec[-11] rec[-20] + DETECTOR(3.5, 5, 3, 2) rec[-1] rec[-10] rec[-19] + MY(0.001) 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 + DETECTOR(2, 0, 4, 1) rec[-13] rec[-14] rec[-17] rec[-18] rec[-28] rec[-37] + DETECTOR(5, 0, 4, 1) rec[-11] rec[-12] rec[-15] rec[-16] rec[-27] rec[-36] + DETECTOR(0.5, 1, 4, 2) rec[-10] rec[-14] rec[-18] rec[-19] rec[-26] rec[-35] + DETECTOR(3.5, 1, 4, 2) rec[-8] rec[-9] rec[-12] rec[-13] rec[-16] rec[-17] rec[-25] rec[-34] + DETECTOR(2, 2, 4, 0) rec[-6] rec[-7] rec[-9] rec[-10] rec[-13] rec[-14] rec[-24] rec[-33] + DETECTOR(5, 2, 4, 0) rec[-5] rec[-8] rec[-11] rec[-12] rec[-23] rec[-32] + DETECTOR(3.5, 3, 4, 1) rec[-3] rec[-4] rec[-5] rec[-6] rec[-8] rec[-9] rec[-22] rec[-31] + DETECTOR(2, 4, 4, 2) rec[-2] rec[-4] rec[-6] rec[-7] rec[-21] rec[-30] + DETECTOR(3.5, 5, 4, 0) rec[-1] rec[-2] rec[-3] rec[-4] rec[-20] rec[-29] + OBSERVABLE_INCLUDE(0) rec[-15] rec[-16] rec[-17] rec[-18] rec[-19] + DEPOLARIZE1(0.001) 0 1 3 4 6 8 9 11 12 13 15 16 18 19 21 23 24 25 27 + X_ERROR(0.001) 2 5 7 10 14 17 20 22 26 + """ + ) diff --git a/src/clorco/color_code/_superdense_planar_color_code_circuits.py b/src/clorco/color_code/_superdense_planar_color_code_circuits.py new file mode 100644 index 0000000..4e116d4 --- /dev/null +++ b/src/clorco/color_code/_superdense_planar_color_code_circuits.py @@ -0,0 +1,271 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Callable +from typing import Iterable +from typing import Literal + +import stim + +import gen + + +def make_color_code_layout_for_superdense( + *, + base_data_width: int, + single_rgb_layer_instead_of_actual_code: bool | Literal['double_measure_qubit'] = False, +) -> gen.StabilizerCode: + assert base_data_width > 2 and base_data_width % 2 == 1 + base_width = base_data_width * 2 - 1 + + tiles = [] + for x in range(-1, base_width, 2): + for y in range((x // 2) % 2, base_width, 2): + q = x + 1j * y + order = [-1, +1j, +1j + 1, +2, -1j + 1, -1j] + rgb = y % 3 + bases = "XYZ"[rgb] if single_rgb_layer_instead_of_actual_code else "XZ" + if single_rgb_layer_instead_of_actual_code == 'double_measure_qubit': + bases *= 2 + for k in range(len(bases)): + tiles.append( + gen.Tile( + bases=bases[k], + measurement_qubit=q + k, + ordered_data_qubits=[q + d for d in order], + extra_coords=[rgb + k * 3], + ) + ) + + def is_in_bounds(q: complex) -> bool: + if q.real < 0 or q.imag < 0 or q.real >= base_width or q.imag >= base_width: + return False + if q.imag * 2 > q.real * 3: + return False + if q.imag * 2 > (base_width - q.real) * 3: + return False + return True + + filtered_tiles = [] + for tile in tiles: + new_tile = gen.Tile( + bases=tile.bases, + measurement_qubit=tile.measurement_qubit, + ordered_data_qubits=[ + (q if is_in_bounds(q) else None) for q in tile.ordered_data_qubits + ], + extra_coords=tile.extra_coords, + ) + if len(new_tile.data_set) >= 4: + filtered_tiles.append(new_tile) + + patch = gen.Patch(filtered_tiles) + obs_x = gen.PauliString({q: "X" for q in patch.data_set}) + obs_z = gen.PauliString({q: "Z" for q in patch.data_set if q.imag == 0}) + + result = gen.StabilizerCode( + patch=patch, + observables_x=[obs_x], + observables_z=[obs_z], + ) + + return result + + +def make_superdense_color_code_circuit_round_chunk( + *, + initialize: bool, + basis: Literal["X", "Z"], + base_data_width: int, +) -> gen.Chunk: + code = make_color_code_layout_for_superdense( + base_data_width=base_data_width, + ) + + builder = gen.Builder.for_qubits(code.patch.used_set) + x_ms = [tile.measurement_qubit for tile in code.patch.tiles if tile.basis == "X"] + z_ms = [tile.measurement_qubit for tile in code.patch.tiles if tile.basis == "Z"] + + def do_cxs( + centers: Iterable[complex], + d_control: complex, + d_target: complex, + inv: Callable[[complex], bool] = lambda _: False, + ) -> None: + builder.gate2( + "CX", + [ + (c + d_control, c + d_target)[:: -1 if inv(c) else +1] + for c in centers + if c + d_control in code.patch.used_set + if c + d_target in code.patch.used_set + ], + ) + + builder.gate("RX", x_ms) + if initialize: + builder.gate(f"R{basis}", code.patch.data_set) + builder.gate("RZ", z_ms) + builder.tick() + + do_cxs(x_ms, +0, +1) + builder.tick() + do_cxs(x_ms, +1j, +0) + do_cxs(z_ms, +1j, +0) + builder.tick() + do_cxs(x_ms, -1, +0) + do_cxs(z_ms, +1, +0) + builder.tick() + do_cxs(x_ms, -1j, +0) + do_cxs(z_ms, -1j, +0) + builder.tick() + do_cxs(x_ms, +0, +1j) + do_cxs(z_ms, +0, +1j) + builder.tick() + do_cxs(x_ms, +0, -1) + do_cxs(z_ms, +0, +1) + builder.tick() + do_cxs(x_ms, +0, -1j) + do_cxs(z_ms, +0, -1j) + builder.tick() + do_cxs(x_ms, +0, +1) + builder.tick() + + builder.measure(x_ms, basis="X", save_layer="solo") + builder.measure(z_ms, basis="Z", save_layer="solo") + + def mf(*qs): + return builder.tracker.measurement_indices( + [gen.AtLayer(q, "solo") for q in qs if q in code.patch.measure_set] + ) + + flows = [] + for tile in code.patch.tiles: + m = tile.measurement_qubit + if tile.basis == "X": + if not initialize: + flows.append( + gen.Flow( + start=tile.to_data_pauli_string(), + measurement_indices=mf(m), + center=m, + additional_coords=tile.extra_coords, + ) + ) + elif basis == "X": + flows.append( + gen.Flow( + measurement_indices=mf(m), + center=m, + additional_coords=tile.extra_coords, + ) + ) + flows.append( + gen.Flow( + end=tile.to_data_pauli_string(), + measurement_indices=mf(m), + center=m, + additional_coords=tile.extra_coords, + ) + ) + elif tile.basis == "Z": + if not initialize: + flows.append( + gen.Flow( + start=tile.to_data_pauli_string(), + measurement_indices=mf(m), + center=m, + additional_coords=tile.extra_coords, + ) + ) + elif basis == "Z": + flows.append( + gen.Flow( + measurement_indices=mf(m), + center=m, + additional_coords=tile.extra_coords, + ) + ) + flows.append( + gen.Flow( + end=tile.to_data_pauli_string(), + measurement_indices=mf(m - 2j if m.imag > 0 else m, m + 2j), + center=m, + additional_coords=tile.extra_coords, + ) + ) + + (obs_x,) = code.observables_x + (obs_z,) = code.observables_z + if basis == "X": + flows.append( + gen.Flow( + start=None if initialize else obs_x, + end=obs_x, + measurement_indices=[], + center=-1 - 1j, + obs_index=0, + ) + ) + elif basis == "Z": + flows.append( + gen.Flow( + start=None if initialize else obs_z, + end=obs_z, + measurement_indices=mf( + *[ + tile.measurement_qubit + for tile in code.patch.tiles + if tile.basis == "Z" and tile.measurement_qubit.imag <= 1 + ] + ), + center=-1 - 1j, + obs_index=0, + ) + ) + + return gen.Chunk( + circuit=builder.circuit, + flows=flows, + q2i=builder.q2i, + ) + + +def make_superdense_color_code_circuit( + *, + base_data_width: int, + basis: Literal["X", "Z"], + rounds: int, +) -> stim.Circuit: + assert rounds >= 2 + + first_round = make_superdense_color_code_circuit_round_chunk( + initialize=True, + basis=basis, + base_data_width=base_data_width, + ) + mid_round = make_superdense_color_code_circuit_round_chunk( + initialize=False, + basis=basis, + base_data_width=base_data_width, + ) + end_round = first_round.inverted() + + return gen.compile_chunks_into_circuit( + [ + first_round, + gen.ChunkLoop([mid_round], repetitions=rounds - 2), + end_round, + ] + ) diff --git a/src/clorco/color_code/_superdense_planar_color_code_circuits_test.py b/src/clorco/color_code/_superdense_planar_color_code_circuits_test.py new file mode 100644 index 0000000..17e2484 --- /dev/null +++ b/src/clorco/color_code/_superdense_planar_color_code_circuits_test.py @@ -0,0 +1,251 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools +from typing import Any + +import pytest +import stim + +import gen +from clorco.color_code._superdense_planar_color_code_circuits import ( + make_superdense_color_code_circuit, +) +from clorco.color_code._superdense_planar_color_code_circuits import ( + make_superdense_color_code_circuit_round_chunk, +) + + +@pytest.mark.parametrize( + "d,b,i", + itertools.product( + [3, 5, 7], + ["X", "Z"], + [False, True], + ), +) +def test_make_superdense_color_code_circuit_round_chunk(d: int, b: Any, i: bool): + chunk = make_superdense_color_code_circuit_round_chunk( + base_data_width=d, + initialize=i, + basis=b, + ) + chunk.verify() + if d == 5: + if i: + assert len(chunk.flows) == 3 * 9 + 1 + else: + assert len(chunk.flows) == 4 * 9 + 1 + + +@pytest.mark.parametrize( + "d,b,r", + itertools.product( + [3, 5], + ["X", "Z"], + [2, 3, 5], + ), +) +def test_make_superdense_color_code_circuit(d: int, b: Any, r: int): + circuit = make_superdense_color_code_circuit( + base_data_width=d, + basis=b, + rounds=r, + ) + circuit = gen.NoiseModel.uniform_depolarizing(1e-3).noisy_circuit(circuit) + assert ( + len( + circuit.search_for_undetectable_logical_errors( + dont_explore_detection_event_sets_with_size_above=4, + dont_explore_edges_with_degree_above=3, + dont_explore_edges_increasing_symptom_degree=False, + ) + ) + == d + ) + + +def test_make_superdense_color_code_circuit_exact(): + circuit = make_superdense_color_code_circuit( + base_data_width=5, + basis="X", + rounds=100, + ) + assert circuit == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + QUBIT_COORDS(1, 0) 1 + QUBIT_COORDS(1, 1) 2 + QUBIT_COORDS(1, 2) 3 + QUBIT_COORDS(2, 0) 4 + QUBIT_COORDS(2, 1) 5 + QUBIT_COORDS(2, 2) 6 + QUBIT_COORDS(2, 3) 7 + QUBIT_COORDS(3, 0) 8 + QUBIT_COORDS(3, 1) 9 + QUBIT_COORDS(3, 2) 10 + QUBIT_COORDS(3, 3) 11 + QUBIT_COORDS(3, 4) 12 + QUBIT_COORDS(3, 5) 13 + QUBIT_COORDS(4, 0) 14 + QUBIT_COORDS(4, 1) 15 + QUBIT_COORDS(4, 2) 16 + QUBIT_COORDS(4, 3) 17 + QUBIT_COORDS(4, 4) 18 + QUBIT_COORDS(4, 5) 19 + QUBIT_COORDS(4, 6) 20 + QUBIT_COORDS(5, 0) 21 + QUBIT_COORDS(5, 1) 22 + QUBIT_COORDS(5, 2) 23 + QUBIT_COORDS(5, 3) 24 + QUBIT_COORDS(5, 4) 25 + QUBIT_COORDS(5, 5) 26 + QUBIT_COORDS(6, 0) 27 + QUBIT_COORDS(6, 1) 28 + QUBIT_COORDS(6, 2) 29 + QUBIT_COORDS(6, 3) 30 + QUBIT_COORDS(6, 4) 31 + QUBIT_COORDS(7, 0) 32 + QUBIT_COORDS(7, 1) 33 + QUBIT_COORDS(7, 2) 34 + QUBIT_COORDS(8, 0) 35 + QUBIT_COORDS(8, 1) 36 + RX 1 3 9 11 13 21 23 25 33 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 + R 4 6 15 17 19 27 29 31 36 + TICK + CX 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 + TICK + CX 2 1 10 9 12 11 22 21 24 23 26 25 34 33 5 4 7 6 16 15 18 17 20 19 28 27 30 29 + TICK + CX 0 1 5 9 7 11 14 21 16 23 18 25 28 33 8 4 10 6 22 15 24 17 26 19 32 27 34 29 + TICK + CX 2 3 8 9 10 11 12 13 22 23 24 25 32 33 5 6 14 15 16 17 18 19 28 29 30 31 35 36 + TICK + CX 1 2 9 10 11 12 21 22 23 24 25 26 33 34 4 5 6 7 15 16 17 18 19 20 27 28 29 30 + TICK + CX 1 0 9 5 11 7 21 14 23 16 25 18 33 28 4 8 6 10 15 22 17 24 19 26 27 32 29 34 + TICK + CX 3 2 9 8 11 10 13 12 23 22 25 24 33 32 6 5 15 14 17 16 19 18 29 28 31 30 36 35 + TICK + CX 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 + TICK + MX 1 3 9 11 13 21 23 25 33 + M 4 6 15 17 19 27 29 31 36 + DETECTOR(1, 0, 0, 0) rec[-18] + DETECTOR(1, 2, 0, 2) rec[-17] + DETECTOR(3, 1, 0, 1) rec[-16] + DETECTOR(3, 3, 0, 0) rec[-15] + DETECTOR(3, 5, 0, 2) rec[-14] + DETECTOR(5, 0, 0, 0) rec[-13] + DETECTOR(5, 2, 0, 2) rec[-12] + DETECTOR(5, 4, 0, 1) rec[-11] + DETECTOR(7, 1, 0, 1) rec[-10] + SHIFT_COORDS(0, 0, 1) + TICK + REPEAT 98 { + RX 1 3 9 11 13 21 23 25 33 + R 4 6 15 17 19 27 29 31 36 + TICK + CX 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 + TICK + CX 2 1 10 9 12 11 22 21 24 23 26 25 34 33 5 4 7 6 16 15 18 17 20 19 28 27 30 29 + TICK + CX 0 1 5 9 7 11 14 21 16 23 18 25 28 33 8 4 10 6 22 15 24 17 26 19 32 27 34 29 + TICK + CX 2 3 8 9 10 11 12 13 22 23 24 25 32 33 5 6 14 15 16 17 18 19 28 29 30 31 35 36 + TICK + CX 1 2 9 10 11 12 21 22 23 24 25 26 33 34 4 5 6 7 15 16 17 18 19 20 27 28 29 30 + TICK + CX 1 0 9 5 11 7 21 14 23 16 25 18 33 28 4 8 6 10 15 22 17 24 19 26 27 32 29 34 + TICK + CX 3 2 9 8 11 10 13 12 23 22 25 24 33 32 6 5 15 14 17 16 19 18 29 28 31 30 36 35 + TICK + CX 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 + TICK + MX 1 3 9 11 13 21 23 25 33 + M 4 6 15 17 19 27 29 31 36 + DETECTOR(1, 0, 0, 0) rec[-36] rec[-18] + DETECTOR(1, 2, 0, 2) rec[-35] rec[-17] + DETECTOR(2, 0, 0, 3) rec[-27] rec[-26] rec[-9] + DETECTOR(2, 2, 0, 5) rec[-27] rec[-8] + DETECTOR(3, 1, 0, 1) rec[-34] rec[-16] + DETECTOR(3, 3, 0, 0) rec[-33] rec[-15] + DETECTOR(3, 5, 0, 2) rec[-32] rec[-14] + DETECTOR(4, 1, 0, 4) rec[-24] rec[-7] + DETECTOR(4, 3, 0, 3) rec[-25] rec[-23] rec[-6] + DETECTOR(4, 5, 0, 5) rec[-24] rec[-5] + DETECTOR(5, 0, 0, 0) rec[-31] rec[-13] + DETECTOR(5, 2, 0, 2) rec[-30] rec[-12] + DETECTOR(5, 4, 0, 1) rec[-29] rec[-11] + DETECTOR(6, 0, 0, 3) rec[-22] rec[-21] rec[-4] + DETECTOR(6, 2, 0, 5) rec[-22] rec[-20] rec[-3] + DETECTOR(6, 4, 0, 4) rec[-21] rec[-2] + DETECTOR(7, 1, 0, 1) rec[-28] rec[-10] + DETECTOR(8, 1, 0, 4) rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + } + R 36 31 29 27 19 17 15 6 4 + RX 33 25 23 21 13 11 9 3 1 + TICK + CX 33 36 25 31 23 29 21 27 13 19 11 17 9 15 3 6 1 4 + TICK + CX 36 35 31 30 29 28 19 18 17 16 15 14 6 5 33 32 25 24 23 22 13 12 11 10 9 8 3 2 + TICK + CX 29 34 27 32 19 26 17 24 15 22 6 10 4 8 33 28 25 18 23 16 21 14 11 7 9 5 1 0 + TICK + CX 29 30 27 28 19 20 17 18 15 16 6 7 4 5 33 34 25 26 23 24 21 22 11 12 9 10 1 2 + TICK + CX 35 36 30 31 28 29 18 19 16 17 14 15 5 6 32 33 24 25 22 23 12 13 10 11 8 9 2 3 + TICK + CX 34 29 32 27 26 19 24 17 22 15 10 6 8 4 28 33 18 25 16 23 14 21 7 11 5 9 0 1 + TICK + CX 30 29 28 27 20 19 18 17 16 15 7 6 5 4 34 33 26 25 24 23 22 21 12 11 10 9 2 1 + TICK + CX 33 36 25 31 23 29 21 27 13 19 11 17 9 15 3 6 1 4 + TICK + M 36 31 29 27 19 17 15 6 4 + MX 35 34 32 30 28 26 24 22 20 18 16 14 12 10 8 7 5 2 0 33 25 23 21 13 11 9 3 1 + DETECTOR(1, 0, 0, 0) rec[-14] rec[-12] rec[-11] rec[-10] rec[-2] rec[-1] + DETECTOR(1, 0, 0, 0) rec[-55] rec[-1] + DETECTOR(1, 2, 0, 2) rec[-15] rec[-13] rec[-12] rec[-11] rec[-1] + DETECTOR(1, 2, 0, 2) rec[-54] rec[-2] + DETECTOR(2, 0, 0, 3) rec[-46] rec[-45] rec[-29] + DETECTOR(2, 2, 0, 5) rec[-46] rec[-30] + DETECTOR(3, 1, 0, 1) rec[-21] rec[-18] rec[-17] rec[-15] rec[-14] rec[-12] rec[-4] + DETECTOR(3, 1, 0, 1) rec[-53] rec[-3] + DETECTOR(3, 3, 0, 0) rec[-22] rec[-19] rec[-18] rec[-16] rec[-15] rec[-13] rec[-5] rec[-3] + DETECTOR(3, 3, 0, 0) rec[-52] rec[-4] + DETECTOR(3, 5, 0, 2) rec[-23] rec[-20] rec[-19] rec[-16] rec[-4] + DETECTOR(3, 5, 0, 2) rec[-51] rec[-5] + DETECTOR(4, 1, 0, 4) rec[-43] rec[-31] + DETECTOR(4, 3, 0, 3) rec[-44] rec[-42] rec[-32] + DETECTOR(4, 5, 0, 5) rec[-43] rec[-33] + DETECTOR(5, 0, 0, 0) rec[-26] rec[-24] rec[-21] rec[-17] rec[-7] rec[-6] + DETECTOR(5, 0, 0, 0) rec[-50] rec[-6] + DETECTOR(5, 2, 0, 2) rec[-27] rec[-25] rec[-24] rec[-22] rec[-21] rec[-18] rec[-8] rec[-6] + DETECTOR(5, 2, 0, 2) rec[-49] rec[-7] + DETECTOR(5, 4, 0, 1) rec[-25] rec[-23] rec[-22] rec[-19] rec[-7] + DETECTOR(5, 4, 0, 1) rec[-48] rec[-8] + DETECTOR(6, 0, 0, 3) rec[-41] rec[-40] rec[-34] + DETECTOR(6, 2, 0, 5) rec[-41] rec[-39] rec[-35] + DETECTOR(6, 4, 0, 4) rec[-40] rec[-36] + DETECTOR(7, 1, 0, 1) rec[-28] rec[-27] rec[-26] rec[-24] + DETECTOR(7, 1, 0, 1) rec[-47] rec[-9] + DETECTOR(8, 1, 0, 4) rec[-37] + OBSERVABLE_INCLUDE(0) rec[-28] rec[-27] rec[-26] rec[-25] rec[-24] rec[-23] rec[-22] rec[-21] rec[-20] rec[-19] rec[-18] rec[-17] rec[-16] rec[-15] rec[-14] rec[-13] rec[-12] rec[-11] rec[-10] rec[-9] rec[-8] rec[-7] rec[-5] rec[-4] rec[-3] rec[-2] + SHIFT_COORDS(0, 0, 1) + TICK + """ + ) diff --git a/src/clorco/color_code/_toric_color_code_circuits.py b/src/clorco/color_code/_toric_color_code_circuits.py new file mode 100644 index 0000000..554d62d --- /dev/null +++ b/src/clorco/color_code/_toric_color_code_circuits.py @@ -0,0 +1,385 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Literal, Iterable, Callable + +import stim + +import gen +from clorco.color_code._color_code_layouts import make_toric_color_code_layout + + +def make_toric_color_code_circuit_with_magic_time_boundaries( + *, + rounds: int, + width: int, + height: int, + noise: gen.NoiseModel, + ablate_into_matchable_code: bool = False, + style: Literal["superdense", "midout"], + convert_to_cz: bool, +) -> stim.Circuit: + if style == "superdense": + rounds_per_chunk = 1 + chunk = make_toric_color_code_circuit_round_chunk_superdense( + width=width, + height=height, + noise=noise, + ablate_into_matchable_code=ablate_into_matchable_code, + convert_to_cz=convert_to_cz, + ) + elif style == "midout": + rounds_per_chunk = 2 + chunk = make_toric_color_code_circuit_double_round_chunk_midout( + width=width, + height=height, + noise=noise, + ablate_into_matchable_code=ablate_into_matchable_code, + convert_to_cz=convert_to_cz, + ) + else: + raise NotImplementedError(f"{style=}") + + assert rounds % rounds_per_chunk == 0 + return gen.compile_chunks_into_circuit( + [ + chunk.magic_init_chunk(), + gen.ChunkLoop([chunk], repetitions=rounds // rounds_per_chunk), + chunk.magic_end_chunk(), + ] + ).with_inlined_feedback() + + +def make_toric_color_code_circuit_round_chunk_superdense( + *, + width: int, + height: int, + noise: gen.NoiseModel | None = None, + ablate_into_matchable_code: bool = False, + convert_to_cz: bool, +) -> gen.Chunk: + ancilla_qubits = [-1, -2] + code = make_toric_color_code_layout(width=width, height=height) + w = max(q.real for q in code.patch.used_set) + 1 + h = max(q.imag for q in code.patch.used_set) + 1 + + def wrap(q: complex) -> complex: + return (q.real % w) + (q.imag % h) * 1j + + builder = gen.Builder.for_qubits(code.patch.used_set | set(ancilla_qubits)) + x_ms = [tile.measurement_qubit for tile in code.patch.tiles if tile.basis == "X"] + z_ms = [tile.measurement_qubit for tile in code.patch.tiles if tile.basis == "Z"] + + def do_cxs( + centers: Iterable[complex], + d_control: complex, + d_target: complex, + inv: Callable[[complex], bool] = lambda _: False, + ) -> None: + builder.gate2( + "CX", + [ + (wrap(c + d_control), wrap(c + d_target))[:: -1 if inv(c) else +1] + for c in centers + ], + ) + + builder.gate("RX", x_ms) + builder.gate("RZ", z_ms) + builder.tick() + + do_cxs(x_ms, +0, +1j) + builder.tick() + do_cxs(x_ms, +1, +0) + do_cxs(z_ms, +1, +0) + builder.tick() + do_cxs(x_ms, -1j, +0) + do_cxs(z_ms, +1j, +0) + builder.tick() + do_cxs(x_ms, -1, +0) + do_cxs(z_ms, -1, +0) + builder.tick() + do_cxs(x_ms, +0, +1) + do_cxs(z_ms, +0, +1) + builder.tick() + do_cxs(x_ms, +0, -1j) + do_cxs(z_ms, +0, +1j) + builder.tick() + do_cxs(x_ms, +0, -1) + do_cxs(z_ms, +0, -1) + builder.tick() + do_cxs(x_ms, +0, +1j) + builder.tick() + + builder.measure(x_ms, basis="X", save_layer="solo") + builder.measure(z_ms, basis="Z", save_layer="solo") + builder.tick() + + def mf(*qs): + return builder.tracker.measurement_indices( + [gen.AtLayer(wrap(q), "solo") for q in qs] + ) + + flows = [] + for tile in code.patch.tiles: + m = tile.measurement_qubit + rgb = m.real % 3 + if tile.basis == "X": + if ablate_into_matchable_code and rgb == 0: + continue + flows.append( + gen.Flow( + end=tile.to_data_pauli_string(), + measurement_indices=mf(m), + center=m, + additional_coords=[rgb], + ) + ) + flows.append( + gen.Flow( + start=tile.to_data_pauli_string(), + measurement_indices=mf(m), + center=m, + additional_coords=[rgb], + ) + ) + elif tile.basis == "Z": + if ablate_into_matchable_code and rgb == 2: + continue + flows.append( + gen.Flow( + start=tile.to_data_pauli_string(), + measurement_indices=mf(m), + center=m, + additional_coords=[3 + rgb], + ) + ) + flows.append( + gen.Flow( + end=tile.to_data_pauli_string(), + measurement_indices=mf(m - 2, m + 2), + center=m, + additional_coords=[3 + rgb], + ) + ) + + x1, x2 = code.observables_x + z1, z2 = code.observables_z + x1 *= gen.PauliString({ancilla_qubits[0]: "X"}) + z1 *= gen.PauliString({ancilla_qubits[0]: "Z"}) + x2 *= gen.PauliString({ancilla_qubits[1]: "X"}) + z2 *= gen.PauliString({ancilla_qubits[1]: "Z"}) + flows.append( + gen.Flow( + start=x1, + end=x1, + measurement_indices=[], + center=-1 - 1j, + obs_index=0, + ) + ) + flows.append( + gen.Flow( + start=x2, + end=x2, + measurement_indices=[], + center=-2 - 1j, + obs_index=1, + ) + ) + flows.append( + gen.Flow( + start=z1, + end=z1, + measurement_indices=[], + center=-3 - 1j, + obs_index=2, + ) + ) + flows.append( + gen.Flow( + start=z2, + end=z2, + measurement_indices=mf(*[m for m in z_ms if m.real in [1, 2, 3]]), + center=-4 - 1j, + obs_index=3, + ) + ) + + circuit = builder.circuit + if convert_to_cz: + circuit = gen.transpile_to_z_basis_interaction_circuit( + circuit, is_entire_circuit=False + ) + if noise is not None: + circuit = noise.noisy_circuit( + circuit, immune_qubit_indices={builder.q2i[-1], builder.q2i[-2]} + ) + return gen.Chunk( + circuit=circuit, + flows=flows, + q2i=builder.q2i, + ) + + +def make_toric_color_code_circuit_double_round_chunk_midout( + *, + width: int, + height: int, + noise: gen.NoiseModel | None = None, + convert_to_cz: bool, + ablate_into_matchable_code: bool = False, +) -> gen.Chunk: + ancilla_qubits = [-1, -2] + code = make_toric_color_code_layout(width=width, height=height, square_coords=True) + w = max(q.real for q in code.patch.used_set) + 1 + h = max(q.imag for q in code.patch.used_set) + 1 + + def wrap(q: complex) -> complex: + return (q.real % w) + (q.imag % h) * 1j + + builder = gen.Builder.for_qubits(code.patch.used_set | set(ancilla_qubits)) + + def do_cxs( + centers: Iterable[complex], + d_control: complex, + d_target: complex, + inv: Callable[[complex], bool] = lambda _: False, + ) -> None: + builder.gate2( + "CX", + [ + ( + wrap(c + d_control), + wrap(c + d_target), + )[:: -1 if inv(c) else +1] + for c in centers + ], + ) + + x_ms = [ + d for d in code.patch.data_set if d.real % 2 != d.imag % 2 and d.real % 2 == 1 + ] + z_ms = [ + d for d in code.patch.data_set if d.real % 2 != d.imag % 2 and d.real % 2 == 0 + ] + d1s = [d for d in code.patch.data_set if d.real % 2 == 0] + d2s = [d for d in code.patch.data_set if d.real % 2 == 1] + + do_cxs(d1s, +0, +1) + builder.tick() + do_cxs(d2s, +0, +1) + builder.tick() + do_cxs(z_ms, +1j, +0) + do_cxs(x_ms, +0, +1j) + builder.tick() + builder.demolition_measure_with_feedback_passthrough( + xs=x_ms, zs=z_ms, save_layer="a" + ) + builder.tick() + do_cxs(z_ms, +1j, +0) + do_cxs(x_ms, +0, +1j) + builder.tick() + do_cxs(d2s, +0, +1) + builder.tick() + do_cxs(d1s, +0, +1) + builder.tick() + + do_cxs(d1s, +1, +0) + builder.tick() + do_cxs(d2s, +1, +0) + builder.tick() + do_cxs(z_ms, +0, +1j) + do_cxs(x_ms, +1j, +0) + builder.tick() + builder.demolition_measure_with_feedback_passthrough( + xs=z_ms, zs=x_ms, save_layer="b" + ) + builder.tick() + do_cxs(z_ms, +0, +1j) + do_cxs(x_ms, +1j, +0) + builder.tick() + do_cxs(d2s, +1, +0) + builder.tick() + do_cxs(d1s, +1, +0) + builder.tick() + + def ma(*qs) -> list[int]: + return builder.tracker.measurement_indices( + [gen.AtLayer(wrap(q), "a") for q in qs] + ) + + def mb(*qs) -> list[int]: + return builder.tracker.measurement_indices( + [gen.AtLayer(wrap(q), "b") for q in qs] + ) + + flows = [] + for tile in code.patch.tiles: + m = tile.measurement_qubit + if ablate_into_matchable_code and tile.extra_coords[0] in [0, 5]: + continue + if tile.basis == "X": + mids = mb(m + 1) if m.real % 2 == 1 else ma(m - 1) + elif tile.basis == "Z": + mids = ma(m + 1 - 1j) if m.real % 2 == 1 else mb(m - 1 - 1j) + else: + raise NotImplementedError(f"{tile=}") + flows.append( + gen.Flow( + start=tile.to_data_pauli_string(), + measurement_indices=mids, + center=m, + additional_coords=tile.extra_coords, + ) + ) + flows.append( + gen.Flow( + end=tile.to_data_pauli_string(), + measurement_indices=mids, + center=m, + additional_coords=tile.extra_coords, + ) + ) + + x1, x2 = code.observables_x + z1, z2 = code.observables_z + x1 *= gen.PauliString({ancilla_qubits[0]: "X"}) + z1 *= gen.PauliString({ancilla_qubits[0]: "Z"}) + x2 *= gen.PauliString({ancilla_qubits[1]: "X"}) + z2 *= gen.PauliString({ancilla_qubits[1]: "Z"}) + for k, obs in enumerate([x1, z1, x2, z1]): + flows.append( + gen.Flow( + start=obs, + end=obs, + center=-1 - 1j - k * 1j, + obs_index=k, + ) + ) + + circuit = builder.circuit + if convert_to_cz: + circuit = gen.transpile_to_z_basis_interaction_circuit( + circuit, is_entire_circuit=False + ) + if noise is not None: + circuit = noise.noisy_circuit( + circuit, immune_qubit_indices={builder.q2i[-1], builder.q2i[-2]} + ) + return gen.Chunk( + circuit=circuit, + flows=flows, + q2i=builder.q2i, + ) diff --git a/src/clorco/color_code/_toric_color_code_circuits_test.py b/src/clorco/color_code/_toric_color_code_circuits_test.py new file mode 100644 index 0000000..f5854e9 --- /dev/null +++ b/src/clorco/color_code/_toric_color_code_circuits_test.py @@ -0,0 +1,329 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools +from typing import Any + +import pytest +import stim + +import gen +from clorco.color_code._toric_color_code_circuits import ( + make_toric_color_code_circuit_with_magic_time_boundaries, + make_toric_color_code_circuit_double_round_chunk_midout, + make_toric_color_code_circuit_round_chunk_superdense, +) + + +@pytest.mark.parametrize("style", ["superdense"]) +def test_make_toric_color_code_circuit_round_chunk(style: Any): + make_toric_color_code_circuit_round_chunk_superdense( + width=6, + height=8, + ablate_into_matchable_code=False, + convert_to_cz=False, + ).verify() + make_toric_color_code_circuit_round_chunk_superdense( + width=6, + height=8, + ablate_into_matchable_code=True, + convert_to_cz=False, + ).verify() + + +def test_make_toric_color_code_circuit_round_chunk_inplace(): + make_toric_color_code_circuit_double_round_chunk_midout( + width=6, + height=8, + ablate_into_matchable_code=False, + convert_to_cz=False, + ).verify() + make_toric_color_code_circuit_double_round_chunk_midout( + width=6, + height=8, + ablate_into_matchable_code=True, + convert_to_cz=False, + ).verify() + + +@pytest.mark.parametrize( + "width,height,style,ablate_into_matchable_code", + itertools.product( + [6, 12], + [4, 8], + ["superdense", "midout"], + [False, True], + ), +) +def test_make_toric_color_code_circuit_with_magic_time_boundaries( + width: int, height: int, style: Any, ablate_into_matchable_code: bool +): + circuit = make_toric_color_code_circuit_with_magic_time_boundaries( + width=width, + height=height, + rounds=4, + noise=gen.NoiseModel.uniform_depolarizing(1e-3), + style=style, + ablate_into_matchable_code=ablate_into_matchable_code, + convert_to_cz=False, + ) + assert gen.count_measurement_layers(circuit) == 4 + 2 + if ablate_into_matchable_code: + err = circuit.shortest_graphlike_error( + canonicalize_circuit_errors=True, + ) + else: + err = circuit.search_for_undetectable_logical_errors( + dont_explore_edges_increasing_symptom_degree=False, + dont_explore_edges_with_degree_above=3, + dont_explore_detection_event_sets_with_size_above=4, + canonicalize_circuit_errors=True, + ) + if style == "midout": + expected_distance = min(width // 3 * 2, height // 2) // 2 + elif style == "superdense": + if ablate_into_matchable_code: + expected_distance = min(width // 3, height // 2) + else: + expected_distance = min(width // 3 * 2, height // 2) + else: + raise NotImplementedError(f"{style=}") + assert len(err) == expected_distance + + +def test_make_toric_color_code_circuit_with_magic_time_boundaries_exact_circuit(): + assert make_toric_color_code_circuit_with_magic_time_boundaries( + width=6, + height=8, + rounds=5, + noise=gen.NoiseModel.uniform_depolarizing(1e-3), + style="superdense", + convert_to_cz=False, + ) == stim.Circuit( + """ + QUBIT_COORDS(-2, 0) 0 + QUBIT_COORDS(-1, 0) 1 + QUBIT_COORDS(0, 0) 2 + QUBIT_COORDS(0, 1) 3 + QUBIT_COORDS(0, 2) 4 + QUBIT_COORDS(0, 3) 5 + QUBIT_COORDS(0, 4) 6 + QUBIT_COORDS(0, 5) 7 + QUBIT_COORDS(0, 6) 8 + QUBIT_COORDS(0, 7) 9 + QUBIT_COORDS(1, 0) 10 + QUBIT_COORDS(1, 1) 11 + QUBIT_COORDS(1, 2) 12 + QUBIT_COORDS(1, 3) 13 + QUBIT_COORDS(1, 4) 14 + QUBIT_COORDS(1, 5) 15 + QUBIT_COORDS(1, 6) 16 + QUBIT_COORDS(1, 7) 17 + QUBIT_COORDS(2, 0) 18 + QUBIT_COORDS(2, 1) 19 + QUBIT_COORDS(2, 2) 20 + QUBIT_COORDS(2, 3) 21 + QUBIT_COORDS(2, 4) 22 + QUBIT_COORDS(2, 5) 23 + QUBIT_COORDS(2, 6) 24 + QUBIT_COORDS(2, 7) 25 + QUBIT_COORDS(3, 0) 26 + QUBIT_COORDS(3, 1) 27 + QUBIT_COORDS(3, 2) 28 + QUBIT_COORDS(3, 3) 29 + QUBIT_COORDS(3, 4) 30 + QUBIT_COORDS(3, 5) 31 + QUBIT_COORDS(3, 6) 32 + QUBIT_COORDS(3, 7) 33 + QUBIT_COORDS(4, 0) 34 + QUBIT_COORDS(4, 1) 35 + QUBIT_COORDS(4, 2) 36 + QUBIT_COORDS(4, 3) 37 + QUBIT_COORDS(4, 4) 38 + QUBIT_COORDS(4, 5) 39 + QUBIT_COORDS(4, 6) 40 + QUBIT_COORDS(4, 7) 41 + QUBIT_COORDS(5, 0) 42 + QUBIT_COORDS(5, 1) 43 + QUBIT_COORDS(5, 2) 44 + QUBIT_COORDS(5, 3) 45 + QUBIT_COORDS(5, 4) 46 + QUBIT_COORDS(5, 5) 47 + QUBIT_COORDS(5, 6) 48 + QUBIT_COORDS(5, 7) 49 + MPP X4*X9*X10*X11*X42*X43 Z4*Z9*Z10*Z11*Z42*Z43 X5*X8*X14*X15*X46*X47 Z5*Z8*Z14*Z15*Z46*Z47 X4*X5*X11*X14*X20*X21 Z4*Z5*Z11*Z14*Z20*Z21 X8*X9*X10*X15*X24*X25 Z8*Z9*Z10*Z15*Z24*Z25 X10*X11*X20*X25*X26*X27 Z10*Z11*Z20*Z25*Z26*Z27 X14*X15*X21*X24*X30*X31 Z14*Z15*Z21*Z24*Z30*Z31 X20*X21*X27*X30*X36*X37 Z20*Z21*Z27*Z30*Z36*Z37 X24*X25*X26*X31*X40*X41 Z24*Z25*Z26*Z31*Z40*Z41 X26*X27*X36*X41*X42*X43 Z26*Z27*Z36*Z41*Z42*Z43 X30*X31*X37*X40*X46*X47 Z30*Z31*Z37*Z40*Z46*Z47 X4*X5*X36*X37*X43*X46 Z4*Z5*Z36*Z37*Z43*Z46 X8*X9*X40*X41*X42*X47 Z8*Z9*Z40*Z41*Z42*Z47 X1*X4*X5*X8*X9 X0*X14*X21*X37*X46 Z1*Z4*Z11*Z27*Z36 Z0*Z20*Z21*Z24*Z25 + OBSERVABLE_INCLUDE(0) rec[-4] + OBSERVABLE_INCLUDE(1) rec[-3] + OBSERVABLE_INCLUDE(2) rec[-2] + OBSERVABLE_INCLUDE(3) rec[-1] + TICK + RX 2 6 12 16 18 22 28 32 34 38 44 48 + R 3 7 13 17 19 23 29 33 35 39 45 49 + X_ERROR(0.001) 3 7 13 17 19 23 29 33 35 39 45 49 + Z_ERROR(0.001) 2 6 12 16 18 22 28 32 34 38 44 48 + DEPOLARIZE1(0.001) 4 5 8 9 10 11 14 15 20 21 24 25 26 27 30 31 36 37 40 41 42 43 46 47 + TICK + CX 2 3 6 7 12 13 16 17 18 19 22 23 28 29 32 33 34 35 38 39 44 45 48 49 + DEPOLARIZE2(0.001) 2 3 6 7 12 13 16 17 18 19 22 23 28 29 32 33 34 35 38 39 44 45 48 49 + DEPOLARIZE1(0.001) 4 5 8 9 10 11 14 15 20 21 24 25 26 27 30 31 36 37 40 41 42 43 46 47 + TICK + CX 4 44 8 48 10 2 14 6 20 12 24 16 26 18 30 22 36 28 40 32 42 34 46 38 5 45 9 49 11 3 15 7 21 13 25 17 27 19 31 23 37 29 41 33 43 35 47 39 + DEPOLARIZE2(0.001) 4 44 8 48 10 2 14 6 20 12 24 16 26 18 30 22 36 28 40 32 42 34 46 38 5 45 9 49 11 3 15 7 21 13 25 17 27 19 31 23 37 29 41 33 43 35 47 39 + TICK + CX 5 6 9 2 11 12 15 16 21 22 25 18 27 28 31 32 37 38 41 34 43 44 47 48 4 3 8 7 10 17 14 13 20 19 24 23 26 33 30 29 36 35 40 39 42 49 46 45 + DEPOLARIZE2(0.001) 5 6 9 2 11 12 15 16 21 22 25 18 27 28 31 32 37 38 41 34 43 44 47 48 4 3 8 7 10 17 14 13 20 19 24 23 26 33 30 29 36 35 40 39 42 49 46 45 + TICK + CX 4 12 8 16 10 18 14 22 20 28 24 32 26 34 30 38 36 44 40 48 42 2 46 6 5 13 9 17 11 19 15 23 21 29 25 33 27 35 31 39 37 45 41 49 43 3 47 7 + DEPOLARIZE2(0.001) 4 12 8 16 10 18 14 22 20 28 24 32 26 34 30 38 36 44 40 48 42 2 46 6 5 13 9 17 11 19 15 23 21 29 25 33 27 35 31 39 37 45 41 49 43 3 47 7 + TICK + CX 2 10 6 14 12 20 16 24 18 26 22 30 28 36 32 40 34 42 38 46 44 4 48 8 3 11 7 15 13 21 17 25 19 27 23 31 29 37 33 41 35 43 39 47 45 5 49 9 + DEPOLARIZE2(0.001) 2 10 6 14 12 20 16 24 18 26 22 30 28 36 32 40 34 42 38 46 44 4 48 8 3 11 7 15 13 21 17 25 19 27 23 31 29 37 33 41 35 43 39 47 45 5 49 9 + TICK + CX 2 9 6 5 12 11 16 15 18 25 22 21 28 27 32 31 34 41 38 37 44 43 48 47 3 4 7 8 13 14 17 10 19 20 23 24 29 30 33 26 35 36 39 40 45 46 49 42 + DEPOLARIZE2(0.001) 2 9 6 5 12 11 16 15 18 25 22 21 28 27 32 31 34 41 38 37 44 43 48 47 3 4 7 8 13 14 17 10 19 20 23 24 29 30 33 26 35 36 39 40 45 46 49 42 + TICK + CX 2 42 6 46 12 4 16 8 18 10 22 14 28 20 32 24 34 26 38 30 44 36 48 40 3 43 7 47 13 5 17 9 19 11 23 15 29 21 33 25 35 27 39 31 45 37 49 41 + DEPOLARIZE2(0.001) 2 42 6 46 12 4 16 8 18 10 22 14 28 20 32 24 34 26 38 30 44 36 48 40 3 43 7 47 13 5 17 9 19 11 23 15 29 21 33 25 35 27 39 31 45 37 49 41 + TICK + CX 2 3 6 7 12 13 16 17 18 19 22 23 28 29 32 33 34 35 38 39 44 45 48 49 + DEPOLARIZE2(0.001) 2 3 6 7 12 13 16 17 18 19 22 23 28 29 32 33 34 35 38 39 44 45 48 49 + DEPOLARIZE1(0.001) 4 5 8 9 10 11 14 15 20 21 24 25 26 27 30 31 36 37 40 41 42 43 46 47 + TICK + MX(0.001) 2 6 12 16 18 22 28 32 34 38 44 48 + M(0.001) 3 7 13 17 19 23 29 33 35 39 45 49 + DEPOLARIZE1(0.001) 2 6 12 16 18 22 28 32 34 38 44 48 3 7 13 17 19 23 29 33 35 39 45 49 4 5 8 9 10 11 14 15 20 21 24 25 26 27 30 31 36 37 40 41 42 43 46 47 + DETECTOR(0, 0, 0, 0) rec[-52] rec[-24] + DETECTOR(0, 1, 0, 3) rec[-51] rec[-12] + DETECTOR(0, 4, 0, 0) rec[-50] rec[-23] + DETECTOR(0, 5, 0, 3) rec[-49] rec[-11] + DETECTOR(1, 2, 0, 1) rec[-48] rec[-22] + DETECTOR(1, 3, 0, 4) rec[-47] rec[-10] + DETECTOR(1, 6, 0, 1) rec[-46] rec[-21] + DETECTOR(1, 7, 0, 4) rec[-45] rec[-9] + DETECTOR(2, 0, 0, 2) rec[-44] rec[-20] + DETECTOR(2, 1, 0, 5) rec[-43] rec[-8] + DETECTOR(2, 4, 0, 2) rec[-42] rec[-19] + DETECTOR(2, 5, 0, 5) rec[-41] rec[-7] + DETECTOR(3, 2, 0, 0) rec[-40] rec[-18] + DETECTOR(3, 3, 0, 3) rec[-39] rec[-6] + DETECTOR(3, 6, 0, 0) rec[-38] rec[-17] + DETECTOR(3, 7, 0, 3) rec[-37] rec[-5] + DETECTOR(4, 0, 0, 1) rec[-36] rec[-16] + DETECTOR(4, 1, 0, 4) rec[-35] rec[-4] + DETECTOR(4, 4, 0, 1) rec[-34] rec[-15] + DETECTOR(4, 5, 0, 4) rec[-33] rec[-3] + DETECTOR(5, 2, 0, 2) rec[-32] rec[-14] + DETECTOR(5, 3, 0, 5) rec[-31] rec[-2] + DETECTOR(5, 6, 0, 2) rec[-30] rec[-13] + DETECTOR(5, 7, 0, 5) rec[-29] rec[-1] + OBSERVABLE_INCLUDE(3) rec[-10] rec[-9] rec[-8] rec[-7] rec[-6] rec[-5] + SHIFT_COORDS(0, 0, 1) + TICK + REPEAT 4 { + RX 2 6 12 16 18 22 28 32 34 38 44 48 + R 3 7 13 17 19 23 29 33 35 39 45 49 + X_ERROR(0.001) 3 7 13 17 19 23 29 33 35 39 45 49 + Z_ERROR(0.001) 2 6 12 16 18 22 28 32 34 38 44 48 + DEPOLARIZE1(0.001) 4 5 8 9 10 11 14 15 20 21 24 25 26 27 30 31 36 37 40 41 42 43 46 47 + TICK + CX 2 3 6 7 12 13 16 17 18 19 22 23 28 29 32 33 34 35 38 39 44 45 48 49 + DEPOLARIZE2(0.001) 2 3 6 7 12 13 16 17 18 19 22 23 28 29 32 33 34 35 38 39 44 45 48 49 + DEPOLARIZE1(0.001) 4 5 8 9 10 11 14 15 20 21 24 25 26 27 30 31 36 37 40 41 42 43 46 47 + TICK + CX 4 44 8 48 10 2 14 6 20 12 24 16 26 18 30 22 36 28 40 32 42 34 46 38 5 45 9 49 11 3 15 7 21 13 25 17 27 19 31 23 37 29 41 33 43 35 47 39 + DEPOLARIZE2(0.001) 4 44 8 48 10 2 14 6 20 12 24 16 26 18 30 22 36 28 40 32 42 34 46 38 5 45 9 49 11 3 15 7 21 13 25 17 27 19 31 23 37 29 41 33 43 35 47 39 + TICK + CX 5 6 9 2 11 12 15 16 21 22 25 18 27 28 31 32 37 38 41 34 43 44 47 48 4 3 8 7 10 17 14 13 20 19 24 23 26 33 30 29 36 35 40 39 42 49 46 45 + DEPOLARIZE2(0.001) 5 6 9 2 11 12 15 16 21 22 25 18 27 28 31 32 37 38 41 34 43 44 47 48 4 3 8 7 10 17 14 13 20 19 24 23 26 33 30 29 36 35 40 39 42 49 46 45 + TICK + CX 4 12 8 16 10 18 14 22 20 28 24 32 26 34 30 38 36 44 40 48 42 2 46 6 5 13 9 17 11 19 15 23 21 29 25 33 27 35 31 39 37 45 41 49 43 3 47 7 + DEPOLARIZE2(0.001) 4 12 8 16 10 18 14 22 20 28 24 32 26 34 30 38 36 44 40 48 42 2 46 6 5 13 9 17 11 19 15 23 21 29 25 33 27 35 31 39 37 45 41 49 43 3 47 7 + TICK + CX 2 10 6 14 12 20 16 24 18 26 22 30 28 36 32 40 34 42 38 46 44 4 48 8 3 11 7 15 13 21 17 25 19 27 23 31 29 37 33 41 35 43 39 47 45 5 49 9 + DEPOLARIZE2(0.001) 2 10 6 14 12 20 16 24 18 26 22 30 28 36 32 40 34 42 38 46 44 4 48 8 3 11 7 15 13 21 17 25 19 27 23 31 29 37 33 41 35 43 39 47 45 5 49 9 + TICK + CX 2 9 6 5 12 11 16 15 18 25 22 21 28 27 32 31 34 41 38 37 44 43 48 47 3 4 7 8 13 14 17 10 19 20 23 24 29 30 33 26 35 36 39 40 45 46 49 42 + DEPOLARIZE2(0.001) 2 9 6 5 12 11 16 15 18 25 22 21 28 27 32 31 34 41 38 37 44 43 48 47 3 4 7 8 13 14 17 10 19 20 23 24 29 30 33 26 35 36 39 40 45 46 49 42 + TICK + CX 2 42 6 46 12 4 16 8 18 10 22 14 28 20 32 24 34 26 38 30 44 36 48 40 3 43 7 47 13 5 17 9 19 11 23 15 29 21 33 25 35 27 39 31 45 37 49 41 + DEPOLARIZE2(0.001) 2 42 6 46 12 4 16 8 18 10 22 14 28 20 32 24 34 26 38 30 44 36 48 40 3 43 7 47 13 5 17 9 19 11 23 15 29 21 33 25 35 27 39 31 45 37 49 41 + TICK + CX 2 3 6 7 12 13 16 17 18 19 22 23 28 29 32 33 34 35 38 39 44 45 48 49 + DEPOLARIZE2(0.001) 2 3 6 7 12 13 16 17 18 19 22 23 28 29 32 33 34 35 38 39 44 45 48 49 + DEPOLARIZE1(0.001) 4 5 8 9 10 11 14 15 20 21 24 25 26 27 30 31 36 37 40 41 42 43 46 47 + TICK + MX(0.001) 2 6 12 16 18 22 28 32 34 38 44 48 + M(0.001) 3 7 13 17 19 23 29 33 35 39 45 49 + DEPOLARIZE1(0.001) 2 6 12 16 18 22 28 32 34 38 44 48 3 7 13 17 19 23 29 33 35 39 45 49 4 5 8 9 10 11 14 15 20 21 24 25 26 27 30 31 36 37 40 41 42 43 46 47 + DETECTOR(0, 0, 0, 0) rec[-48] rec[-24] + DETECTOR(0, 1, 0, 3) rec[-32] rec[-28] rec[-12] + DETECTOR(0, 4, 0, 0) rec[-47] rec[-23] + DETECTOR(0, 5, 0, 3) rec[-31] rec[-27] rec[-11] + DETECTOR(1, 2, 0, 1) rec[-46] rec[-22] + DETECTOR(1, 3, 0, 4) rec[-30] rec[-26] rec[-10] + DETECTOR(1, 6, 0, 1) rec[-45] rec[-21] + DETECTOR(1, 7, 0, 4) rec[-29] rec[-25] rec[-9] + DETECTOR(2, 0, 0, 2) rec[-44] rec[-20] + DETECTOR(2, 1, 0, 5) rec[-36] rec[-28] rec[-8] + DETECTOR(2, 4, 0, 2) rec[-43] rec[-19] + DETECTOR(2, 5, 0, 5) rec[-35] rec[-27] rec[-7] + DETECTOR(3, 2, 0, 0) rec[-42] rec[-18] + DETECTOR(3, 3, 0, 3) rec[-34] rec[-26] rec[-6] + DETECTOR(3, 6, 0, 0) rec[-41] rec[-17] + DETECTOR(3, 7, 0, 3) rec[-33] rec[-25] rec[-5] + DETECTOR(4, 0, 0, 1) rec[-40] rec[-16] + DETECTOR(4, 1, 0, 4) rec[-36] rec[-32] rec[-4] + DETECTOR(4, 4, 0, 1) rec[-39] rec[-15] + DETECTOR(4, 5, 0, 4) rec[-35] rec[-31] rec[-3] + DETECTOR(5, 2, 0, 2) rec[-38] rec[-14] + DETECTOR(5, 3, 0, 5) rec[-34] rec[-30] rec[-2] + DETECTOR(5, 6, 0, 2) rec[-37] rec[-13] + DETECTOR(5, 7, 0, 5) rec[-33] rec[-29] rec[-1] + OBSERVABLE_INCLUDE(3) rec[-10] rec[-9] rec[-8] rec[-7] rec[-6] rec[-5] + SHIFT_COORDS(0, 0, 1) + TICK + } + MPP X4*X9*X10*X11*X42*X43 Z4*Z9*Z10*Z11*Z42*Z43 X5*X8*X14*X15*X46*X47 Z5*Z8*Z14*Z15*Z46*Z47 X4*X5*X11*X14*X20*X21 Z4*Z5*Z11*Z14*Z20*Z21 X8*X9*X10*X15*X24*X25 Z8*Z9*Z10*Z15*Z24*Z25 X10*X11*X20*X25*X26*X27 Z10*Z11*Z20*Z25*Z26*Z27 X14*X15*X21*X24*X30*X31 Z14*Z15*Z21*Z24*Z30*Z31 X20*X21*X27*X30*X36*X37 Z20*Z21*Z27*Z30*Z36*Z37 X24*X25*X26*X31*X40*X41 Z24*Z25*Z26*Z31*Z40*Z41 X26*X27*X36*X41*X42*X43 Z26*Z27*Z36*Z41*Z42*Z43 X30*X31*X37*X40*X46*X47 Z30*Z31*Z37*Z40*Z46*Z47 X4*X5*X36*X37*X43*X46 Z4*Z5*Z36*Z37*Z43*Z46 X8*X9*X40*X41*X42*X47 Z8*Z9*Z40*Z41*Z42*Z47 X1*X4*X5*X8*X9 X0*X14*X21*X37*X46 Z1*Z4*Z11*Z27*Z36 Z0*Z20*Z21*Z24*Z25 + DETECTOR(0, 0, 0, 0) rec[-52] rec[-28] + DETECTOR(0, 1, 0, 3) rec[-36] rec[-32] rec[-27] + DETECTOR(0, 4, 0, 0) rec[-51] rec[-26] + DETECTOR(0, 5, 0, 3) rec[-35] rec[-31] rec[-25] + DETECTOR(1, 2, 0, 1) rec[-50] rec[-24] + DETECTOR(1, 3, 0, 4) rec[-34] rec[-30] rec[-23] + DETECTOR(1, 6, 0, 1) rec[-49] rec[-22] + DETECTOR(1, 7, 0, 4) rec[-33] rec[-29] rec[-21] + DETECTOR(2, 0, 0, 2) rec[-48] rec[-20] + DETECTOR(2, 1, 0, 5) rec[-40] rec[-32] rec[-19] + DETECTOR(2, 4, 0, 2) rec[-47] rec[-18] + DETECTOR(2, 5, 0, 5) rec[-39] rec[-31] rec[-17] + DETECTOR(3, 2, 0, 0) rec[-46] rec[-16] + DETECTOR(3, 3, 0, 3) rec[-38] rec[-30] rec[-15] + DETECTOR(3, 6, 0, 0) rec[-45] rec[-14] + DETECTOR(3, 7, 0, 3) rec[-37] rec[-29] rec[-13] + DETECTOR(4, 0, 0, 1) rec[-44] rec[-12] + DETECTOR(4, 1, 0, 4) rec[-40] rec[-36] rec[-11] + DETECTOR(4, 4, 0, 1) rec[-43] rec[-10] + DETECTOR(4, 5, 0, 4) rec[-39] rec[-35] rec[-9] + DETECTOR(5, 2, 0, 2) rec[-42] rec[-8] + DETECTOR(5, 3, 0, 5) rec[-38] rec[-34] rec[-7] + DETECTOR(5, 6, 0, 2) rec[-41] rec[-6] + DETECTOR(5, 7, 0, 5) rec[-37] rec[-33] rec[-5] + OBSERVABLE_INCLUDE(0) rec[-4] + OBSERVABLE_INCLUDE(1) rec[-3] + OBSERVABLE_INCLUDE(2) rec[-2] + OBSERVABLE_INCLUDE(3) rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + """ + ) diff --git a/src/clorco/pyramid_code/__init__.py b/src/clorco/pyramid_code/__init__.py new file mode 100644 index 0000000..aaa2d35 --- /dev/null +++ b/src/clorco/pyramid_code/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/clorco/pyramid_code/_keyed_constructions.py b/src/clorco/pyramid_code/_keyed_constructions.py new file mode 100644 index 0000000..e737de4 --- /dev/null +++ b/src/clorco/pyramid_code/_keyed_constructions.py @@ -0,0 +1,92 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Callable + +import stim + +import gen +from clorco._make_circuit_params import Params +from clorco.pyramid_code._pyramid_code_layouts import make_planar_pyramid_code_layout +from clorco.pyramid_code._pyramid_code_layouts import make_toric_pyramid_code_layout + + +def make_named_pyramid_code_constructions() -> ( + dict[str, Callable[[Params], stim.Circuit]] +): + constructions: dict[str, Callable[[Params], stim.Circuit]] = {} + + def _make_simple_circuit( + params: Params, *, code: gen.StabilizerCode, phenom: bool + ) -> stim.Circuit: + if params.debug_out_dir is not None: + code.patch.write_svg(params.debug_out_dir / 'rgb_patch.svg', other=[ + code.patch.with_only_x_tiles(), + code.patch.with_only_z_tiles(), + gen.Patch(gen.Tile( + ordered_data_qubits=tile.ordered_data_qubits, + measurement_qubit=tile.measurement_qubit, + bases='XYZXYZ'[int(tile.extra_coords[0])], + ) for tile in code.patch.with_only_x_tiles().tiles), + gen.Patch(gen.Tile( + ordered_data_qubits=tile.ordered_data_qubits, + measurement_qubit=tile.measurement_qubit, + bases='XYZXYZ'[int(tile.extra_coords[0])], + ) for tile in code.patch.with_only_z_tiles().tiles), + ]) + if phenom: + return code.make_phenom_circuit( + noise=params.noise_model, + rounds=params.rounds, + debug_out_dir=params.debug_out_dir, + ) + assert params.rounds == 1 + return code.make_code_capacity_circuit( + noise=params.noise_model.idle_noise, + debug_out_dir=params.debug_out_dir + ) + + constructions["transit_pyramid_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_planar_pyramid_code_layout( + width=params.diameter * 2 - 1, + height=params.diameter * 3 // 2 + 1, + ), + phenom=False, + ) + constructions["phenom_pyramid_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_planar_pyramid_code_layout( + width=params.diameter * 2 - 1, + height=params.diameter * 3 // 2 + 1, + ), + phenom=True, + ) + constructions["transit_toric_pyramid_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_toric_pyramid_code_layout( + width=params.diameter * 2, + height=params.diameter * 3 // 2 + (-(params.diameter * 3 // 2) % 3), + ), + phenom=False, + ) + constructions["phenom_toric_pyramid_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_toric_pyramid_code_layout( + width=params.diameter * 2, + height=params.diameter * 3 // 2 + (-(params.diameter * 3 // 2) % 3), + ), + phenom=True, + ) + return constructions diff --git a/src/clorco/pyramid_code/_pyramid_code_layouts.py b/src/clorco/pyramid_code/_pyramid_code_layouts.py new file mode 100644 index 0000000..5de03e2 --- /dev/null +++ b/src/clorco/pyramid_code/_pyramid_code_layouts.py @@ -0,0 +1,116 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gen + + +def make_toric_pyramid_code_layout( + *, + width: int, + height: int, +) -> gen.StabilizerCode: + assert width % 2 == 0 + assert height % 3 == 0 + + def wrap(v: complex) -> complex: + return (v.real % width) + 1j * (v.imag % height) + + tiles = [] + for x in range(width): + for y in range(height): + c = x + 1j * y + b = "X" if x % 2 == 1 else "Z" + tiles.append( + gen.Tile( + bases=b, + ordered_data_qubits=[wrap(c + d) for d in [1, -1, 1j, -1j, 0]], + measurement_qubit=c, + extra_coords=[y % 3 + 3 * (b == "Z")], + ) + ) + patch = gen.Patch(tiles) + + return gen.StabilizerCode( + patch=patch, + observables_x=[ + gen.PauliString( + {q: "X" for q in patch.data_set if q.imag % 3 != 2 and q.real == 0} + ), + gen.PauliString( + {q: "X" for q in patch.data_set if q.real % 2 == 1 and q.imag == 0} + ), + ], + observables_z=[ + gen.PauliString( + {q: "Z" for q in patch.data_set if q.real % 2 == 0 and q.imag == 0} + ), + gen.PauliString( + {q: "Z" for q in patch.data_set if q.imag % 3 != 2 and q.real == 1} + ), + ], + ) + + +def make_planar_pyramid_code_layout( + *, + width: int, + height: int, +) -> gen.StabilizerCode: + tiles = [] + for x in range(-1, width + 1): + for y in range(-1, height + 1): + c = x + 1j * y + b = "X" if x % 2 == 1 else "Z" + qs: list[complex | None] = [c + d for d in [1, -1, 1j, -1j, 0]] + drop_tile = False + for k in range(len(qs)): + q = qs[k] + if not (0 <= q.real < width): + drop_tile |= b == "X" + qs[k] = None + if not (0 <= q.imag < height): + drop_tile |= b == "Z" + qs[k] = None + if drop_tile: + continue + + tiles.append( + gen.Tile( + bases=b, + ordered_data_qubits=qs, + measurement_qubit=c, + extra_coords=[y % 3 + 3 * (b == "Z")], + ) + ) + patch = gen.Patch(tiles) + + return gen.StabilizerCode( + patch=patch, + observables_x=[ + gen.PauliString( + {q: "X" for q in patch.data_set if q.imag % 3 != 2 and q.real == 0} + ), + gen.PauliString( + {q: "X" for q in patch.data_set if q.imag % 3 != 0 and q.real == 0} + ), + ], + observables_z=[ + gen.PauliString( + {q: "Z" for q in patch.data_set if q.real % 2 == 0 and q.imag == 0} + ), + gen.PauliString( + {q: "Z" for q in patch.data_set if q.real % 2 == 0 and q.imag == 2} + ), + ], + ) diff --git a/src/clorco/pyramid_code/_pyramid_code_layouts_test.py b/src/clorco/pyramid_code/_pyramid_code_layouts_test.py new file mode 100644 index 0000000..9a597a4 --- /dev/null +++ b/src/clorco/pyramid_code/_pyramid_code_layouts_test.py @@ -0,0 +1,61 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +from clorco.pyramid_code._pyramid_code_layouts import make_planar_pyramid_code_layout +from clorco.pyramid_code._pyramid_code_layouts import make_toric_pyramid_code_layout + + +@pytest.mark.parametrize("h", [3, 6, 9]) +@pytest.mark.parametrize("w", [4, 6, 8, 10]) +def test_make_toric_pyramid_code_layout(w: int, h: int): + code = make_toric_pyramid_code_layout( + width=w, + height=h, + ) + code.check_commutation_relationships() + assert ( + len(code.patch.data_set) + == len(code.patch.tiles) + + max(len(code.observables_x), len(code.observables_z)) + - 2 + ) + c = code.make_code_capacity_circuit(noise=1e-3) + err = c.search_for_undetectable_logical_errors( + dont_explore_edges_with_degree_above=3, + dont_explore_detection_event_sets_with_size_above=6, + dont_explore_edges_increasing_symptom_degree=False, + ) + assert len(err) == min((w + 1) // 2, h * 2 // 3) + + +@pytest.mark.parametrize("h", [3, 4, 5, 6, 7, 8, 9, 10]) +@pytest.mark.parametrize("w", [3, 4, 5, 6, 7, 8, 9, 10]) +def test_make_planar_pyramid_code_layout(w: int, h: int): + code = make_planar_pyramid_code_layout( + width=w, + height=h, + ) + code.check_commutation_relationships() + c = code.make_code_capacity_circuit(noise=1e-3) + assert len(code.patch.data_set) == len(code.patch.tiles) + max( + len(code.observables_x), len(code.observables_z) + ) + err = c.search_for_undetectable_logical_errors( + dont_explore_edges_with_degree_above=3, + dont_explore_detection_event_sets_with_size_above=6, + dont_explore_edges_increasing_symptom_degree=False, + ) + assert len(err) == min((w + 1) // 2, h * 2 // 3) diff --git a/src/clorco/rep_code/__init__.py b/src/clorco/rep_code/__init__.py new file mode 100644 index 0000000..a83514b --- /dev/null +++ b/src/clorco/rep_code/__init__.py @@ -0,0 +1,17 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ._keyed_constructions import ( + make_named_rep_code_constructions, +) diff --git a/src/clorco/rep_code/_keyed_constructions.py b/src/clorco/rep_code/_keyed_constructions.py new file mode 100644 index 0000000..c365030 --- /dev/null +++ b/src/clorco/rep_code/_keyed_constructions.py @@ -0,0 +1,139 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import functools +from typing import Callable + +import stim + +import gen +from clorco._make_circuit_params import Params +from clorco.rep_code._rep_code_circuits import make_rep_code_circuit +from clorco.rep_code._rep_code_layouts import make_rep_code_layout + + +def make_named_rep_code_constructions() -> dict[str, Callable[[Params], stim.Circuit]]: + constructions: dict[str, Callable[[Params], stim.Circuit]] = { + **_simplified_noise_rep_code_constructions(), + } + + for coloring in ["r", "rg", "rbrrr"]: + for toric in [False, True]: + prefix = "" + if toric: + prefix += "toric_" + suffix = "" if coloring == "r" else f"_{coloring}" + constructions[f"{prefix}rep_code{suffix}"] = functools.partial( + _make_circuit, coloring=coloring, toric=toric + ) + + return constructions + + +def _make_circuit( + params: Params, + *, + coloring: str, + toric: bool, +) -> stim.Circuit: + round_colorings = [] + for k in range(len(coloring)): + round_colorings.append((coloring * 2)[k : k + len(coloring)]) + circuit = make_rep_code_circuit( + distance=params.diameter, + toric=toric, + rounds=params.rounds, + round_colorings=round_colorings, + ) + + if params.debug_out_dir is not None: + code = make_rep_code_layout(distance=params.diameter, toric=toric) + code.write_svg(params.debug_out_dir / "code.svg") + gen.write_file( + params.debug_out_dir / "ideal_circuit.html", + gen.stim_circuit_html_viewer( + circuit, + patch=code.patch, + ), + ) + gen.write_file(params.debug_out_dir / "ideal_circuit.stim", circuit) + gen.write_file( + params.debug_out_dir / "ideal_circuit_dets.svg", + circuit.diagram("time+detector-slice-svg"), + ) + + if params.convert_to_cz: + circuit = gen.transpile_to_z_basis_interaction_circuit(circuit) + if params.noise_model is not None: + circuit = params.noise_model.noisy_circuit(circuit) + + if params.debug_out_dir is not None: + code = make_rep_code_layout(distance=params.diameter, toric=toric) + gen.write_file( + params.debug_out_dir / "circuit.html", + gen.stim_circuit_html_viewer( + circuit, + patch=code.patch, + ), + ) + gen.write_file(params.debug_out_dir / "circuit.stim", circuit) + gen.write_file( + params.debug_out_dir / "circuit_dets.svg", + circuit.diagram("time+detector-slice-svg"), + ) + + return circuit + + +def _simplified_noise_rep_code_constructions() -> ( + dict[str, Callable[[Params], stim.Circuit]] +): + constructions: dict[str, Callable[[Params], stim.Circuit]] = {} + + def _make_simple_circuit( + params: Params, + *, + coloring: str, + toric: bool, + phenom: bool, + ) -> stim.Circuit: + code = make_rep_code_layout( + distance=params.diameter, + coloring=coloring, + toric=toric, + ) + if phenom: + return code.make_phenom_circuit( + noise=params.noise_model, + rounds=params.rounds, + debug_out_dir=params.debug_out_dir, + ) + assert params.rounds == 1 + return code.make_code_capacity_circuit( + noise=params.noise_model.idle_noise, + debug_out_dir=params.debug_out_dir + ) + + for coloring in ["r", "rg", "rbrrr"]: + for toric in [False, True]: + for phenom in [False, True]: + prefix = "phenom_" if phenom else "transit_" + if toric: + prefix += "toric_" + suffix = "" if coloring == "r" else f"_{coloring}" + constructions[f"{prefix}rep_code{suffix}"] = functools.partial( + _make_simple_circuit, coloring=coloring, toric=toric, phenom=phenom + ) + + return constructions diff --git a/src/clorco/rep_code/_keyed_constructions_test.py b/src/clorco/rep_code/_keyed_constructions_test.py new file mode 100644 index 0000000..3fc3a78 --- /dev/null +++ b/src/clorco/rep_code/_keyed_constructions_test.py @@ -0,0 +1,125 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Any +from typing import Callable + +import pytest +import stim + +import gen +from clorco._make_circuit_params import Params +from clorco.rep_code._keyed_constructions import make_named_rep_code_constructions + + +@pytest.mark.parametrize("name,maker", make_named_rep_code_constructions().items()) +def test_rep_code_constructions(name: str, maker: Callable[[Params], stim.Circuit]): + params = Params( + style=name, + rounds=1 if "transit" in name else 5, + diameter=4, + noise_strength=1e-3, + noise_model=gen.NoiseModel.uniform_depolarizing(1e-3), + convert_to_cz=False, + editable_extras={}, + debug_out_dir=None, + ) + circuit: stim.Circuit = maker(params) + assert circuit.detector_error_model(decompose_errors=True) is not None + assert len(circuit.shortest_graphlike_error()) == 4 + + +def test_exact_construction(): + style = "rep_code_rbrrr" + params = Params( + style=style, + rounds=3, + diameter=4, + noise_strength=1e-3, + noise_model=gen.NoiseModel.uniform_depolarizing(1e-3), + convert_to_cz=False, + editable_extras={}, + debug_out_dir=None, + ) + circuit = make_named_rep_code_constructions()[style](params) + assert circuit == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + QUBIT_COORDS(1, 0) 1 + QUBIT_COORDS(2, 0) 2 + QUBIT_COORDS(3, 0) 3 + QUBIT_COORDS(0.5, 0) 4 + QUBIT_COORDS(1.5, 0) 5 + QUBIT_COORDS(2.5, 0) 6 + R 0 1 2 3 4 5 6 + X_ERROR(0.001) 0 1 2 3 4 5 6 + TICK + CX 0 4 1 5 2 6 + DEPOLARIZE2(0.001) 0 4 1 5 2 6 + DEPOLARIZE1(0.001) 3 + TICK + CX 1 4 2 5 3 6 + DEPOLARIZE2(0.001) 1 4 2 5 3 6 + DEPOLARIZE1(0.001) 0 + TICK + M(0.001) 4 5 6 + DETECTOR(0.5, 0, 0, 3) rec[-3] + DETECTOR(1.5, 0, 0, 5) rec[-2] + DETECTOR(2.5, 0, 0, 3) rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 4 5 6 0 1 2 3 + TICK + R 4 5 6 + X_ERROR(0.001) 4 5 6 + DEPOLARIZE1(0.001) 0 1 2 3 + TICK + CX 0 4 1 5 2 6 + DEPOLARIZE2(0.001) 0 4 1 5 2 6 + DEPOLARIZE1(0.001) 3 + TICK + CX 1 4 2 5 3 6 + DEPOLARIZE2(0.001) 1 4 2 5 3 6 + DEPOLARIZE1(0.001) 0 + TICK + M(0.001) 4 5 6 + DETECTOR(0.5, 0, 0, 5) rec[-6] rec[-3] + DETECTOR(1.5, 0, 0, 3) rec[-5] rec[-2] + DETECTOR(2.5, 0, 0, 3) rec[-4] rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 4 5 6 0 1 2 3 + TICK + R 4 5 6 + X_ERROR(0.001) 4 5 6 + DEPOLARIZE1(0.001) 0 1 2 3 + TICK + CX 0 4 1 5 2 6 + DEPOLARIZE2(0.001) 0 4 1 5 2 6 + DEPOLARIZE1(0.001) 3 + TICK + CX 1 4 2 5 3 6 + DEPOLARIZE2(0.001) 1 4 2 5 3 6 + DEPOLARIZE1(0.001) 0 + TICK + M(0.001) 0 1 2 3 4 5 6 + DETECTOR(0.5, 0, 0, 3) rec[-10] rec[-3] + DETECTOR(1.5, 0, 0, 3) rec[-9] rec[-2] + DETECTOR(2.5, 0, 0, 3) rec[-8] rec[-1] + SHIFT_COORDS(0, 0, 1) + DETECTOR(0.5, 0, 0, 3) rec[-7] rec[-6] rec[-3] + DETECTOR(1.5, 0, 0, 3) rec[-6] rec[-5] rec[-2] + DETECTOR(2.5, 0, 0, 3) rec[-5] rec[-4] rec[-1] + OBSERVABLE_INCLUDE(0) rec[-7] + DEPOLARIZE1(0.001) 0 1 2 3 4 5 6 + """ + ) diff --git a/src/clorco/rep_code/_rep_code_circuits.py b/src/clorco/rep_code/_rep_code_circuits.py new file mode 100644 index 0000000..e1db824 --- /dev/null +++ b/src/clorco/rep_code/_rep_code_circuits.py @@ -0,0 +1,83 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Sequence + +import stim + +import gen +from clorco.rep_code._rep_code_layouts import make_rep_code_layout + + +def make_rep_code_circuit( + *, + distance: int, + toric: bool = False, + rounds: int, + round_colorings: Sequence[str] = ("r",), +) -> stim.Circuit: + assert rounds > 1 + code = make_rep_code_layout( + distance=distance, + toric=toric, + ) + color_indices = { + "r": [3], + "g": [4], + "b": [5], + "R": [3], + "G": [4], + "B": [5], + } + + builder = gen.Builder.for_qubits(code.patch.used_set) + + for cur_round in range(rounds): + if cur_round > 0: + builder.tick() + builder.gate( + "R", code.patch.used_set if cur_round == 0 else code.patch.measure_set + ) + builder.tick() + builder.gate2("CX", [(m - 0.5, m) for m in code.patch.measure_set]) + builder.tick() + builder.gate2( + "CX", [((m.real + 0.5) % distance, m) for m in code.patch.measure_set] + ) + builder.tick() + builder.measure( + code.patch.used_set if cur_round == rounds - 1 else code.patch.measure_set, + save_layer=cur_round, + ) + for m in gen.sorted_complex(code.patch.measure_set): + m_key = gen.AtLayer(m, cur_round) + other_key = [] if cur_round == 0 else [gen.AtLayer(m, cur_round - 1)] + rc = round_colorings[cur_round % len(round_colorings)] + c = color_indices[rc[int(m.real % len(rc) - 0.5)]] + builder.detector([m_key] + other_key, pos=m, extra_coords=c) + builder.shift_coords(dt=1) + for m in gen.sorted_complex(code.patch.measure_set): + rc = round_colorings[rounds % len(round_colorings)] + c = color_indices[rc[int(m.real % len(rc) - 0.5)]] + builder.detector( + [ + gen.AtLayer(m, rounds - 1), + gen.AtLayer((m.real + 0.5) % distance, rounds - 1), + gen.AtLayer(m - 0.5, rounds - 1), + ], + pos=m, + extra_coords=c, + ) + builder.obs_include([gen.AtLayer(0, rounds - 1)], obs_index=0) + return builder.circuit diff --git a/src/clorco/rep_code/_rep_code_circuits_test.py b/src/clorco/rep_code/_rep_code_circuits_test.py new file mode 100644 index 0000000..37f8ab6 --- /dev/null +++ b/src/clorco/rep_code/_rep_code_circuits_test.py @@ -0,0 +1,43 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools + +import pytest + +import gen +from clorco.rep_code._rep_code_circuits import make_rep_code_circuit + + +@pytest.mark.parametrize( + "d,toric,rounds", + itertools.product( + [3, 4, 5, 6], + [False, True], + [3, 4, 5], + ), +) +def test_make_rep_code_circuit(d: int, toric: bool, rounds: int): + c = make_rep_code_circuit( + distance=d, + toric=toric, + rounds=rounds, + ) + c = gen.NoiseModel.uniform_depolarizing(1e-3).noisy_circuit(c) + assert c.detector_error_model(decompose_errors=True) is not None + assert len(c.shortest_graphlike_error()) == d + assert gen.count_measurement_layers(c) == rounds + assert ( + c.count_determined_measurements() == c.num_observables + c.num_detectors - toric + ) diff --git a/src/clorco/rep_code/_rep_code_layouts.py b/src/clorco/rep_code/_rep_code_layouts.py new file mode 100644 index 0000000..dfee9ce --- /dev/null +++ b/src/clorco/rep_code/_rep_code_layouts.py @@ -0,0 +1,77 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gen + + +def make_rep_code_layout( + *, + distance: int, + coloring: str = "r", + toric: bool = False, + replace_basis_with_coloring=False, +) -> gen.StabilizerCode: + """Creates a rotated surface code. + + Data qubits are at integer coordinates. Measure qubits are at half integer coordinates. + + Args: + distance: The number of data qubits. + coloring: A coloring pattern to use. Must be a non-empty string made up + of the characters 'r', 'g', and 'b'. These are the colors given to + the color code decoder, which can affect its internal representation + but ideally should not affect its final answer. + + If the coloring is shorter than the number of data qubits, it will + be repeated until it is longer. + + If the coloring is longer than the number of data qubits, it will be + truncated. + toric: Defaults to False. When True, an additional stabilizer is added + comparing the leftmost qubit to the rightmost qubit. + replace_basis_with_coloring: For debugging purposes. This causes the + stabilizer basis to be XYZ=RGB instead of always Z, so that a + drawing of the code shows the coloring. + + Returns: + A StabilizerCode object defining the stabilizers and X/Z observable pair of the code. + """ + assert distance > 1 + + tiles = [] + color_indices = { + "r": 3, + "g": 4, + "b": 5, + "R": 3, + "G": 4, + "B": 5, + } + for x in range(distance - (0 if toric else 1)): + c = color_indices[coloring[x % len(coloring)]] + tiles.append( + gen.Tile( + ordered_data_qubits=[x, (x + 1) % distance], + bases="XYZ"[c % 3] if replace_basis_with_coloring else "Z", + measurement_qubit=x + 0.5, + extra_coords=[c], + ) + ) + patch = gen.Patch(tiles) + + return gen.StabilizerCode( + patch=patch, + observables_x=[], + observables_z=[gen.PauliString({0: "Z"})], + ) diff --git a/src/clorco/rep_code/_rep_code_layouts_test.py b/src/clorco/rep_code/_rep_code_layouts_test.py new file mode 100644 index 0000000..e3cb7e0 --- /dev/null +++ b/src/clorco/rep_code/_rep_code_layouts_test.py @@ -0,0 +1,86 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gen +from clorco.rep_code._rep_code_layouts import make_rep_code_layout + + +def test_make_rep_code_layout(): + v = make_rep_code_layout(distance=5, coloring="rgb") + v.check_commutation_relationships() + assert v == gen.StabilizerCode( + patch=gen.Patch( + tiles=[ + gen.Tile( + ordered_data_qubits=(0, 1), + measurement_qubit=0.5, + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=(1, 2), + measurement_qubit=1.5, + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=(2, 3), + measurement_qubit=2.5, + bases="Z", + extra_coords=(5,), + ), + gen.Tile( + ordered_data_qubits=(3, 4), + measurement_qubit=3.5, + bases="Z", + extra_coords=(3,), + ), + ] + ), + observables_x=[], + observables_z=[ + gen.PauliString(qubits={0: "Z"}), + ], + ) + + v = make_rep_code_layout(distance=3, coloring="rg", toric=True) + v.check_commutation_relationships() + assert v == gen.StabilizerCode( + patch=gen.Patch( + tiles=[ + gen.Tile( + ordered_data_qubits=(0, 1), + measurement_qubit=0.5, + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=(1, 2), + measurement_qubit=1.5, + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=(2, 0), + measurement_qubit=2.5, + bases="Z", + extra_coords=(3,), + ), + ] + ), + observables_x=[], + observables_z=[ + gen.PauliString(qubits={0: "Z"}), + ], + ) diff --git a/src/clorco/surface_code/__init__.py b/src/clorco/surface_code/__init__.py new file mode 100644 index 0000000..68942d0 --- /dev/null +++ b/src/clorco/surface_code/__init__.py @@ -0,0 +1,17 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ._keyed_constructions import ( + make_named_surface_code_constructions, +) diff --git a/src/clorco/surface_code/_keyed_constructions.py b/src/clorco/surface_code/_keyed_constructions.py new file mode 100644 index 0000000..5dc7e6a --- /dev/null +++ b/src/clorco/surface_code/_keyed_constructions.py @@ -0,0 +1,244 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Callable + +import stim + +import gen +from clorco._make_circuit_params import Params +from clorco.surface_code._surface_code_layouts import ( + make_surface_code_layout, + make_toric_surface_code_layout, +) +from clorco.surface_code._transversal_cnot import ( + make_transversal_cnot_surface_code_circuit, +) +from clorco.surface_code._xz_surface_code_memory_circuits import ( + make_xz_memory_experiment_chunks, +) + + +def make_named_surface_code_constructions() -> ( + dict[str, Callable[[Params], stim.Circuit]] +): + constructions: dict[str, Callable[[Params], stim.Circuit]] = { + **_simplified_noise_surface_code_constructions(), + } + + constructions["surface_code_X"] = lambda params: _chunks_to_circuit( + params, + make_xz_memory_experiment_chunks( + basis="X", + diameter=params.diameter, + rounds=params.rounds, + ), + ) + constructions["surface_code_Z"] = lambda params: _chunks_to_circuit( + params, + make_xz_memory_experiment_chunks( + basis="Z", + diameter=params.diameter, + rounds=params.rounds, + ), + ) + + constructions[ + "surface_code_trans_cx_X" + ] = lambda params: make_transversal_cnot_surface_code_circuit( + diameter=params.diameter, + basis="X", + pad_rounds=params.rounds, + noise=params.noise_model, + convert_to_z=params.convert_to_cz, + ) + constructions[ + "surface_code_trans_cx_Z" + ] = lambda params: make_transversal_cnot_surface_code_circuit( + diameter=params.diameter, + basis="Z", + pad_rounds=params.rounds, + noise=params.noise_model, + convert_to_z=params.convert_to_cz, + ) + constructions[ + "surface_code_trans_cx_magicEPR" + ] = lambda params: make_transversal_cnot_surface_code_circuit( + diameter=params.diameter, + basis="MagicEPR", + pad_rounds=params.rounds, + noise=params.noise_model, + convert_to_z=params.convert_to_cz, + ) + + return constructions + + +def _chunks_to_circuit(params: Params, chunks: list[gen.Chunk]) -> stim.Circuit: + assert len(chunks) >= 2 + if "magic" not in params.style: + assert not any(chunk.magic for chunk in chunks) + + if params.debug_out_dir is not None: + patches = [chunk.end_patch() for chunk in chunks[:-1]] + changed_patches = [ + patches[k] + for k in range(len(patches)) + if k == 0 or patches[k] != patches[k - 1] + ] + allowed_qubits = {q for patch in changed_patches for q in patch.used_set} + gen.write_file( + params.debug_out_dir / "patch.svg", + gen.patch_svg_viewer( + changed_patches, + show_order=False, + available_qubits=allowed_qubits, + ), + ) + + if params.debug_out_dir is not None: + ignore_errors_ideal_circuit = gen.compile_chunks_into_circuit( + chunks, ignore_errors=True + ) + patch_dict = {} + cur_tick = 0 + last_patch = gen.Patch([]) + if chunks[0].start_patch() != last_patch: + patch_dict[0] = chunks[0].start_patch() + last_patch = chunks[0].start_patch() + cur_tick += 1 + + for c in gen.ChunkLoop(chunks, repetitions=1).flattened(): + cur_tick += c.tick_count() + if c.end_patch() != last_patch: + patch_dict[cur_tick] = c.end_patch() + last_patch = c.end_patch() + cur_tick += 1 + gen.write_file( + params.debug_out_dir / "ideal_circuit.html", + gen.stim_circuit_html_viewer( + ignore_errors_ideal_circuit, + patch=patch_dict, + ), + ) + gen.write_file( + params.debug_out_dir / "ideal_circuit.stim", ignore_errors_ideal_circuit + ) + gen.write_file( + params.debug_out_dir / "ideal_circuit_dets.svg", + ignore_errors_ideal_circuit.diagram("time+detector-slice-svg"), + ) + + body = gen.compile_chunks_into_circuit(chunks) + mpp_indices = [ + k + for k, inst in enumerate(body) + if isinstance(inst, stim.CircuitInstruction) and inst.name == "MPP" + ] + skip_mpp_head = chunks[0].magic + skip_mpp_tail = chunks[-1].magic + body_start = mpp_indices[0] + 2 if skip_mpp_head else 0 + body_end = mpp_indices[-1] if skip_mpp_tail else len(body) + magic_head = body[:body_start] + magic_tail = body[body_end:] + body = body[body_start:body_end] + + if params.convert_to_cz: + body = gen.transpile_to_z_basis_interaction_circuit(body) + if params.debug_out_dir is not None: + ideal_circuit = magic_head + body + magic_tail + gen.write_file( + params.debug_out_dir / "ideal_cz_circuit.html", + gen.stim_circuit_html_viewer( + ideal_circuit, + patch=chunks[0].end_patch(), + ), + ) + gen.write_file( + params.debug_out_dir / "ideal_cz_circuit.stim", ideal_circuit + ) + gen.write_file( + params.debug_out_dir / "ideal_cz_circuit_dets.svg", + ideal_circuit.diagram("time+detector-slice-svg"), + ) + + if params.noise_model is not None: + body = params.noise_model.noisy_circuit(body) + noisy_circuit = magic_head + body + magic_tail + + if params.debug_out_dir is not None: + gen.write_file( + params.debug_out_dir / "noisy_circuit.html", + gen.stim_circuit_html_viewer( + noisy_circuit, + patch=chunks[0].end_patch(), + ), + ) + + return noisy_circuit + + +def _simplified_noise_surface_code_constructions() -> ( + dict[str, Callable[[Params], stim.Circuit]] +): + constructions: dict[str, Callable[[Params], stim.Circuit]] = {} + + def _make_simple_circuit( + params: Params, *, code: gen.StabilizerCode, phenom: bool + ) -> stim.Circuit: + if phenom: + return code.make_phenom_circuit( + noise=params.noise_model, + rounds=params.rounds, + debug_out_dir=params.debug_out_dir, + ) + assert params.rounds == 1 + return code.make_code_capacity_circuit( + noise=params.noise_model.idle_noise, + debug_out_dir=params.debug_out_dir + ) + + constructions["transit_surface_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_surface_code_layout( + width=params.diameter, + height=params.diameter, + ), + phenom=False, + ) + constructions["phenom_surface_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_surface_code_layout( + width=params.diameter, + height=params.diameter, + ), + phenom=True, + ) + constructions["transit_toric_surface_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_toric_surface_code_layout( + width=params.diameter, + height=params.diameter, + ), + phenom=False, + ) + constructions["phenom_toric_surface_code"] = lambda params: _make_simple_circuit( + params=params, + code=make_toric_surface_code_layout( + width=params.diameter, + height=params.diameter, + ), + phenom=True, + ) + return constructions diff --git a/src/clorco/surface_code/_surface_code_chunks.py b/src/clorco/surface_code/_surface_code_chunks.py new file mode 100644 index 0000000..f1bf4c1 --- /dev/null +++ b/src/clorco/surface_code/_surface_code_chunks.py @@ -0,0 +1,193 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Literal +from typing import Any + +import gen + + +def build_surface_code_round_circuit( + patch: gen.Patch, + *, + init_data_basis: None | Literal["X", "Y", "Z"] | dict[complex, Literal["X", "Y", "Z"]] = None, + measure_data_basis: None | Literal["X", "Y", "Z"] | dict[complex, Literal["X", "Y", "Z"]] = None, + save_layer: Any, + out: gen.Builder, +): + measure_xs = gen.Patch([tile for tile in patch.tiles if tile.basis == "X"]) + measure_zs = gen.Patch([tile for tile in patch.tiles if tile.basis == "Z"]) + if init_data_basis is None: + init_data_basis = {} + elif isinstance(init_data_basis, str): + init_data_basis = {q: init_data_basis for q in patch.data_set} + if measure_data_basis is None: + measure_data_basis = {} + elif isinstance(measure_data_basis, str): + measure_data_basis = {q: measure_data_basis for q in patch.data_set} + + out.gate("RX", measure_xs.measure_set) + for basis in "XYZ": + qs = [q for q in init_data_basis if init_data_basis[q] == basis] + if qs: + out.gate(f"R{basis}", qs) + out.gate("R", measure_zs.measure_set) + out.tick() + + (num_layers,) = {len(tile.ordered_data_qubits) for tile in patch.tiles} + for k in range(num_layers): + out.gate2( + "CX", + [ + (tile.measurement_qubit, tile.ordered_data_qubits[k])[ + :: -1 if tile.basis == "Z" else +1 + ] + for tile in patch.tiles + if tile.ordered_data_qubits[k] is not None + ], + ) + out.tick() + + out.measure(measure_xs.measure_set, basis="X", save_layer=save_layer) + for basis in "XYZ": + qs = [q for q in measure_data_basis if measure_data_basis[q] == basis] + if qs: + out.measure(qs, basis=basis, save_layer=save_layer) + out.measure(measure_zs.measure_set, basis="Z", save_layer=save_layer) + + +def standard_surface_code_chunk( + patch: gen.Patch, + *, + init_data_basis: None | str | dict[complex, str] = None, + measure_data_basis: None | str | dict[complex, str] = None, + obs: gen.PauliString | None = None, +) -> gen.Chunk: + if init_data_basis is None: + init_data_basis = {} + elif isinstance(init_data_basis, str): + init_data_basis = {q: init_data_basis for q in patch.data_set} + if measure_data_basis is None: + measure_data_basis = {} + elif isinstance(measure_data_basis, str): + measure_data_basis = {q: measure_data_basis for q in patch.data_set} + + out = gen.Builder.for_qubits(patch.used_set) + save_layer = "solo" + build_surface_code_round_circuit( + patch=patch, + init_data_basis=init_data_basis, + measure_data_basis=measure_data_basis, + save_layer=save_layer, + out=out, + ) + + discarded_inputs = [] + discarded_outputs = [] + flows = [] + for tile in patch.tiles: + from_prev = gen.PauliString( + { + q: b + for q, b in zip(tile.ordered_data_qubits, tile.bases) + if q is not None and q not in init_data_basis + } + ) + if any( + init_data_basis.get(q, b) != b + for q, b in zip(tile.ordered_data_qubits, tile.bases) + ): + # Stabilizer anticommutes with a reset. Not prepared. + if from_prev: + discarded_inputs.append(from_prev) + continue + flows.append( + gen.Flow( + center=tile.measurement_qubit, + start=from_prev, + measurement_indices=out.tracker.measurement_indices( + [gen.AtLayer(tile.measurement_qubit, save_layer)] + ), + additional_coords=[ + (tile.measurement_qubit.real % 2 == 0.5) + 3 * (tile.basis == "Z") + ], + ) + ) + + for tile in patch.tiles: + to_next = gen.PauliString( + { + q: b + for q, b in zip(tile.ordered_data_qubits, tile.bases) + if q is not None and q not in measure_data_basis + } + ) + if any( + measure_data_basis.get(q, b) != b + for q, b in zip(tile.ordered_data_qubits, tile.bases) + ): + # Stabilizer anticommutes with a reset. Not prepared. + if to_next: + discarded_outputs.append(to_next) + continue + flows.append( + gen.Flow( + center=tile.measurement_qubit, + end=to_next, + measurement_indices=out.tracker.measurement_indices( + [ + gen.AtLayer(q, save_layer) + for q in tile.used_set + if q in measure_data_basis or q == tile.measurement_qubit + ] + ), + additional_coords=[ + (tile.measurement_qubit.real % 2 == 0.5) + 3 * (tile.basis == "Z") + ], + ) + ) + + if obs is not None: + start_obs = dict(obs.qubits) + end_obs = dict(obs.qubits) + for q in init_data_basis: + if q in start_obs: + if start_obs.pop(q) != init_data_basis[q]: + raise ValueError("wrong init basis for obs") + measure_indices = [] + for q in measure_data_basis: + if q in end_obs: + if end_obs.pop(q) != measure_data_basis[q]: + raise ValueError("wrong measure basis for obs") + measure_indices.extend( + out.tracker.measurement_indices([gen.AtLayer(q, save_layer)]) + ) + + flows.append( + gen.Flow( + center=0, + start=gen.PauliString(start_obs), + end=gen.PauliString(end_obs), + obs_index=0, + measurement_indices=measure_indices, + ) + ) + + return gen.Chunk( + circuit=out.circuit, + q2i=out.q2i, + flows=flows, + discarded_inputs=discarded_inputs, + discarded_outputs=discarded_outputs, + ) diff --git a/src/clorco/surface_code/_surface_code_chunks_test.py b/src/clorco/surface_code/_surface_code_chunks_test.py new file mode 100644 index 0000000..570f145 --- /dev/null +++ b/src/clorco/surface_code/_surface_code_chunks_test.py @@ -0,0 +1,180 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +import gen +from clorco.surface_code._surface_code_chunks import standard_surface_code_chunk +from clorco.surface_code._surface_code_patches import make_xtop_qubit_patch + + +def test_magic_init_surface_code_chunk(): + p = make_xtop_qubit_patch(diameter=3) + obs = gen.PauliString({0: "X", 1j: "X", 2j: "X"}) + c = standard_surface_code_chunk(p, obs=obs) + c2 = c.magic_init_chunk() + c2.verify() + c3 = c.magic_end_chunk() + c3.verify() + assert gen.compile_chunks_into_circuit([c2, c3]) == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + QUBIT_COORDS(0, 1) 1 + QUBIT_COORDS(0, 2) 2 + QUBIT_COORDS(1, 0) 3 + QUBIT_COORDS(1, 1) 4 + QUBIT_COORDS(1, 2) 5 + QUBIT_COORDS(2, 0) 6 + QUBIT_COORDS(2, 1) 7 + QUBIT_COORDS(2, 2) 8 + QUBIT_COORDS(-0.5, 1.5) 9 + QUBIT_COORDS(0.5, -0.5) 10 + QUBIT_COORDS(0.5, 0.5) 11 + QUBIT_COORDS(0.5, 1.5) 12 + QUBIT_COORDS(1.5, 0.5) 13 + QUBIT_COORDS(1.5, 1.5) 14 + QUBIT_COORDS(1.5, 2.5) 15 + QUBIT_COORDS(2.5, 0.5) 16 + MPP Z1*Z2 X0*X3 Z0*Z1*Z3*Z4 X1*X2*X4*X5 X3*X4*X6*X7 Z4*Z5*Z7*Z8 X5*X8 Z6*Z7 X0*X1*X2 + OBSERVABLE_INCLUDE(0) rec[-1] + TICK + MPP Z1*Z2 X0*X3 Z0*Z1*Z3*Z4 X1*X2*X4*X5 X3*X4*X6*X7 Z4*Z5*Z7*Z8 X5*X8 Z6*Z7 X0*X1*X2 + DETECTOR(-0.5, 1.5, 0, 3) rec[-18] rec[-9] + DETECTOR(0.5, -0.5, 0, 1) rec[-17] rec[-8] + DETECTOR(0.5, 0.5, 0, 4) rec[-16] rec[-7] + DETECTOR(0.5, 1.5, 0, 1) rec[-15] rec[-6] + DETECTOR(1.5, 0.5, 0, 0) rec[-14] rec[-5] + DETECTOR(1.5, 1.5, 0, 3) rec[-13] rec[-4] + DETECTOR(1.5, 2.5, 0, 0) rec[-12] rec[-3] + DETECTOR(2.5, 0.5, 0, 4) rec[-11] rec[-2] + OBSERVABLE_INCLUDE(0) rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + """ + ) + + +def test_verify_normal_surface_code_chunk(): + p = make_xtop_qubit_patch(diameter=3) + obs = gen.PauliString({0: "X", 1j: "X", 2j: "X"}) + c1 = standard_surface_code_chunk(p, init_data_basis="X", obs=obs) + c2 = standard_surface_code_chunk(p, obs=obs) + c3 = standard_surface_code_chunk(p, measure_data_basis="X", obs=obs) + c4 = standard_surface_code_chunk(p, init_data_basis="X", measure_data_basis="X") + c1.verify() + c2.verify() + c3.verify() + c4.verify() + circuit = gen.compile_chunks_into_circuit([c1, c2, c3]) + circuit.detector_error_model(decompose_errors=True) + assert ( + len( + gen.NoiseModel.uniform_depolarizing(1e-3) + .noisy_circuit(circuit) + .shortest_graphlike_error() + ) + == 3 + ) + + assert circuit == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + QUBIT_COORDS(0, 1) 1 + QUBIT_COORDS(0, 2) 2 + QUBIT_COORDS(1, 0) 3 + QUBIT_COORDS(1, 1) 4 + QUBIT_COORDS(1, 2) 5 + QUBIT_COORDS(2, 0) 6 + QUBIT_COORDS(2, 1) 7 + QUBIT_COORDS(2, 2) 8 + QUBIT_COORDS(-0.5, 1.5) 9 + QUBIT_COORDS(0.5, -0.5) 10 + QUBIT_COORDS(0.5, 0.5) 11 + QUBIT_COORDS(0.5, 1.5) 12 + QUBIT_COORDS(1.5, 0.5) 13 + QUBIT_COORDS(1.5, 1.5) 14 + QUBIT_COORDS(1.5, 2.5) 15 + QUBIT_COORDS(2.5, 0.5) 16 + RX 10 12 13 15 0 1 2 3 4 5 6 7 8 + R 9 11 14 16 + TICK + CX 1 9 3 11 7 14 12 4 13 6 15 8 + TICK + CX 2 9 4 11 8 14 12 1 13 3 15 5 + TICK + CX 0 11 4 14 6 16 10 3 12 5 13 7 + TICK + CX 1 11 5 14 7 16 10 0 12 2 13 4 + TICK + MX 10 12 13 15 + M 9 11 14 16 + DETECTOR(0.5, -0.5, 0, 1) rec[-8] + DETECTOR(0.5, 1.5, 0, 1) rec[-7] + DETECTOR(1.5, 0.5, 0, 0) rec[-6] + DETECTOR(1.5, 2.5, 0, 0) rec[-5] + SHIFT_COORDS(0, 0, 1) + TICK + RX 10 12 13 15 + R 9 11 14 16 + TICK + CX 1 9 3 11 7 14 12 4 13 6 15 8 + TICK + CX 2 9 4 11 8 14 12 1 13 3 15 5 + TICK + CX 0 11 4 14 6 16 10 3 12 5 13 7 + TICK + CX 1 11 5 14 7 16 10 0 12 2 13 4 + TICK + MX 10 12 13 15 + M 9 11 14 16 + DETECTOR(-0.5, 1.5, 0, 3) rec[-12] rec[-4] + DETECTOR(0.5, -0.5, 0, 1) rec[-16] rec[-8] + DETECTOR(0.5, 0.5, 0, 4) rec[-11] rec[-3] + DETECTOR(0.5, 1.5, 0, 1) rec[-15] rec[-7] + DETECTOR(1.5, 0.5, 0, 0) rec[-14] rec[-6] + DETECTOR(1.5, 1.5, 0, 3) rec[-10] rec[-2] + DETECTOR(1.5, 2.5, 0, 0) rec[-13] rec[-5] + DETECTOR(2.5, 0.5, 0, 4) rec[-9] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + RX 10 12 13 15 + R 9 11 14 16 + TICK + CX 1 9 3 11 7 14 12 4 13 6 15 8 + TICK + CX 2 9 4 11 8 14 12 1 13 3 15 5 + TICK + CX 0 11 4 14 6 16 10 3 12 5 13 7 + TICK + CX 1 11 5 14 7 16 10 0 12 2 13 4 + TICK + MX 10 12 13 15 0 1 2 3 4 5 6 7 8 + M 9 11 14 16 + DETECTOR(-0.5, 1.5, 0, 3) rec[-21] rec[-4] + DETECTOR(0.5, -0.5, 0, 1) rec[-25] rec[-17] + DETECTOR(0.5, 0.5, 0, 4) rec[-20] rec[-3] + DETECTOR(0.5, 1.5, 0, 1) rec[-24] rec[-16] + DETECTOR(1.5, 0.5, 0, 0) rec[-23] rec[-15] + DETECTOR(1.5, 1.5, 0, 3) rec[-19] rec[-2] + DETECTOR(1.5, 2.5, 0, 0) rec[-22] rec[-14] + DETECTOR(2.5, 0.5, 0, 4) rec[-18] rec[-1] + DETECTOR(0.5, -0.5, 0, 1) rec[-17] rec[-13] rec[-10] + DETECTOR(0.5, 1.5, 0, 1) rec[-16] rec[-12] rec[-11] rec[-9] rec[-8] + DETECTOR(1.5, 0.5, 0, 0) rec[-15] rec[-10] rec[-9] rec[-7] rec[-6] + DETECTOR(1.5, 2.5, 0, 0) rec[-14] rec[-8] rec[-5] + OBSERVABLE_INCLUDE(0) rec[-13] rec[-12] rec[-11] + SHIFT_COORDS(0, 0, 1) + TICK + """ + ) diff --git a/src/clorco/surface_code/_surface_code_layouts.py b/src/clorco/surface_code/_surface_code_layouts.py new file mode 100644 index 0000000..00aa3e0 --- /dev/null +++ b/src/clorco/surface_code/_surface_code_layouts.py @@ -0,0 +1,116 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gen + + +def make_surface_code_layout( + *, + width: int, + height: int, +) -> gen.StabilizerCode: + """Creates a rotated surface code. + + Data qubits are at integer coordinates. Measure qubits are at half integer coordinates. + + Args: + width: width of the patch measured in data qubits. + height: height of the patch measured in data qubits. + + Returns: + A StabilizerCode object defining the stabilizers and X/Z observable pair of the code. + """ + tiles = [] + for x in range(-1, width + 1): + for y in range(-1, height + 1): + m = x + 1j * y + 0.5 + 0.5j + b = "XZ"[(x + y) % 2] + if not (0 < m.real < width - 1) and b == "X": + continue + if not (0 < m.imag < height - 1) and b == "Z": + continue + order = gen.Order_Z if b == "X" else gen.Order_ᴎ + data_qubits = [m + d for d in order] + tile = gen.Tile( + ordered_data_qubits=[ + (d if 0 <= d.real < width and 0 <= d.imag < height else None) + for d in data_qubits + ], + bases=b, + measurement_qubit=m, + extra_coords=["XZ".index(b) * 3 + (x % 2) * 2], + ) + if sum(e is not None for e in tile.ordered_data_qubits) > 0: + tiles.append(tile) + patch = gen.Patch(tiles) + + return gen.StabilizerCode( + patch=patch, + observables_x=[ + gen.PauliString({q: "X" for q in patch.data_set if q.real == 0}) + ], + observables_z=[ + gen.PauliString({q: "Z" for q in patch.data_set if q.imag == 0}) + ], + ) + + +def make_toric_surface_code_layout( + *, + width: int, + height: int, +) -> gen.StabilizerCode: + """Creates a rotated toric surface code. + + Data qubits are at integer coordinates. Measure qubits are at half integer coordinates. + + Args: + width: width of the patch measured in data qubits. + height: height of the patch measured in data qubits. + + Returns: + A StabilizerCode object defining the stabilizers and X/Z observable pair of the code. + """ + if width % 2 != 0 or height % 2 != 0: + raise ValueError(f"{width=} and {height=} must be even") + + def wrap(c: complex) -> complex: + return (c.real % width) + 1j * (c.imag % height) + + tiles = [] + for x in range(width): + for y in range(height): + m = wrap(x + 1j * y + 0.5 + 0.5j) + b = "XZ"[(x + y) % 2] + order = gen.Order_ᴎ if b == "X" else gen.Order_Z + tiles.append( + gen.Tile( + ordered_data_qubits=[wrap(m + d) for d in order], + bases=b, + measurement_qubit=m, + extra_coords=["XZ".index(b) * 3 + x % 2], + ) + ) + patch = gen.Patch(tiles) + return gen.StabilizerCode( + patch=patch, + observables_x=[ + gen.PauliString({q: "X" for q in patch.data_set if q.real == 0}), + gen.PauliString({q: "X" for q in patch.data_set if q.imag == 0}), + ], + observables_z=[ + gen.PauliString({q: "Z" for q in patch.data_set if q.imag == 0}), + gen.PauliString({q: "Z" for q in patch.data_set if q.real == 0}), + ], + ) diff --git a/src/clorco/surface_code/_surface_code_layouts_test.py b/src/clorco/surface_code/_surface_code_layouts_test.py new file mode 100644 index 0000000..6a250c7 --- /dev/null +++ b/src/clorco/surface_code/_surface_code_layouts_test.py @@ -0,0 +1,257 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gen +from clorco.surface_code._surface_code_layouts import ( + make_surface_code_layout, + make_toric_surface_code_layout, +) + + +def test_make_surface_code_layout(): + code = make_surface_code_layout( + width=3, + height=4, + ) + assert len(code.observables_x) == len(code.observables_z) == 1 + code.check_commutation_relationships() + assert ( + len(code.make_code_capacity_circuit(noise=1e-3).shortest_graphlike_error()) == 3 + ) + assert code.patch.tiles == ( + gen.Tile( + ordered_data_qubits=(None, None, 0j, 1j), + measurement_qubit=(-0.5 + 0.5j), + bases="Z", + extra_coords=(5,), + ), + gen.Tile( + ordered_data_qubits=(None, None, 2j, 3j), + measurement_qubit=(-0.5 + 2.5j), + bases="Z", + extra_coords=(5,), + ), + gen.Tile( + ordered_data_qubits=(0j, (1 + 0j), 1j, (1 + 1j)), + measurement_qubit=(0.5 + 0.5j), + bases="X", + extra_coords=(0,), + ), + gen.Tile( + ordered_data_qubits=(1j, 2j, (1 + 1j), (1 + 2j)), + measurement_qubit=(0.5 + 1.5j), + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=(2j, (1 + 2j), 3j, (1 + 3j)), + measurement_qubit=(0.5 + 2.5j), + bases="X", + extra_coords=(0,), + ), + gen.Tile( + ordered_data_qubits=(None, None, (1 + 0j), (2 + 0j)), + measurement_qubit=(1.5 - 0.5j), + bases="X", + extra_coords=(2,), + ), + gen.Tile( + ordered_data_qubits=((1 + 0j), (1 + 1j), (2 + 0j), (2 + 1j)), + measurement_qubit=(1.5 + 0.5j), + bases="Z", + extra_coords=(5,), + ), + gen.Tile( + ordered_data_qubits=((1 + 1j), (2 + 1j), (1 + 2j), (2 + 2j)), + measurement_qubit=(1.5 + 1.5j), + bases="X", + extra_coords=(2,), + ), + gen.Tile( + ordered_data_qubits=((1 + 2j), (1 + 3j), (2 + 2j), (2 + 3j)), + measurement_qubit=(1.5 + 2.5j), + bases="Z", + extra_coords=(5,), + ), + gen.Tile( + ordered_data_qubits=((1 + 3j), (2 + 3j), None, None), + measurement_qubit=(1.5 + 3.5j), + bases="X", + extra_coords=(2,), + ), + gen.Tile( + ordered_data_qubits=((2 + 1j), (2 + 2j), None, None), + measurement_qubit=(2.5 + 1.5j), + bases="Z", + extra_coords=(3,), + ), + ) + + +def test_make_toric_surface_code_layout(): + code = make_toric_surface_code_layout( + width=4, + height=6, + ) + assert len(code.observables_x) == len(code.observables_z) == 2 + code.check_commutation_relationships() + assert ( + len(code.make_code_capacity_circuit(noise=1e-3).shortest_graphlike_error()) == 4 + ) + assert code.patch.tiles == ( + gen.Tile( + ordered_data_qubits=(0j, 1j, (1 + 0j), (1 + 1j)), + measurement_qubit=(0.5 + 0.5j), + bases="X", + extra_coords=(0,), + ), + gen.Tile( + ordered_data_qubits=(1j, (1 + 1j), 2j, (1 + 2j)), + measurement_qubit=(0.5 + 1.5j), + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=(2j, 3j, (1 + 2j), (1 + 3j)), + measurement_qubit=(0.5 + 2.5j), + bases="X", + extra_coords=(0,), + ), + gen.Tile( + ordered_data_qubits=(3j, (1 + 3j), 4j, (1 + 4j)), + measurement_qubit=(0.5 + 3.5j), + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=(4j, 5j, (1 + 4j), (1 + 5j)), + measurement_qubit=(0.5 + 4.5j), + bases="X", + extra_coords=(0,), + ), + gen.Tile( + ordered_data_qubits=(5j, (1 + 5j), 0j, (1 + 0j)), + measurement_qubit=(0.5 + 5.5j), + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=((1 + 0j), (2 + 0j), (1 + 1j), (2 + 1j)), + measurement_qubit=(1.5 + 0.5j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=((1 + 1j), (1 + 2j), (2 + 1j), (2 + 2j)), + measurement_qubit=(1.5 + 1.5j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=((1 + 2j), (2 + 2j), (1 + 3j), (2 + 3j)), + measurement_qubit=(1.5 + 2.5j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=((1 + 3j), (1 + 4j), (2 + 3j), (2 + 4j)), + measurement_qubit=(1.5 + 3.5j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=((1 + 4j), (2 + 4j), (1 + 5j), (2 + 5j)), + measurement_qubit=(1.5 + 4.5j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=((1 + 5j), (1 + 0j), (2 + 5j), (2 + 0j)), + measurement_qubit=(1.5 + 5.5j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=((2 + 0j), (2 + 1j), (3 + 0j), (3 + 1j)), + measurement_qubit=(2.5 + 0.5j), + bases="X", + extra_coords=(0,), + ), + gen.Tile( + ordered_data_qubits=((2 + 1j), (3 + 1j), (2 + 2j), (3 + 2j)), + measurement_qubit=(2.5 + 1.5j), + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=((2 + 2j), (2 + 3j), (3 + 2j), (3 + 3j)), + measurement_qubit=(2.5 + 2.5j), + bases="X", + extra_coords=(0,), + ), + gen.Tile( + ordered_data_qubits=((2 + 3j), (3 + 3j), (2 + 4j), (3 + 4j)), + measurement_qubit=(2.5 + 3.5j), + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=((2 + 4j), (2 + 5j), (3 + 4j), (3 + 5j)), + measurement_qubit=(2.5 + 4.5j), + bases="X", + extra_coords=(0,), + ), + gen.Tile( + ordered_data_qubits=((2 + 5j), (3 + 5j), (2 + 0j), (3 + 0j)), + measurement_qubit=(2.5 + 5.5j), + bases="Z", + extra_coords=(3,), + ), + gen.Tile( + ordered_data_qubits=((3 + 0j), 0j, (3 + 1j), 1j), + measurement_qubit=(3.5 + 0.5j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=((3 + 1j), (3 + 2j), 1j, 2j), + measurement_qubit=(3.5 + 1.5j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=((3 + 2j), 2j, (3 + 3j), 3j), + measurement_qubit=(3.5 + 2.5j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=((3 + 3j), (3 + 4j), 3j, 4j), + measurement_qubit=(3.5 + 3.5j), + bases="X", + extra_coords=(1,), + ), + gen.Tile( + ordered_data_qubits=((3 + 4j), 4j, (3 + 5j), 5j), + measurement_qubit=(3.5 + 4.5j), + bases="Z", + extra_coords=(4,), + ), + gen.Tile( + ordered_data_qubits=((3 + 5j), (3 + 0j), 5j, 0j), + measurement_qubit=(3.5 + 5.5j), + bases="X", + extra_coords=(1,), + ), + ) diff --git a/src/clorco/surface_code/_surface_code_patches.py b/src/clorco/surface_code/_surface_code_patches.py new file mode 100644 index 0000000..5f990ce --- /dev/null +++ b/src/clorco/surface_code/_surface_code_patches.py @@ -0,0 +1,155 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import functools +from typing import Iterable, Callable + +import gen + +DIRS = tuple((0.5 + 0.5j) * 1j**d for d in range(4)) +DR, DL, UL, UR = DIRS +ORDER_S = [UR, UL, DR, DL] +ORDER_N = [UR, DR, UL, DL] + + +def surface_code_patch( + *, + possible_data_qubits: Iterable[complex], + basis: Callable[[complex], str], + is_boundary_x: Callable[[complex], bool], + is_boundary_z: Callable[[complex], bool], + order_func: Callable[[complex], Iterable[complex | None]], + dirs: Iterable[complex] = DIRS, +) -> gen.Patch: + possible_data_qubits = set(possible_data_qubits) + possible_measure_qubits = {q + d for q in possible_data_qubits for d in dirs} + measure_qubits = { + m + for m in possible_measure_qubits + if sum(m + d in possible_data_qubits for d in dirs) > 1 + if is_boundary_x(m) <= (basis(m) == "X") + if is_boundary_z(m) <= (basis(m) == "Z") + } + data_qubits = { + q + for q in possible_data_qubits + if sum(q + d in measure_qubits for d in dirs) > 1 + } + + tiles = [] + for m in measure_qubits: + tiles.append( + gen.Tile( + bases=basis(m), + measurement_qubit=m, + ordered_data_qubits=[ + m + d if d is not None and m + d in data_qubits else None + for d in order_func(m) + ], + ) + ) + return gen.Patch(tiles) + + +def rectangular_surface_code_patch( + *, + width: int, + height: int, + top_basis: str, + bot_basis: str, + left_basis: str, + right_basis: str, + order_func: Callable[[complex], Iterable[complex | None]], +) -> gen.Patch: + def is_boundary(m: complex, *, b: str) -> bool: + if top_basis == b and m.imag == -0.5: + return True + if left_basis == b and m.real == -0.5: + return True + if bot_basis == b and m.imag == height - 0.5: + return True + if right_basis == b and m.real == width - 0.5: + return True + return False + + return surface_code_patch( + possible_data_qubits=[x + 1j * y for x in range(width) for y in range(height)], + basis=gen.checkerboard_basis, + is_boundary_x=functools.partial(is_boundary, b="X"), + is_boundary_z=functools.partial(is_boundary, b="Z"), + order_func=order_func, + ) + + +def rectangular_unrotated_surface_code_patch( + *, + width: int, + height: int, + order_func: Callable[[complex], Iterable[complex | None]], +) -> gen.Patch: + return surface_code_patch( + possible_data_qubits=[ + x + 1j * y + for x in range(width * 2 - 1) + for y in range(height * 2 - 1) + if x % 2 == y % 2 + ], + basis=lambda m: "X" if m.imag % 2 == 0 else "Z", + is_boundary_x=lambda _: False, + is_boundary_z=lambda _: False, + order_func=order_func, + dirs=[1, -1, 1j, -1j], + ) + + +def make_ztop_yboundary_patch(*, distance: int) -> gen.Patch: + def order_func(m: complex) -> list[complex]: + if m.real > m.imag and False: + if gen.checkerboard_basis(m) == "X": + return ORDER_N + else: + return ORDER_S + else: + if gen.checkerboard_basis(m) == "X": + return ORDER_S + else: + return ORDER_N + + return rectangular_surface_code_patch( + width=distance, + height=distance, + top_basis="Z", + right_basis="X", + bot_basis="X", + left_basis="Z", + order_func=order_func, + ) + + +def make_xtop_qubit_patch(*, diameter: int) -> gen.Patch: + def order_func(m: complex) -> list[complex]: + if gen.checkerboard_basis(m) == "X": + return ORDER_S + else: + return ORDER_N + + return rectangular_surface_code_patch( + width=diameter, + height=diameter, + top_basis="X", + right_basis="Z", + bot_basis="X", + left_basis="Z", + order_func=order_func, + ) diff --git a/src/clorco/surface_code/_transversal_cnot.py b/src/clorco/surface_code/_transversal_cnot.py new file mode 100644 index 0000000..786387b --- /dev/null +++ b/src/clorco/surface_code/_transversal_cnot.py @@ -0,0 +1,197 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Literal + +import stim + +import gen +from clorco.surface_code._surface_code_chunks import build_surface_code_round_circuit +from clorco.surface_code._surface_code_layouts import make_surface_code_layout + + +def make_transversal_cnot_surface_code_circuit( + *, + diameter: int, + basis: Literal["X", "Z", "MagicEPR"], + pad_rounds: int, + noise: gen.NoiseModel | None, + convert_to_z: bool, +) -> stim.Circuit: + assert pad_rounds >= 1 + offset = diameter + 2 + left = make_surface_code_layout(width=diameter, height=diameter) + right = left.with_transformed_coords(lambda e: e + offset) + combo = gen.Patch(left.patch.tiles + right.patch.tiles) + ancillas = {-1, -2} if basis == "MagicEPR" else set() + xl = left.observables_x[0] + zl = left.observables_z[0] + xr = right.observables_x[0] + zr = right.observables_z[0] + + # Initial round. + head = gen.Builder.for_qubits(combo.used_set | ancillas) + builder = head.fork() + tail = head.fork() + if basis == "MagicEPR": + head.gate("RY", combo.used_set) + head.measure_pauli_string(xl * gen.PauliString({-1: "X"}), key="OBS_INIT1") + head.measure_pauli_string(zl * gen.PauliString({-1: "Z"}), key="OBS_INIT2") + head.measure_pauli_string(xr * gen.PauliString({-2: "X"}), key="OBS_INIT3") + head.measure_pauli_string(zr * gen.PauliString({-2: "Z"}), key="OBS_INIT4") + head.obs_include(["OBS_INIT1"], obs_index=0) + head.obs_include(["OBS_INIT2"], obs_index=1) + head.obs_include(["OBS_INIT3"], obs_index=2) + head.obs_include(["OBS_INIT4"], obs_index=3) + head.measure_patch(combo, sorted_by_basis=True, save_layer="init") + pad_rounds += 1 + else: + build_surface_code_round_circuit( + patch=combo, + init_data_basis=basis, + save_layer="init", + out=builder, + ) + for tile in combo.tiles: + m = tile.measurement_qubit + if tile.basis == basis: + builder.detector( + [gen.AtLayer(m, "init")], + pos=m, + extra_coords=[0 + 3 * (tile.basis == "Z")], + ) + builder.shift_coords(dt=1) + builder.tick() + + # Padding rounds until transition. + loop = builder.fork() + build_surface_code_round_circuit( + patch=combo, + save_layer="before", + out=loop, + ) + for tile in combo.tiles: + m = tile.measurement_qubit + loop.detector( + [gen.AtLayer(m, "init"), gen.AtLayer(m, "before")], + pos=m, + extra_coords=[0 + 3 * (tile.basis == "Z")], + ) + loop.shift_coords(dt=1) + loop.tick() + builder.circuit += loop.circuit * (pad_rounds - 1) + + # Transition round. + builder.gate2("CX", [(q, q + offset) for q in left.patch.data_set]) + builder.tick() + build_surface_code_round_circuit( + patch=combo, + save_layer="transition", + out=builder, + ) + for tile in combo.tiles: + m = tile.measurement_qubit + if tile.basis == "X" and m in left.patch.measure_set: + tile_offsets = [(0, "before"), (0, "transition"), (offset, "transition")] + elif tile.basis == "Z" and m in right.patch.measure_set: + tile_offsets = [(0, "before"), (0, "transition"), (-offset, "transition")] + else: + tile_offsets = [(0, "before"), (0, "transition")] + builder.detector( + [gen.AtLayer(m + d, layer) for d, layer in tile_offsets], + pos=m, + extra_coords=[1 + (m in left.patch.measure_set) + 3 * (tile.basis == "Z")], + ) + builder.shift_coords(dt=1) + builder.tick() + + # Padding rounds until measurement round. + loop = builder.fork() + build_surface_code_round_circuit( + patch=combo, + save_layer="after", + out=loop, + ) + for tile in combo.tiles: + m = tile.measurement_qubit + loop.detector( + [gen.AtLayer(m, "transition"), gen.AtLayer(m, "after")], + pos=m, + extra_coords=[0 + 3 * (tile.basis == "Z")], + ) + loop.shift_coords(dt=1) + loop.tick() + builder.circuit += loop.circuit * (pad_rounds - 2) + + # Final measurement round. + if basis == "MagicEPR": + tail.measure_patch(combo, sorted_by_basis=True, save_layer="end") + for tile in combo.tiles: + m = tile.measurement_qubit + tail.detector( + [gen.AtLayer(m, "after"), gen.AtLayer(m, "end")], + pos=m, + extra_coords=[0 + 3 * (tile.basis == "Z")], + ) + tail.measure_pauli_string(xl * xr * gen.PauliString({-1: "X"}), key="OBS_END1") + tail.measure_pauli_string(zl * gen.PauliString({-1: "Z"}), key="OBS_END2") + tail.measure_pauli_string(xr * gen.PauliString({-2: "X"}), key="OBS_END3") + tail.measure_pauli_string(zl * zr * gen.PauliString({-2: "Z"}), key="OBS_END4") + tail.obs_include(["OBS_END1"], obs_index=0) + tail.obs_include(["OBS_END2"], obs_index=1) + tail.obs_include(["OBS_END3"], obs_index=2) + tail.obs_include(["OBS_END4"], obs_index=3) + else: + build_surface_code_round_circuit( + patch=combo, + measure_data_basis=basis, + save_layer="end", + out=builder, + ) + for tile in combo.tiles: + m = tile.measurement_qubit + builder.detector( + [gen.AtLayer(m, "after"), gen.AtLayer(m, "end")], + pos=m, + extra_coords=[0 + 3 * (tile.basis == "Z")], + ) + builder.shift_coords(dt=1) + for tile in combo.tiles: + m = tile.measurement_qubit + if tile.basis == basis: + builder.detector( + [gen.AtLayer(q, "end") for q in tile.used_set], + pos=m, + extra_coords=[0 + 3 * (tile.basis == "Z")], + ) + if basis == "X": + builder.obs_include([gen.AtLayer(q, "end") for q in xl.qubits], obs_index=0) + builder.obs_include([gen.AtLayer(q, "end") for q in xr.qubits], obs_index=1) + elif basis == "Z": + builder.obs_include([gen.AtLayer(q, "end") for q in zl.qubits], obs_index=0) + builder.obs_include([gen.AtLayer(q, "end") for q in zr.qubits], obs_index=1) + else: + raise NotImplementedError(f"{basis=}") + + body = builder.circuit + if convert_to_z: + body = gen.transpile_to_z_basis_interaction_circuit( + body, is_entire_circuit=False + ) + if noise is not None: + body = noise.noisy_circuit( + body, immune_qubit_indices={builder.q2i[a] for a in ancillas} + ) + + return head.circuit + body + tail.circuit diff --git a/src/clorco/surface_code/_transversal_cnot_test.py b/src/clorco/surface_code/_transversal_cnot_test.py new file mode 100644 index 0000000..731468f --- /dev/null +++ b/src/clorco/surface_code/_transversal_cnot_test.py @@ -0,0 +1,236 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools +from typing import Any + +import pytest +import stim + +import gen +from clorco.surface_code._transversal_cnot import ( + make_transversal_cnot_surface_code_circuit, +) + + +@pytest.mark.parametrize( + "d,b", + itertools.product( + [3, 4, 5], + ["X", "Z", "MagicEPR"], + ), +) +def test_make_transversal_cnot_surface_code_circuit(d: int, b: Any): + c = make_transversal_cnot_surface_code_circuit( + diameter=d, + basis=b, + pad_rounds=2, + noise=gen.NoiseModel.uniform_depolarizing(1e-3), + convert_to_z=True, + ) + err = c.search_for_undetectable_logical_errors( + dont_explore_edges_with_degree_above=3, + dont_explore_detection_event_sets_with_size_above=5, + dont_explore_edges_increasing_symptom_degree=False, + canonicalize_circuit_errors=True, + ) + assert len(err) == d + if b == "MagicEPR": + assert gen.count_measurement_layers(c) == 6 + assert c.num_observables == 4 + assert ( + c.count_determined_measurements() + == c.num_detectors + c.num_observables + 6 * (d % 2 == 0) + ) + else: + assert gen.count_measurement_layers(c) == 4 + assert c.num_observables == 2 + assert c.count_determined_measurements() == c.num_detectors + c.num_observables + + +def test_make_transversal_cnot_surface_code_circuit_exact(): + assert make_transversal_cnot_surface_code_circuit( + diameter=3, + basis="MagicEPR", + pad_rounds=2, + noise=None, + convert_to_z=False, + ) == stim.Circuit( + """ + QUBIT_COORDS(-2, 0) 0 + QUBIT_COORDS(-1, 0) 1 + QUBIT_COORDS(0, 0) 2 + QUBIT_COORDS(0, 1) 3 + QUBIT_COORDS(0, 2) 4 + QUBIT_COORDS(1, 0) 5 + QUBIT_COORDS(1, 1) 6 + QUBIT_COORDS(1, 2) 7 + QUBIT_COORDS(2, 0) 8 + QUBIT_COORDS(2, 1) 9 + QUBIT_COORDS(2, 2) 10 + QUBIT_COORDS(5, 0) 11 + QUBIT_COORDS(5, 1) 12 + QUBIT_COORDS(5, 2) 13 + QUBIT_COORDS(6, 0) 14 + QUBIT_COORDS(6, 1) 15 + QUBIT_COORDS(6, 2) 16 + QUBIT_COORDS(7, 0) 17 + QUBIT_COORDS(7, 1) 18 + QUBIT_COORDS(7, 2) 19 + QUBIT_COORDS(-0.5, 0.5) 20 + QUBIT_COORDS(0.5, 0.5) 21 + QUBIT_COORDS(0.5, 1.5) 22 + QUBIT_COORDS(0.5, 2.5) 23 + QUBIT_COORDS(1.5, -0.5) 24 + QUBIT_COORDS(1.5, 0.5) 25 + QUBIT_COORDS(1.5, 1.5) 26 + QUBIT_COORDS(2.5, 1.5) 27 + QUBIT_COORDS(4.5, 0.5) 28 + QUBIT_COORDS(5.5, 0.5) 29 + QUBIT_COORDS(5.5, 1.5) 30 + QUBIT_COORDS(5.5, 2.5) 31 + QUBIT_COORDS(6.5, -0.5) 32 + QUBIT_COORDS(6.5, 0.5) 33 + QUBIT_COORDS(6.5, 1.5) 34 + QUBIT_COORDS(7.5, 1.5) 35 + RY 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 + MPP X1*X2*X3*X4 Z1*Z2*Z5*Z8 X0*X11*X12*X13 Z0*Z11*Z14*Z17 + OBSERVABLE_INCLUDE(0) rec[-4] + OBSERVABLE_INCLUDE(1) rec[-3] + OBSERVABLE_INCLUDE(2) rec[-2] + OBSERVABLE_INCLUDE(3) rec[-1] + MPP X2*X3*X5*X6 X4*X7 X5*X8 X6*X7*X9*X10 X11*X12*X14*X15 X13*X16 X14*X17 X15*X16*X18*X19 Z2*Z3 Z3*Z4*Z6*Z7 Z5*Z6*Z8*Z9 Z9*Z10 Z11*Z12 Z12*Z13*Z15*Z16 Z14*Z15*Z17*Z18 Z18*Z19 + SHIFT_COORDS(0, 0, 1) + TICK + REPEAT 2 { + RX 21 23 24 26 29 31 32 34 + R 20 22 25 27 28 30 33 35 + TICK + CX 3 22 5 25 9 27 12 30 14 33 18 35 21 2 23 4 26 6 29 11 31 13 34 15 + TICK + CX 4 22 6 25 10 27 13 30 15 33 19 35 21 5 23 7 26 9 29 14 31 16 34 18 + TICK + CX 2 20 6 22 8 25 11 28 15 30 17 33 21 3 24 5 26 7 29 12 32 14 34 16 + TICK + CX 3 20 7 22 9 25 12 28 16 30 18 33 21 6 24 8 26 10 29 15 32 17 34 19 + TICK + MX 21 23 24 26 29 31 32 34 + M 20 22 25 27 28 30 33 35 + DETECTOR(-0.5, 0.5, 0, 3) rec[-24] rec[-8] + DETECTOR(0.5, 0.5, 0, 0) rec[-32] rec[-16] + DETECTOR(0.5, 1.5, 0, 3) rec[-23] rec[-7] + DETECTOR(0.5, 2.5, 0, 0) rec[-31] rec[-15] + DETECTOR(1.5, -0.5, 0, 0) rec[-30] rec[-14] + DETECTOR(1.5, 0.5, 0, 3) rec[-22] rec[-6] + DETECTOR(1.5, 1.5, 0, 0) rec[-29] rec[-13] + DETECTOR(2.5, 1.5, 0, 3) rec[-21] rec[-5] + DETECTOR(4.5, 0.5, 0, 3) rec[-20] rec[-4] + DETECTOR(5.5, 0.5, 0, 0) rec[-28] rec[-12] + DETECTOR(5.5, 1.5, 0, 3) rec[-19] rec[-3] + DETECTOR(5.5, 2.5, 0, 0) rec[-27] rec[-11] + DETECTOR(6.5, -0.5, 0, 0) rec[-26] rec[-10] + DETECTOR(6.5, 0.5, 0, 3) rec[-18] rec[-2] + DETECTOR(6.5, 1.5, 0, 0) rec[-25] rec[-9] + DETECTOR(7.5, 1.5, 0, 3) rec[-17] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + } + CX 2 11 3 12 4 13 5 14 6 15 7 16 8 17 9 18 10 19 + TICK + RX 21 23 24 26 29 31 32 34 + R 20 22 25 27 28 30 33 35 + TICK + CX 3 22 5 25 9 27 12 30 14 33 18 35 21 2 23 4 26 6 29 11 31 13 34 15 + TICK + CX 4 22 6 25 10 27 13 30 15 33 19 35 21 5 23 7 26 9 29 14 31 16 34 18 + TICK + CX 2 20 6 22 8 25 11 28 15 30 17 33 21 3 24 5 26 7 29 12 32 14 34 16 + TICK + CX 3 20 7 22 9 25 12 28 16 30 18 33 21 6 24 8 26 10 29 15 32 17 34 19 + TICK + MX 21 23 24 26 29 31 32 34 + M 20 22 25 27 28 30 33 35 + DETECTOR(-0.5, 0.5, 0, 5) rec[-24] rec[-8] + DETECTOR(0.5, 0.5, 0, 2) rec[-32] rec[-16] rec[-12] + DETECTOR(0.5, 1.5, 0, 5) rec[-23] rec[-7] + DETECTOR(0.5, 2.5, 0, 2) rec[-31] rec[-15] rec[-11] + DETECTOR(1.5, -0.5, 0, 2) rec[-30] rec[-14] rec[-10] + DETECTOR(1.5, 0.5, 0, 5) rec[-22] rec[-6] + DETECTOR(1.5, 1.5, 0, 2) rec[-29] rec[-13] rec[-9] + DETECTOR(2.5, 1.5, 0, 5) rec[-21] rec[-5] + DETECTOR(4.5, 0.5, 0, 4) rec[-20] rec[-8] rec[-4] + DETECTOR(5.5, 0.5, 0, 1) rec[-28] rec[-12] + DETECTOR(5.5, 1.5, 0, 4) rec[-19] rec[-7] rec[-3] + DETECTOR(5.5, 2.5, 0, 1) rec[-27] rec[-11] + DETECTOR(6.5, -0.5, 0, 1) rec[-26] rec[-10] + DETECTOR(6.5, 0.5, 0, 4) rec[-18] rec[-6] rec[-2] + DETECTOR(6.5, 1.5, 0, 1) rec[-25] rec[-9] + DETECTOR(7.5, 1.5, 0, 4) rec[-17] rec[-5] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + RX 21 23 24 26 29 31 32 34 + R 20 22 25 27 28 30 33 35 + TICK + CX 3 22 5 25 9 27 12 30 14 33 18 35 21 2 23 4 26 6 29 11 31 13 34 15 + TICK + CX 4 22 6 25 10 27 13 30 15 33 19 35 21 5 23 7 26 9 29 14 31 16 34 18 + TICK + CX 2 20 6 22 8 25 11 28 15 30 17 33 21 3 24 5 26 7 29 12 32 14 34 16 + TICK + CX 3 20 7 22 9 25 12 28 16 30 18 33 21 6 24 8 26 10 29 15 32 17 34 19 + TICK + MX 21 23 24 26 29 31 32 34 + M 20 22 25 27 28 30 33 35 + DETECTOR(-0.5, 0.5, 0, 3) rec[-24] rec[-8] + DETECTOR(0.5, 0.5, 0, 0) rec[-32] rec[-16] + DETECTOR(0.5, 1.5, 0, 3) rec[-23] rec[-7] + DETECTOR(0.5, 2.5, 0, 0) rec[-31] rec[-15] + DETECTOR(1.5, -0.5, 0, 0) rec[-30] rec[-14] + DETECTOR(1.5, 0.5, 0, 3) rec[-22] rec[-6] + DETECTOR(1.5, 1.5, 0, 0) rec[-29] rec[-13] + DETECTOR(2.5, 1.5, 0, 3) rec[-21] rec[-5] + DETECTOR(4.5, 0.5, 0, 3) rec[-20] rec[-4] + DETECTOR(5.5, 0.5, 0, 0) rec[-28] rec[-12] + DETECTOR(5.5, 1.5, 0, 3) rec[-19] rec[-3] + DETECTOR(5.5, 2.5, 0, 0) rec[-27] rec[-11] + DETECTOR(6.5, -0.5, 0, 0) rec[-26] rec[-10] + DETECTOR(6.5, 0.5, 0, 3) rec[-18] rec[-2] + DETECTOR(6.5, 1.5, 0, 0) rec[-25] rec[-9] + DETECTOR(7.5, 1.5, 0, 3) rec[-17] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + MPP X2*X3*X5*X6 X4*X7 X5*X8 X6*X7*X9*X10 X11*X12*X14*X15 X13*X16 X14*X17 X15*X16*X18*X19 Z2*Z3 Z3*Z4*Z6*Z7 Z5*Z6*Z8*Z9 Z9*Z10 Z11*Z12 Z12*Z13*Z15*Z16 Z14*Z15*Z17*Z18 Z18*Z19 + DETECTOR(-0.5, 0.5, 0, 3) rec[-24] rec[-8] + DETECTOR(0.5, 0.5, 0, 0) rec[-32] rec[-16] + DETECTOR(0.5, 1.5, 0, 3) rec[-23] rec[-7] + DETECTOR(0.5, 2.5, 0, 0) rec[-31] rec[-15] + DETECTOR(1.5, -0.5, 0, 0) rec[-30] rec[-14] + DETECTOR(1.5, 0.5, 0, 3) rec[-22] rec[-6] + DETECTOR(1.5, 1.5, 0, 0) rec[-29] rec[-13] + DETECTOR(2.5, 1.5, 0, 3) rec[-21] rec[-5] + DETECTOR(4.5, 0.5, 0, 3) rec[-20] rec[-4] + DETECTOR(5.5, 0.5, 0, 0) rec[-28] rec[-12] + DETECTOR(5.5, 1.5, 0, 3) rec[-19] rec[-3] + DETECTOR(5.5, 2.5, 0, 0) rec[-27] rec[-11] + DETECTOR(6.5, -0.5, 0, 0) rec[-26] rec[-10] + DETECTOR(6.5, 0.5, 0, 3) rec[-18] rec[-2] + DETECTOR(6.5, 1.5, 0, 0) rec[-25] rec[-9] + DETECTOR(7.5, 1.5, 0, 3) rec[-17] rec[-1] + MPP X1*X2*X3*X4*X11*X12*X13 Z1*Z2*Z5*Z8 X0*X11*X12*X13 Z0*Z2*Z5*Z8*Z11*Z14*Z17 + OBSERVABLE_INCLUDE(0) rec[-4] + OBSERVABLE_INCLUDE(1) rec[-3] + OBSERVABLE_INCLUDE(2) rec[-2] + OBSERVABLE_INCLUDE(3) rec[-1] + """ + ) diff --git a/src/clorco/surface_code/_xz_surface_code_memory_circuits.py b/src/clorco/surface_code/_xz_surface_code_memory_circuits.py new file mode 100644 index 0000000..2e4a271 --- /dev/null +++ b/src/clorco/surface_code/_xz_surface_code_memory_circuits.py @@ -0,0 +1,54 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gen +from clorco.surface_code._surface_code_chunks import standard_surface_code_chunk +from clorco.surface_code._surface_code_patches import make_xtop_qubit_patch + + +def make_xz_memory_experiment_chunks( + *, + diameter: int, + basis: str, + rounds: int, +) -> list[gen.Chunk]: + qubit_patch = make_xtop_qubit_patch(diameter=diameter) + xs = {q for q in qubit_patch.data_set if q.real == 0} + zs = {q for q in qubit_patch.data_set if q.imag == 0} + assert len(xs & zs) % 2 == 1 + obs = gen.PauliString({q: basis for q in (xs if basis == "X" else zs)}) + assert rounds > 0 + if rounds == 1: + return [ + standard_surface_code_chunk( + qubit_patch, init_data_basis=basis, measure_data_basis=basis, obs=obs + ) + ] + + return [ + standard_surface_code_chunk( + qubit_patch, + init_data_basis=basis, + obs=obs, + ), + standard_surface_code_chunk( + qubit_patch, + obs=obs, + ).with_repetitions(rounds - 2), + standard_surface_code_chunk( + qubit_patch, + measure_data_basis=basis, + obs=obs, + ), + ] diff --git a/src/clorco/surface_code/_xz_surface_code_memory_circuits_test.py b/src/clorco/surface_code/_xz_surface_code_memory_circuits_test.py new file mode 100644 index 0000000..3e4aab5 --- /dev/null +++ b/src/clorco/surface_code/_xz_surface_code_memory_circuits_test.py @@ -0,0 +1,225 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import itertools + +import pytest +import stim + +import gen +from clorco._make_circuit import make_circuit + + +@pytest.mark.parametrize("basis,diameter", itertools.product(["X", "Z"], [2, 3, 4, 5])) +def test_make_xz_memory_experiment(basis: str, diameter: int): + circuit = make_circuit( + style=f"surface_code_{basis}", + diameter=diameter, + rounds=5, + noise_model=gen.NoiseModel.uniform_depolarizing(1e-3), + noise_strength=1e-3, + convert_to_cz=True, + editable_extras={}, + ) + + dem = circuit.detector_error_model( + decompose_errors=True, block_decomposition_from_introducing_remnant_edges=True + ) + assert dem is not None + + actual_distance = len(circuit.shortest_graphlike_error()) + expected_distance = diameter + assert actual_distance == expected_distance + + +@pytest.mark.parametrize( + "basis,diameter,rounds", itertools.product(["X", "Z"], [3, 4, 5], [0, 5]) +) +def test_have_all_detectors(basis: str, diameter: int, rounds: int): + c = make_circuit( + style=f"surface_code_{basis}", + diameter=diameter, + noise_model=gen.NoiseModel.uniform_depolarizing(1e-3), + noise_strength=1e-3, + convert_to_cz=True, + editable_extras={}, + rounds=3, + ) + assert c.detector_error_model() is not None + assert c.count_determined_measurements() == c.num_observables + c.num_detectors + + +def test_exact_circuit_x(): + assert make_circuit( + style="surface_code_X", + diameter=3, + noise_model=gen.NoiseModel.uniform_depolarizing(1e-3), + noise_strength=1e-3, + convert_to_cz=True, + editable_extras={}, + rounds=100, + ) == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + QUBIT_COORDS(0, 1) 1 + QUBIT_COORDS(0, 2) 2 + QUBIT_COORDS(1, 0) 3 + QUBIT_COORDS(1, 1) 4 + QUBIT_COORDS(1, 2) 5 + QUBIT_COORDS(2, 0) 6 + QUBIT_COORDS(2, 1) 7 + QUBIT_COORDS(2, 2) 8 + QUBIT_COORDS(-0.5, 1.5) 9 + QUBIT_COORDS(0.5, -0.5) 10 + QUBIT_COORDS(0.5, 0.5) 11 + QUBIT_COORDS(0.5, 1.5) 12 + QUBIT_COORDS(1.5, 0.5) 13 + QUBIT_COORDS(1.5, 1.5) 14 + QUBIT_COORDS(1.5, 2.5) 15 + QUBIT_COORDS(2.5, 0.5) 16 + R 10 12 13 15 0 1 2 3 4 5 6 7 8 9 11 14 16 + X_ERROR(0.001) 10 12 13 15 0 1 2 3 4 5 6 7 8 9 11 14 16 + TICK + H 0 1 2 3 7 9 10 11 12 13 14 15 16 + DEPOLARIZE1(0.001) 0 1 2 3 7 9 10 11 12 13 14 15 16 4 5 6 8 + TICK + CZ 1 9 3 11 4 12 6 13 7 14 8 15 + DEPOLARIZE2(0.001) 1 9 3 11 4 12 6 13 7 14 8 15 + DEPOLARIZE1(0.001) 0 2 5 10 16 + TICK + H 1 3 4 6 7 8 + DEPOLARIZE1(0.001) 1 3 4 6 7 8 0 2 5 9 10 11 12 13 14 15 16 + TICK + CZ 1 12 2 9 3 13 4 11 5 15 8 14 + DEPOLARIZE2(0.001) 1 12 2 9 3 13 4 11 5 15 8 14 + DEPOLARIZE1(0.001) 0 6 7 10 16 + TICK + CZ 0 11 3 10 4 14 5 12 6 16 7 13 + DEPOLARIZE2(0.001) 0 11 3 10 4 14 5 12 6 16 7 13 + DEPOLARIZE1(0.001) 1 2 8 9 15 + TICK + H 0 1 2 3 4 5 7 9 + DEPOLARIZE1(0.001) 0 1 2 3 4 5 7 9 6 8 10 11 12 13 14 15 16 + TICK + CZ 0 10 1 11 2 12 4 13 5 14 7 16 + DEPOLARIZE2(0.001) 0 10 1 11 2 12 4 13 5 14 7 16 + DEPOLARIZE1(0.001) 3 6 8 9 15 + TICK + H 0 2 4 10 11 12 13 14 15 16 + DEPOLARIZE1(0.001) 0 2 4 10 11 12 13 14 15 16 1 3 5 6 7 8 9 + TICK + M(0.001) 10 12 13 15 9 11 14 16 + DETECTOR(0.5, -0.5, 0, 1) rec[-8] + DETECTOR(0.5, 1.5, 0, 1) rec[-7] + DETECTOR(1.5, 0.5, 0, 0) rec[-6] + DETECTOR(1.5, 2.5, 0, 0) rec[-5] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 10 12 13 15 9 11 14 16 0 1 2 3 4 5 6 7 8 + TICK + REPEAT 98 { + R 10 12 13 15 9 11 14 16 + X_ERROR(0.001) 10 12 13 15 9 11 14 16 + DEPOLARIZE1(0.001) 0 1 2 3 4 5 6 7 8 + TICK + H 4 6 8 9 10 11 12 13 14 15 16 + DEPOLARIZE1(0.001) 4 6 8 9 10 11 12 13 14 15 16 0 1 2 3 5 7 + TICK + CZ 1 9 3 11 4 12 6 13 7 14 8 15 + DEPOLARIZE2(0.001) 1 9 3 11 4 12 6 13 7 14 8 15 + DEPOLARIZE1(0.001) 0 2 5 10 16 + TICK + H 1 3 4 5 6 7 8 + DEPOLARIZE1(0.001) 1 3 4 5 6 7 8 0 2 9 10 11 12 13 14 15 16 + TICK + CZ 1 12 2 9 3 13 4 11 5 15 8 14 + DEPOLARIZE2(0.001) 1 12 2 9 3 13 4 11 5 15 8 14 + DEPOLARIZE1(0.001) 0 6 7 10 16 + TICK + CZ 0 11 3 10 4 14 5 12 6 16 7 13 + DEPOLARIZE2(0.001) 0 11 3 10 4 14 5 12 6 16 7 13 + DEPOLARIZE1(0.001) 1 2 8 9 15 + TICK + H 0 1 2 3 4 5 7 9 + DEPOLARIZE1(0.001) 0 1 2 3 4 5 7 9 6 8 10 11 12 13 14 15 16 + TICK + CZ 0 10 1 11 2 12 4 13 5 14 7 16 + DEPOLARIZE2(0.001) 0 10 1 11 2 12 4 13 5 14 7 16 + DEPOLARIZE1(0.001) 3 6 8 9 15 + TICK + H 0 2 4 10 11 12 13 14 15 16 + DEPOLARIZE1(0.001) 0 2 4 10 11 12 13 14 15 16 1 3 5 6 7 8 9 + TICK + M(0.001) 10 12 13 15 9 11 14 16 + DETECTOR(-0.5, 1.5, 0, 3) rec[-12] rec[-4] + DETECTOR(0.5, -0.5, 0, 1) rec[-16] rec[-8] + DETECTOR(0.5, 0.5, 0, 4) rec[-11] rec[-3] + DETECTOR(0.5, 1.5, 0, 1) rec[-15] rec[-7] + DETECTOR(1.5, 0.5, 0, 0) rec[-14] rec[-6] + DETECTOR(1.5, 1.5, 0, 3) rec[-10] rec[-2] + DETECTOR(1.5, 2.5, 0, 0) rec[-13] rec[-5] + DETECTOR(2.5, 0.5, 0, 4) rec[-9] rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 10 12 13 15 9 11 14 16 0 1 2 3 4 5 6 7 8 + TICK + } + R 10 12 13 15 9 11 14 16 + X_ERROR(0.001) 10 12 13 15 9 11 14 16 + DEPOLARIZE1(0.001) 0 1 2 3 4 5 6 7 8 + TICK + H 4 6 8 9 10 11 12 13 14 15 16 + DEPOLARIZE1(0.001) 4 6 8 9 10 11 12 13 14 15 16 0 1 2 3 5 7 + TICK + CZ 1 9 3 11 4 12 6 13 7 14 8 15 + DEPOLARIZE2(0.001) 1 9 3 11 4 12 6 13 7 14 8 15 + DEPOLARIZE1(0.001) 0 2 5 10 16 + TICK + H 1 3 4 5 6 7 8 + DEPOLARIZE1(0.001) 1 3 4 5 6 7 8 0 2 9 10 11 12 13 14 15 16 + TICK + CZ 1 12 2 9 3 13 4 11 5 15 8 14 + DEPOLARIZE2(0.001) 1 12 2 9 3 13 4 11 5 15 8 14 + DEPOLARIZE1(0.001) 0 6 7 10 16 + TICK + CZ 0 11 3 10 4 14 5 12 6 16 7 13 + DEPOLARIZE2(0.001) 0 11 3 10 4 14 5 12 6 16 7 13 + DEPOLARIZE1(0.001) 1 2 8 9 15 + TICK + H 0 1 2 4 5 6 7 9 + DEPOLARIZE1(0.001) 0 1 2 4 5 6 7 9 3 8 10 11 12 13 14 15 16 + TICK + CZ 0 10 1 11 2 12 4 13 5 14 7 16 + DEPOLARIZE2(0.001) 0 10 1 11 2 12 4 13 5 14 7 16 + DEPOLARIZE1(0.001) 3 6 8 9 15 + TICK + H 1 5 7 8 10 11 12 13 14 15 16 + DEPOLARIZE1(0.001) 1 5 7 8 10 11 12 13 14 15 16 0 2 3 4 6 9 + TICK + M(0.001) 10 12 13 15 0 1 2 3 4 5 6 7 8 9 11 14 16 + DETECTOR(-0.5, 1.5, 0, 3) rec[-21] rec[-4] + DETECTOR(0.5, -0.5, 0, 1) rec[-25] rec[-17] + DETECTOR(0.5, 0.5, 0, 4) rec[-20] rec[-3] + DETECTOR(0.5, 1.5, 0, 1) rec[-24] rec[-16] + DETECTOR(1.5, 0.5, 0, 0) rec[-23] rec[-15] + DETECTOR(1.5, 1.5, 0, 3) rec[-19] rec[-2] + DETECTOR(1.5, 2.5, 0, 0) rec[-22] rec[-14] + DETECTOR(2.5, 0.5, 0, 4) rec[-18] rec[-1] + DETECTOR(0.5, -0.5, 0, 1) rec[-17] rec[-13] rec[-10] + DETECTOR(0.5, 1.5, 0, 1) rec[-16] rec[-12] rec[-11] rec[-9] rec[-8] + DETECTOR(1.5, 0.5, 0, 0) rec[-15] rec[-10] rec[-9] rec[-7] rec[-6] + DETECTOR(1.5, 2.5, 0, 0) rec[-14] rec[-8] rec[-5] + OBSERVABLE_INCLUDE(0) rec[-13] rec[-12] rec[-11] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 10 12 13 15 0 1 2 3 4 5 6 7 8 9 11 14 16 + """ + ) diff --git a/src/gen/__init__.py b/src/gen/__init__.py new file mode 100644 index 0000000..153c7db --- /dev/null +++ b/src/gen/__init__.py @@ -0,0 +1,81 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from gen._circuit_util import ( + gates_used_by_circuit, + gate_counts_for_circuit, + count_measurement_layers, +) +from gen._core import ( + AtLayer, + Builder, + complex_key, + MeasurementTracker, + min_max_complex, + NoiseModel, + NoiseRule, + occurs_in_classical_control_system, + Patch, + PauliString, + sorted_complex, + StabilizerCode, + Tile, +) +from gen._flows import ( + Chunk, + ChunkLoop, + Flow, + compile_chunks_into_circuit, + magic_measure_for_flows, + FlowStabilizerVerifier, +) +from gen._layers import ( + transpile_to_z_basis_interaction_circuit, +) +from gen._surf import ( + ClosedCurve, + CssObservableBoundaryPair, + StepSequenceOutline, + int_points_on_line, + int_points_inside_polygon, + checkerboard_basis, + Order_Z, + Order_ᴎ, + Order_N, + Order_S, + PatchOutline, + layer_begin, + layer_loop, + layer_transition, + layer_end, + layer_single_shot, + surface_code_patch, + PathOutline, + build_patch_to_patch_surface_code_transition_rounds, + PatchTransitionOutline, + StepOutline, +) +from gen._util import ( + stim_circuit_with_transformed_coords, + estimate_qubit_count_during_postselection, + write_file, +) +from gen._viz_circuit_html import ( + stim_circuit_html_viewer, +) +from gen._viz_patch_svg import ( + patch_svg_viewer, + is_colinear, + svg_path_directions_for_tile, +) diff --git a/src/gen/_circuit_util.py b/src/gen/_circuit_util.py new file mode 100644 index 0000000..c9b0370 --- /dev/null +++ b/src/gen/_circuit_util.py @@ -0,0 +1,181 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import collections +from typing import Counter + +import stim + +from gen._core._noise import ANNOTATION_OPS + + +def count_measurement_layers(circuit: stim.Circuit) -> int: + saw_measurement = False + result = 0 + for instruction in circuit: + if isinstance(instruction, stim.CircuitRepeatBlock): + result += ( + count_measurement_layers(instruction.body_copy()) + * instruction.repeat_count + ) + elif isinstance(instruction, stim.CircuitInstruction): + saw_measurement |= stim.gate_data(instruction.name).produces_measurements + if instruction.name == "TICK": + result += saw_measurement + saw_measurement = False + else: + raise NotImplementedError(f"{instruction=}") + result += saw_measurement + return result + + +def gate_counts_for_circuit(circuit: stim.Circuit) -> Counter[str]: + """Determines gates used by a circuit, disambiguating MPP/feedback cases. + + MPP instructions are expanded into what they actually measure, such as + "MXX" for MPP X1*X2 and "MXYZ" for MPP X4*Y5*Z7. + + Feedback instructions like `CX rec[-1] 0` become the gate "feedback". + + Sweep instructions like `CX sweep[2] 0` become the gate "sweep". + """ + out = collections.Counter() + for instruction in circuit: + if isinstance(instruction, stim.CircuitRepeatBlock): + for k, v in gate_counts_for_circuit(instruction.body_copy()).items(): + out[k] += v * instruction.repeat_count + + elif instruction.name in ["CX", "CY", "CZ", "XCZ", "YCZ"]: + targets = instruction.targets_copy() + for k in range(0, len(targets), 2): + if ( + targets[k].is_measurement_record_target + or targets[k + 1].is_measurement_record_target + ): + out["feedback"] += 1 + elif ( + targets[k].is_sweep_bit_target or targets[k + 1].is_sweep_bit_target + ): + out["sweep"] += 1 + else: + out[instruction.name] += 1 + + elif instruction.name == "MPP": + op = "M" + targets = instruction.targets_copy() + is_continuing = True + for t in targets: + if t.is_combiner: + is_continuing = True + continue + p = ( + "X" + if t.is_x_target + else "Y" + if t.is_y_target + else "Z" + if t.is_z_target + else "?" + ) + if is_continuing: + op += p + is_continuing = False + else: + if op == "MZ": + op = "M" + out[op] += 1 + op = "M" + p + if op: + if op == "MZ": + op = "M" + out[op] += 1 + + elif stim.gate_data(instruction.name).is_two_qubit_gate: + out[instruction.name] += len(instruction.targets_copy()) // 2 + elif ( + instruction.name in ANNOTATION_OPS + or instruction.name == "E" + or instruction.name == "ELSE_CORRELATED_ERROR" + ): + out[instruction.name] += 1 + else: + out[instruction.name] += len(instruction.targets_copy()) + + return out + + +def gates_used_by_circuit(circuit: stim.Circuit) -> set[str]: + """Determines gates used by a circuit, disambiguating MPP/feedback cases. + + MPP instructions are expanded into what they actually measure, such as + "MXX" for MPP X1*X2 and "MXYZ" for MPP X4*Y5*Z7. + + Feedback instructions like `CX rec[-1] 0` become the gate "feedback". + + Sweep instructions like `CX sweep[2] 0` become the gate "sweep". + """ + out = set() + for instruction in circuit: + if isinstance(instruction, stim.CircuitRepeatBlock): + out |= gates_used_by_circuit(instruction.body_copy()) + + elif instruction.name in ["CX", "CY", "CZ", "XCZ", "YCZ"]: + targets = instruction.targets_copy() + for k in range(0, len(targets), 2): + if ( + targets[k].is_measurement_record_target + or targets[k + 1].is_measurement_record_target + ): + out.add("feedback") + elif ( + targets[k].is_sweep_bit_target or targets[k + 1].is_sweep_bit_target + ): + out.add("sweep") + else: + out.add(instruction.name) + + elif instruction.name == "MPP": + op = "M" + targets = instruction.targets_copy() + is_continuing = True + for t in targets: + if t.is_combiner: + is_continuing = True + continue + p = ( + "X" + if t.is_x_target + else "Y" + if t.is_y_target + else "Z" + if t.is_z_target + else "?" + ) + if is_continuing: + op += p + is_continuing = False + else: + if op == "MZ": + op = "M" + out.add(op) + op = "M" + p + if op: + if op == "MZ": + op = "M" + out.add(op) + + else: + out.add(instruction.name) + + return out diff --git a/src/gen/_circuit_util_test.py b/src/gen/_circuit_util_test.py new file mode 100644 index 0000000..e0d11b5 --- /dev/null +++ b/src/gen/_circuit_util_test.py @@ -0,0 +1,270 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +import gen +from gen._circuit_util import ( + gates_used_by_circuit, + gate_counts_for_circuit, + count_measurement_layers, +) + + +def test_gates_used_by_circuit(): + assert ( + gates_used_by_circuit( + stim.Circuit( + """ + H 0 + TICK + CX 0 1 + """ + ) + ) + == {"H", "TICK", "CX"} + ) + + assert ( + gates_used_by_circuit( + stim.Circuit( + """ + S 0 + XCZ 0 1 + """ + ) + ) + == {"S", "XCZ"} + ) + + assert ( + gates_used_by_circuit( + stim.Circuit( + """ + MPP X0*X1 Z2*Z3*Z4 Y0*Z1 + """ + ) + ) + == {"MXX", "MZZZ", "MYZ"} + ) + + assert ( + gates_used_by_circuit( + stim.Circuit( + """ + CX rec[-1] 1 + """ + ) + ) + == {"feedback"} + ) + + assert ( + gates_used_by_circuit( + stim.Circuit( + """ + CX sweep[1] 1 + """ + ) + ) + == {"sweep"} + ) + + assert ( + gates_used_by_circuit( + stim.Circuit( + """ + CX rec[-1] 1 0 1 + """ + ) + ) + == {"feedback", "CX"} + ) + + +def test_gate_counts_for_circuit(): + assert ( + gate_counts_for_circuit( + stim.Circuit( + """ + H 0 + TICK + CX 0 1 + """ + ) + ) + == {"H": 1, "TICK": 1, "CX": 1} + ) + + assert ( + gate_counts_for_circuit( + stim.Circuit( + """ + S 0 + XCZ 0 1 + """ + ) + ) + == {"S": 1, "XCZ": 1} + ) + + assert ( + gate_counts_for_circuit( + stim.Circuit( + """ + MPP X0*X1 Z2*Z3*Z4 Y0*Z1 + """ + ) + ) + == {"MXX": 1, "MZZZ": 1, "MYZ": 1} + ) + + assert ( + gate_counts_for_circuit( + stim.Circuit( + """ + CX rec[-1] 1 + """ + ) + ) + == {"feedback": 1} + ) + + assert ( + gate_counts_for_circuit( + stim.Circuit( + """ + CX sweep[1] 1 + """ + ) + ) + == {"sweep": 1} + ) + + assert ( + gate_counts_for_circuit( + stim.Circuit( + """ + CX rec[-1] 1 0 1 + """ + ) + ) + == {"feedback": 1, "CX": 1} + ) + + assert ( + gate_counts_for_circuit( + stim.Circuit( + """ + H 0 1 + REPEAT 100 { + S 0 1 2 + CX 0 1 2 3 + } + """ + ) + ) + == {"H": 2, "S": 300, "CX": 200} + ) + + +def test_count_measurement_layers(): + assert count_measurement_layers(stim.Circuit()) == 0 + assert ( + count_measurement_layers( + stim.Circuit( + """ + M 0 1 2 + """ + ) + ) + == 1 + ) + assert ( + count_measurement_layers( + stim.Circuit( + """ + M 0 1 + MX 2 + MR 3 + """ + ) + ) + == 1 + ) + assert ( + count_measurement_layers( + stim.Circuit( + """ + M 0 1 + MX 2 + TICK + MR 3 + """ + ) + ) + == 2 + ) + assert ( + count_measurement_layers( + stim.Circuit( + """ + R 0 + CX 0 1 + TICK + M 0 + """ + ) + ) + == 1 + ) + assert ( + count_measurement_layers( + stim.Circuit( + """ + R 0 + CX 0 1 + TICK + M 0 + DETECTOR rec[-1] + M 1 + DETECTOR rec[-1] + OBSERVABLE_INCLUDE(0) rec[-1] + MPP X0*X1 + DETECTOR rec[-1] + """ + ) + ) + == 1 + ) + assert ( + count_measurement_layers( + stim.Circuit.generated( + "repetition_code:memory", + distance=3, + rounds=4, + ) + ) + == 4 + ) + assert ( + count_measurement_layers( + stim.Circuit.generated( + "surface_code:rotated_memory_x", + distance=3, + rounds=1000, + ) + ) + == 1000 + ) diff --git a/src/gen/_core/__init__.py b/src/gen/_core/__init__.py new file mode 100644 index 0000000..61c1c17 --- /dev/null +++ b/src/gen/_core/__init__.py @@ -0,0 +1,43 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from gen._core._builder import ( + Builder, +) +from gen._core._measurement_tracker import ( + AtLayer, + MeasurementTracker, +) +from gen._core._noise import ( + NoiseModel, + NoiseRule, + occurs_in_classical_control_system, +) +from gen._core._patch import ( + Patch, +) +from gen._core._stabilizer_code import ( + StabilizerCode, +) +from gen._core._tile import ( + Tile, +) +from gen._core._util import ( + sorted_complex, + min_max_complex, + complex_key, +) +from gen._core._pauli_string import ( + PauliString, +) diff --git a/src/gen/_core/_builder.py b/src/gen/_core/_builder.py new file mode 100644 index 0000000..f2f66d8 --- /dev/null +++ b/src/gen/_core/_builder.py @@ -0,0 +1,392 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Iterable, Callable, Any, TYPE_CHECKING +from typing import Sequence + +import stim + +from gen._core._measurement_tracker import MeasurementTracker, AtLayer +from gen._core._pauli_string import PauliString +from gen._core._util import complex_key, sorted_complex + +if TYPE_CHECKING: + import gen + + +SYMMETRIC_GATES = { + "CZ", + "XCX", + "YCY", + "ZCZ", + "SWAP", + "ISWAP", + "ISWAP_DAG", + "SQRT_XX", + "SQRT_YY", + "SQRT_ZZ", + "SQRT_XX_DAG", + "SQRT_YY_DAG", + "SQRT_ZZ_DAG", +} + + +class Builder: + """Helper class for building stim circuits. + + Handles qubit indexing (complex -> int conversion). + Handles measurement tracking (naming results and referring to them by name). + """ + + def __init__( + self, + *, + q2i: dict[complex, int], + circuit: stim.Circuit, + tracker: MeasurementTracker, + ): + self.q2i = q2i + self.circuit = circuit + self.tracker = tracker + + def copy(self) -> "Builder": + """Returns a Builder with independent copies of this builder's circuit and tracking data.""" + return Builder( + q2i=dict(self.q2i), circuit=self.circuit.copy(), tracker=self.tracker.copy() + ) + + def fork(self) -> "Builder": + """Returns a Builder with the same underlying tracking but which appends into a different circuit.""" + return Builder(q2i=self.q2i, circuit=stim.Circuit(), tracker=self.tracker) + + @staticmethod + def for_qubits( + qubits: Iterable[complex], + *, + to_circuit_coord_data: Callable[[complex], complex] = lambda e: e, + ) -> "Builder": + q2i = {q: i for i, q in enumerate(sorted_complex(set(qubits)))} + circuit = stim.Circuit() + for q, i in q2i.items(): + c = to_circuit_coord_data(q) + circuit.append("QUBIT_COORDS", [i], [c.real, c.imag]) + return Builder( + q2i=q2i, + circuit=circuit, + tracker=MeasurementTracker(), + ) + + def gate(self, name: str, qubits: Iterable[complex], arg: Any = None) -> None: + assert name not in [ + "CZ", + "ZCZ", + "XCX", + "YCY", + "ISWAP", + "ISWAP_DAG", + "SWAP", + "M", + "MX", + "MY", + ] + qubits = sorted_complex(qubits) + if not qubits: + return + self.circuit.append(name, [self.q2i[q] for q in qubits], arg) + + def gate2(self, name: str, pairs: Iterable[tuple[complex, complex]]) -> None: + pairs = sorted( + pairs, key=lambda pair: (complex_key(pair[0]), complex_key(pair[1])) + ) + if name == "XCZ": + pairs = [pair[::-1] for pair in pairs] + name = "CX" + if name == "YCZ": + pairs = [pair[::-1] for pair in pairs] + name = "CY" + if name == "SWAPCX": + pairs = [pair[::-1] for pair in pairs] + name = "CXSWAP" + if name in SYMMETRIC_GATES: + pairs = [sorted_complex(pair) for pair in pairs] + if not pairs: + return + self.circuit.append(name, [self.q2i[q] for pair in pairs for q in pair]) + + def shift_coords(self, *, dp: complex = 0, dt: int): + self.circuit.append("SHIFT_COORDS", [], [dp.real, dp.imag, dt]) + + def measure_stabilizer_code( + self, + code: "gen.StabilizerCode", + *, + save_layer: Any, + det_cmp_layer: Any | None = None, + noise: float | None = None, + sorted_by_basis: bool = False, + observables_first: bool = False, + ancilla_qubits_for_xz_observable_pairs: Sequence[complex], + ) -> None: + m_obs = lambda: self.measure_observables_and_include( + observables=code.entangled_observables( + ancilla_qubits_for_xz_observable_pairs + )[0], + save_layer=save_layer, + noise=noise, + ) + m_det = lambda: self.measure_patch( + patch=code.patch, + save_layer=save_layer, + cmp_layer=det_cmp_layer, + noise=noise, + sorted_by_basis=sorted_by_basis, + ) + if observables_first: + m_obs() + m_det() + else: + m_det() + m_obs() + + def measure_observables_and_include( + self, + observables: Iterable["gen.PauliString | None"], + *, + save_layer: Any | None = None, + noise: float | None = None, + ) -> None: + for obs_index, obs in enumerate(observables): + if obs is None: + continue + key = ( + None if save_layer is None else AtLayer(f"obs_{obs_index}", save_layer) + ) + self.measure_pauli_string( + obs, + key=key, + noise=noise, + ) + self.circuit.append("OBSERVABLE_INCLUDE", stim.target_rec(-1), [obs_index]) + + def measure_patch( + self, + patch: "gen.Patch", + *, + save_layer: Any, + cmp_layer: Any | None = None, + noise: float | None = None, + sorted_by_basis: bool = False, + ) -> None: + """Directly measures the stabilizers in a patch using MPP. + + Args: + patch: The patch to get stabilizers (tiles) from. + save_layer: The layer used when saving results to the tracker. The + measurement for a tile is saved under the key + `gen.AtLayer(tile.measurement_qubit, save_layer)`. + cmp_layer: If set to None, does nothing. If set to something else, + adds detectors comparing the new layer's measurements to this + layer's measurements. + noise: The probability of measurement results being wrong. If set to + None, does nothing. If set to a float, adds it as an argument + to the MPP instruction. + sorted_by_basis: Sorts the tiles by basis when deciding what order + to perform measurements in. This can be important when making + sure measurement offsets line up when entering and exiting + loops. Extremely hacky. + """ + if sorted_by_basis: + from gen._core._patch import Patch + + patch = Patch(sorted(patch.tiles, key=lambda t: t.basis), do_not_sort=True) + for tile in patch.tiles: + self.measure_pauli_string( + PauliString( + { + tile.ordered_data_qubits[k]: tile.bases[k] + for k in range(len(tile.ordered_data_qubits)) + if tile.ordered_data_qubits[k] is not None + } + ), + key=AtLayer(tile.measurement_qubit, save_layer), + noise=noise, + ) + if cmp_layer is not None: + for tile in patch.tiles: + m = tile.measurement_qubit + self.detector( + [AtLayer(m, save_layer), AtLayer(m, cmp_layer)], + pos=m, + extra_coords=tile.extra_coords, + ) + + def demolition_measure_with_feedback_passthrough( + self, + xs: Iterable[complex] = (), + ys: Iterable[complex] = (), + zs: Iterable[complex] = (), + *, + tracker_key: Callable[[complex], Any] = lambda e: e, + save_layer: Any, + ) -> None: + """Performs demolition measurements that look like measurements w.r.t. detectors. + + This is done by adding feedback operations that flip the demolished qubits depending + on the measurement result. This feedback can then later be removed using + stim.Circuit.with_inlined_feedback. The benefit is that it can be easier to + programmatically create the detectors using the passthrough measurements, and + then they can be automatically converted. + """ + self.measure( + qubits=xs, basis="X", tracker_key=tracker_key, save_layer=save_layer + ) + self.measure( + qubits=ys, basis="Y", tracker_key=tracker_key, save_layer=save_layer + ) + self.measure( + qubits=zs, basis="Z", tracker_key=tracker_key, save_layer=save_layer + ) + self.tick() + self.gate("RX", xs) + self.gate("RY", ys) + self.gate("RZ", zs) + for qs, b in [(xs, "Z"), (ys, "X"), (zs, "X")]: + for q in qs: + self.classical_paulis( + control_keys=[AtLayer(tracker_key(q), save_layer)], + targets=[q], + basis=b, + ) + + def measure( + self, + qubits: Iterable[complex], + *, + basis: str = "Z", + tracker_key: Callable[[complex], Any] = lambda e: e, + save_layer: Any, + ) -> None: + qubits = sorted_complex(qubits) + if not qubits: + return + self.circuit.append(f"M{basis}", [self.q2i[q] for q in qubits]) + for q in qubits: + self.tracker.record_measurement(AtLayer(tracker_key(q), save_layer)) + + def measure_pauli_string( + self, + observable: "gen.PauliString", + *, + noise: float | None = None, + key: Any | None, + ): + """Adds an MPP operation to measure the given pauli string. + + Args: + observable: A gen.PauliString to measure. + key: The value used to refer to the result later. + noise: Optional measurement flip probability argument to add to the measurement. + """ + targets = [] + for q in sorted_complex(observable.qubits): + b = observable.qubits[q] + if b == "X": + m = stim.target_x + elif b == "Y": + m = stim.target_y + elif b == "Z": + m = stim.target_z + else: + raise NotImplementedError(f"{b=}") + targets.append(m(self.q2i[q])) + targets.append(stim.target_combiner()) + + if targets: + targets.pop() + self.circuit.append("MPP", targets, noise) + if key is not None: + self.tracker.record_measurement(key) + elif key is not None: + self.tracker.make_measurement_group([], key=key) + + def detector( + self, + keys: Iterable[Any], + *, + pos: complex | None, + t: float = 0, + extra_coords: Iterable[float] = (), + mark_as_post_selected: bool = False, + ignore_non_existent: bool = False, + ) -> None: + if pos is not None: + coords = [pos.real, pos.imag, t] + list(extra_coords) + if mark_as_post_selected: + coords.append(1) + else: + if list(extra_coords): + raise ValueError("pos is None but extra_coords is not empty") + if mark_as_post_selected: + raise ValueError("pos is None and mark_as_post_selected") + coords = None + + if ignore_non_existent: + keys = [k for k in keys if k in self.tracker.recorded] + targets = self.tracker.current_measurement_record_targets_for(keys) + self.circuit.append("DETECTOR", targets, coords) + + def obs_include(self, keys: Iterable[Any], *, obs_index: int) -> None: + ms = self.tracker.current_measurement_record_targets_for(keys) + if ms: + self.circuit.append( + "OBSERVABLE_INCLUDE", + ms, + obs_index, + ) + + def tick(self) -> None: + self.circuit.append("TICK") + + def cz(self, pairs: list[tuple[complex, complex]]) -> None: + sorted_pairs = [] + for a, b in pairs: + if complex_key(a) > complex_key(b): + a, b = b, a + sorted_pairs.append((a, b)) + sorted_pairs = sorted( + sorted_pairs, key=lambda e: (complex_key(e[0]), complex_key(e[1])) + ) + for a, b in sorted_pairs: + self.circuit.append("CZ", [self.q2i[a], self.q2i[b]]) + + def swap(self, pairs: list[tuple[complex, complex]]) -> None: + sorted_pairs = [] + for a, b in pairs: + if complex_key(a) > complex_key(b): + a, b = b, a + sorted_pairs.append((a, b)) + sorted_pairs = sorted( + sorted_pairs, key=lambda e: (complex_key(e[0]), complex_key(e[1])) + ) + for a, b in sorted_pairs: + self.circuit.append("SWAP", [self.q2i[a], self.q2i[b]]) + + def classical_paulis( + self, *, control_keys: Iterable[Any], targets: Iterable[complex], basis: str + ) -> None: + gate = f"C{basis}" + indices = [self.q2i[q] for q in sorted_complex(targets)] + for rec in self.tracker.current_measurement_record_targets_for(control_keys): + for i in indices: + self.circuit.append(gate, [rec, i]) diff --git a/src/gen/_core/_builder_test.py b/src/gen/_core/_builder_test.py new file mode 100644 index 0000000..fc75d0c --- /dev/null +++ b/src/gen/_core/_builder_test.py @@ -0,0 +1,90 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +import gen + + +def test_builder_init(): + builder = gen.Builder.for_qubits([0, 1j, 3 + 2j]) + assert builder.circuit == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + QUBIT_COORDS(0, 1) 1 + QUBIT_COORDS(3, 2) 2 + """ + ) + + +def test_measure_code(): + perfect_code = gen.StabilizerCode( + patch=gen.Patch( + [ + gen.Tile( + bases="XZZX", + measurement_qubit=k + 1j, + ordered_data_qubits=[(k + j) % 5 for j in range(4)], + ) + for k in range(4) + ] + ), + observables_x=[gen.PauliString.from_xyzs(xs=range(5))], + observables_z=[gen.PauliString.from_xyzs(zs=range(5))], + ) + + builder = gen.Builder.for_qubits([1j, 0, 1, 2, 3, 4]) + builder.measure_stabilizer_code( + perfect_code, + save_layer="init", + observables_first=True, + ancilla_qubits_for_xz_observable_pairs=[1j], + ) + assert builder.circuit == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + QUBIT_COORDS(0, 1) 1 + QUBIT_COORDS(1, 0) 2 + QUBIT_COORDS(2, 0) 3 + QUBIT_COORDS(3, 0) 4 + QUBIT_COORDS(4, 0) 5 + MPP X0*X1*X2*X3*X4*X5 + OBSERVABLE_INCLUDE(0) rec[-1] + MPP Z0*Z1*Z2*Z3*Z4*Z5 + OBSERVABLE_INCLUDE(1) rec[-1] + MPP X0*Z2*Z3*X4 X2*Z3*Z4*X5 X0*X3*Z4*Z5 Z0*X2*X4*Z5 + """ + ) + + builder.circuit.clear() + builder.measure_stabilizer_code( + perfect_code, + save_layer="end", + det_cmp_layer="init", + observables_first=False, + ancilla_qubits_for_xz_observable_pairs=[1j], + ) + assert builder.circuit == stim.Circuit( + """ + MPP X0*Z2*Z3*X4 X2*Z3*Z4*X5 X0*X3*Z4*Z5 Z0*X2*X4*Z5 + DETECTOR(0, 1, 0) rec[-8] rec[-4] + DETECTOR(1, 1, 0) rec[-7] rec[-3] + DETECTOR(2, 1, 0) rec[-6] rec[-2] + DETECTOR(3, 1, 0) rec[-5] rec[-1] + MPP X0*X1*X2*X3*X4*X5 + OBSERVABLE_INCLUDE(0) rec[-1] + MPP Z0*Z1*Z2*Z3*Z4*Z5 + OBSERVABLE_INCLUDE(1) rec[-1] + """ + ) diff --git a/src/gen/_core/_measurement_tracker.py b/src/gen/_core/_measurement_tracker.py new file mode 100644 index 0000000..a4ced0c --- /dev/null +++ b/src/gen/_core/_measurement_tracker.py @@ -0,0 +1,76 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses +from typing import Iterable, Any + +import stim + + +@dataclasses.dataclass(frozen=True) +class AtLayer: + """A special class that indicates the layer to read a measurement key from.""" + + key: Any + layer: Any + + +class MeasurementTracker: + """Tracks measurements and groups of measurements, for producing stim record targets.""" + + def __init__(self): + self.recorded: dict[Any, list[int] | None] = {} + self.next_measurement_index = 0 + + def copy(self) -> "MeasurementTracker": + result = MeasurementTracker() + result.recorded = {k: list(v) for k, v in self.recorded.items()} + result.next_measurement_index = self.next_measurement_index + return result + + def _rec(self, key: Any, value: list[int] | None) -> None: + if key in self.recorded: + raise ValueError(f"Measurement key collision: {key=}") + self.recorded[key] = value + + def record_measurement(self, key: Any) -> None: + self._rec(key, [self.next_measurement_index]) + self.next_measurement_index += 1 + + def make_measurement_group(self, sub_keys: Iterable[Any], *, key: Any) -> None: + self._rec(key, self.measurement_indices(sub_keys)) + + def record_obstacle(self, key: Any) -> None: + self._rec(key, None) + + def measurement_indices(self, keys: Iterable[Any]) -> list[int]: + result = set() + for key in keys: + if key not in self.recorded: + raise ValueError(f"No such measurement: {key=}") + for v in self.recorded[key]: + if v is None: + raise ValueError(f"Obstacle at {key=}") + if v in result: + result.remove(v) + else: + result.add(v) + return sorted(result) + + def current_measurement_record_targets_for( + self, keys: Iterable[Any] + ) -> list[stim.GateTarget]: + t0 = self.next_measurement_index + times = self.measurement_indices(keys) + return [stim.target_rec(t - t0) for t in sorted(times)] diff --git a/src/gen/_core/_noise.py b/src/gen/_core/_noise.py new file mode 100644 index 0000000..336ccc6 --- /dev/null +++ b/src/gen/_core/_noise.py @@ -0,0 +1,543 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Iterator, AbstractSet, Any + +import collections + +import stim + + +ANNOTATION_OPS = { + "DETECTOR", + "OBSERVABLE_INCLUDE", + "QUBIT_COORDS", + "SHIFT_COORDS", + "TICK", +} +OP_TO_MEASURE_BASES = { + "M": "Z", + "MX": "X", + "MY": "Y", + "MZ": "Z", + "MXX": "XX", + "MYY": "YY", + "MZZ": "ZZ", + "MPP": "*", +} + + +class NoiseRule: + """Describes how to add noise to an operation.""" + + def __init__( + self, + *, + after: dict[str, float], + flip_result: float = 0, + ): + """ + Args: + after: A dictionary mapping noise rule names to their probability argument. + For example, {"DEPOLARIZE2": 0.01, "X_ERROR": 0.02} will add two qubit + depolarization with parameter 0.01 and also add 2% bit flip noise. These + noise channels occur after all other operations in the moment and are applied + to the same targets as the relevant operation. + flip_result: The probability that a measurement result should be reported incorrectly. + Only valid when applied to operations that produce measurement results. + """ + if not (0 <= flip_result <= 1): + raise ValueError(f"not (0 <= {flip_result=} <= 1)") + for k, p in after.items(): + gate_data = stim.gate_data(k) + if gate_data.produces_measurements or not gate_data.is_noisy_gate: + raise ValueError(f"not a pure noise channel: {k} from {after=}") + if not (0 <= p <= 1): + raise ValueError(f"not (0 <= {p} <= 1) from {after=}") + self.after = after + self.flip_result = flip_result + + def append_noisy_version_of( + self, + *, + split_op: stim.CircuitInstruction, + out_during_moment: stim.Circuit, + after_moments: collections.defaultdict[Any, stim.Circuit], + immune_qubit_indices: AbstractSet[int], + ) -> None: + targets = split_op.targets_copy() + if immune_qubit_indices and any( + (t.is_qubit_target or t.is_x_target or t.is_y_target or t.is_z_target) + and t.value in immune_qubit_indices + for t in targets + ): + out_during_moment.append(split_op) + return + + args = split_op.gate_args_copy() + if self.flip_result: + gate_data = stim.gate_data(split_op.name) + assert gate_data.produces_measurements + assert gate_data.is_noisy_gate + assert gate_data.num_parens_arguments_range == range(0, 2) + assert len(args) == 0 + args = [self.flip_result] + + out_during_moment.append(split_op.name, targets, args) + raw_targets = [t.value for t in targets if not t.is_combiner] + for op_name, arg in self.after.items(): + after_moments[(op_name, arg)].append(op_name, raw_targets, arg) + + +class NoiseModel: + def __init__( + self, + idle_noise: float | NoiseRule | None = None, + tick_noise: NoiseRule | None = None, + additional_depolarization_waiting_for_m_or_r: float = 0, + gate_rules: dict[str, NoiseRule] | None = None, + measure_rules: dict[str, NoiseRule] | None = None, + any_measurement_rule: NoiseRule | None = None, + any_clifford_1q_rule: NoiseRule | None = None, + any_clifford_2q_rule: NoiseRule | None = None, + allow_multiple_uses_of_a_qubit_in_one_tick: bool = False, + ): + if isinstance(idle_noise, float): + if idle_noise == 0: + idle_noise = None + else: + idle_noise = NoiseRule(after={'DEPOLARIZE1': idle_noise}) + self.idle_noise: NoiseRule | None = idle_noise + self.tick_noise = tick_noise + self.additional_depolarization_waiting_for_m_or_r = ( + additional_depolarization_waiting_for_m_or_r + ) + self.gate_rules = {} if gate_rules is None else gate_rules + self.measure_rules = measure_rules + self.any_measurement_rule = any_measurement_rule + self.any_clifford_1q_rule = any_clifford_1q_rule + self.any_clifford_2q_rule = any_clifford_2q_rule + self.allow_multiple_uses_of_a_qubit_in_one_tick = ( + allow_multiple_uses_of_a_qubit_in_one_tick + ) + assert self.tick_noise is None or not self.tick_noise.flip_result + + @staticmethod + def si1000(p: float) -> "NoiseModel": + """Superconducting inspired noise. + + As defined in "A Fault-Tolerant Honeycomb Memory" https://arxiv.org/abs/2108.10457 + + Small tweak when measurements aren't immediately followed by a reset: the measurement result + is probabilistically flipped instead of the input qubit. The input qubit is depolarized after + the measurement. + """ + return NoiseModel( + idle_noise=p / 10, + additional_depolarization_waiting_for_m_or_r=2 * p, + any_clifford_1q_rule=NoiseRule(after={"DEPOLARIZE1": p / 10}), + any_clifford_2q_rule=NoiseRule(after={"DEPOLARIZE2": p}), + measure_rules={ + "Z": NoiseRule(after={"DEPOLARIZE1": p}, flip_result=p * 5), + "ZZ": NoiseRule(after={"DEPOLARIZE2": p}, flip_result=p * 5), + }, + gate_rules={ + "R": NoiseRule(after={"X_ERROR": p * 2}), + }, + ) + + @staticmethod + def uniform_depolarizing(p: float) -> "NoiseModel": + """Near-standard circuit depolarizing noise. + + Everything has the same parameter p. + Single qubit clifford gates get single qubit depolarization. + Two qubit clifford gates get single qubit depolarization. + Dissipative gates have their result probabilistically bit flipped (or phase flipped if appropriate). + + Non-demolition measurement is treated a bit unusually in that it is the result that is flipped instead of + the input qubit. The input qubit is depolarized. + """ + return NoiseModel( + idle_noise=p, + any_clifford_1q_rule=NoiseRule(after={"DEPOLARIZE1": p}), + any_clifford_2q_rule=NoiseRule(after={"DEPOLARIZE2": p}), + measure_rules={ + "X": NoiseRule(after={"DEPOLARIZE1": p}, flip_result=p), + "Y": NoiseRule(after={"DEPOLARIZE1": p}, flip_result=p), + "Z": NoiseRule(after={"DEPOLARIZE1": p}, flip_result=p), + "XX": NoiseRule(after={"DEPOLARIZE2": p}, flip_result=p), + "YY": NoiseRule(after={"DEPOLARIZE2": p}, flip_result=p), + "ZZ": NoiseRule(after={"DEPOLARIZE2": p}, flip_result=p), + }, + gate_rules={ + "RX": NoiseRule(after={"Z_ERROR": p}), + "RY": NoiseRule(after={"X_ERROR": p}), + "R": NoiseRule(after={"X_ERROR": p}), + }, + ) + + def _noise_rule_for_split_operation( + self, + *, + split_op: stim.CircuitInstruction, + ) -> NoiseRule | None: + if occurs_in_classical_control_system(split_op): + return None + + rule = self.gate_rules.get(split_op.name) + if rule is not None: + return rule + + gate_data = stim.gate_data(split_op.name) + + if ( + self.any_clifford_1q_rule is not None + and gate_data.is_unitary + and gate_data.is_single_qubit_gate + ): + return self.any_clifford_1q_rule + if ( + self.any_clifford_2q_rule is not None + and gate_data.is_unitary + and gate_data.is_two_qubit_gate + ): + return self.any_clifford_2q_rule + if self.measure_rules is not None: + rule = self.measure_rules.get(_measure_basis(split_op=split_op)) + if rule is not None: + return rule + if self.any_measurement_rule is not None and gate_data.produces_measurements: + return self.any_measurement_rule + if gate_data.is_reset and gate_data.produces_measurements: + m_name, r_name = { + "MRX": ("MX", "RX"), + "MRY": ("MY", "RY"), + "MR": ("M", "R"), + }[gate_data.name] + r_noise = self._noise_rule_for_split_operation( + split_op=stim.CircuitInstruction(r_name, split_op.targets_copy()) + ) + m_noise = self._noise_rule_for_split_operation( + split_op=stim.CircuitInstruction(m_name, split_op.targets_copy()) + ) + return NoiseRule( + after=r_noise.after if r_noise is not None else {}, + flip_result=m_noise.flip_result if m_noise is not None else 0, + ) + + raise ValueError(f"No noise (or lack of noise) specified for {split_op=}.") + + def _append_idle_error( + self, + *, + moment_split_ops: list[stim.CircuitInstruction], + out: stim.Circuit, + system_qubit_indices: AbstractSet[int], + immune_qubit_indices: AbstractSet[int], + ) -> None: + collapse_qubits = [] + clifford_qubits = [] + for split_op in moment_split_ops: + if occurs_in_classical_control_system(split_op): + continue + gate_data = stim.gate_data(split_op.name) + if gate_data.is_reset or gate_data.produces_measurements: + qubits_out = collapse_qubits + else: + qubits_out = clifford_qubits + for target in split_op.targets_copy(): + if not target.is_combiner: + qubits_out.append(target.value) + + # Safety check for operation collisions. + usage_counts = collections.Counter(collapse_qubits + clifford_qubits) + qubits_used_multiple_times = {q for q, c in usage_counts.items() if c != 1} + if ( + qubits_used_multiple_times + and not self.allow_multiple_uses_of_a_qubit_in_one_tick + ): + moment = stim.Circuit() + for op in moment_split_ops: + moment.append(op) + raise ValueError( + f"Qubits were operated on multiple times without a TICK in between:\n" + f"multiple uses: {sorted(qubits_used_multiple_times)}\n" + f"moment:\n" + f"{moment}" + ) + + collapse_qubits_set = set(collapse_qubits) + clifford_qubits_set = set(clifford_qubits) + idle = sorted( + system_qubit_indices + - collapse_qubits_set + - clifford_qubits_set + - immune_qubit_indices + ) + if idle and self.idle_noise is not None: + for k, v in self.idle_noise.after.items(): + out.append(k, idle, v) + + waiting_for_mr = sorted( + system_qubit_indices - collapse_qubits_set - immune_qubit_indices + ) + if ( + collapse_qubits_set + and waiting_for_mr + and self.additional_depolarization_waiting_for_m_or_r + ): + out.append( + "DEPOLARIZE1", idle, self.additional_depolarization_waiting_for_m_or_r + ) + + if self.tick_noise is not None: + for k, p in self.tick_noise.after.items(): + out.append(k, system_qubit_indices - immune_qubit_indices, p) + + def _append_noisy_moment( + self, + *, + moment_split_ops: list[stim.CircuitInstruction], + out: stim.Circuit, + system_qubits_indices: AbstractSet[int], + immune_qubit_indices: AbstractSet[int], + ) -> None: + after = collections.defaultdict(stim.Circuit) + for split_op in moment_split_ops: + rule = self._noise_rule_for_split_operation(split_op=split_op) + if rule is None: + out.append(split_op) + else: + rule.append_noisy_version_of( + split_op=split_op, + out_during_moment=out, + after_moments=after, + immune_qubit_indices=immune_qubit_indices, + ) + for k in sorted(after.keys()): + out += after[k] + + self._append_idle_error( + moment_split_ops=moment_split_ops, + out=out, + system_qubit_indices=system_qubits_indices, + immune_qubit_indices=immune_qubit_indices, + ) + + def noisy_circuit( + self, + circuit: stim.Circuit, + *, + system_qubit_indices: AbstractSet[int] | None = None, + immune_qubit_indices: AbstractSet[int] | None = None, + ) -> stim.Circuit: + """Returns a noisy version of the given circuit, by applying the receiving noise model. + + Args: + circuit: The circuit to layer noise over. + system_qubit_indices: All qubits used by the circuit. These are the qubits eligible for idling noise. + immune_qubit_indices: Qubits to not apply noise to, even if they are operated on. + + Returns: + The noisy version of the circuit. + """ + if system_qubit_indices is None: + system_qubit_indices = set(range(circuit.num_qubits)) + if immune_qubit_indices is None: + immune_qubit_indices = set() + + result = stim.Circuit() + + first = True + for moment_split_ops in _iter_split_op_moments( + circuit, immune_qubit_indices=immune_qubit_indices + ): + if first: + first = False + elif result and isinstance(result[-1], stim.CircuitRepeatBlock): + pass + else: + result.append("TICK") + if isinstance(moment_split_ops, stim.CircuitRepeatBlock): + noisy_body = self.noisy_circuit( + moment_split_ops.body_copy(), + system_qubit_indices=system_qubit_indices, + immune_qubit_indices=immune_qubit_indices, + ) + noisy_body.append("TICK") + result.append( + stim.CircuitRepeatBlock( + repeat_count=moment_split_ops.repeat_count, body=noisy_body + ) + ) + else: + self._append_noisy_moment( + moment_split_ops=moment_split_ops, + out=result, + system_qubits_indices=system_qubit_indices, + immune_qubit_indices=immune_qubit_indices, + ) + + return result + + +def occurs_in_classical_control_system(op: stim.CircuitInstruction) -> bool: + """Determines if an operation is an annotation or a classical control system update.""" + if op.name in ANNOTATION_OPS: + return True + + gate_data = stim.gate_data(op.name) + if gate_data.is_unitary and gate_data.is_two_qubit_gate: + targets = op.targets_copy() + for k in range(0, len(targets), 2): + a = targets[k] + b = targets[k + 1] + classical_0 = a.is_measurement_record_target or a.is_sweep_bit_target + classical_1 = b.is_measurement_record_target or b.is_sweep_bit_target + if not (classical_0 or classical_1): + return False + return True + return False + + +def _split_targets_if_needed( + op: stim.CircuitInstruction, + immune_qubit_indices: AbstractSet[int], +) -> list[stim.CircuitInstruction]: + """Splits operations into pieces as needed (e.g. MPP into each product, classical control away from quantum ops).""" + gate_data = stim.gate_data(op.name) + if gate_data.is_unitary and gate_data.is_two_qubit_gate: + yield from _split_targets_if_needed_clifford_2q(op, immune_qubit_indices) + elif op.name == "MPP": + yield from _split_targets_if_needed_m_basis(op) + elif op.name in ANNOTATION_OPS: + yield op + elif gate_data.is_noisy_gate and not gate_data.produces_measurements: + yield op + elif gate_data.is_single_qubit_gate: + yield from _split_out_immune_targets_assuming_single_qubit_gate( + op, immune_qubit_indices + ) + else: + raise NotImplementedError(f"{op=}") + + +def _split_out_immune_targets_assuming_single_qubit_gate( + op: stim.CircuitInstruction, + immune_qubit_indices: AbstractSet[int], +) -> list[stim.CircuitInstruction]: + if immune_qubit_indices: + args = op.gate_args_copy() + for t in op.targets_copy(): + yield stim.CircuitInstruction(op.name, [t], args) + else: + yield op + + +def _split_targets_if_needed_clifford_2q( + op: stim.CircuitInstruction, + immune_qubit_indices: AbstractSet[int], +) -> list[stim.CircuitInstruction]: + """Splits classical control system operations away from things actually happening on the quantum computer.""" + gate_data = stim.gate_data(op.name) + assert gate_data.is_unitary and gate_data.is_two_qubit_gate + targets = op.targets_copy() + if immune_qubit_indices or any(t.is_measurement_record_target for t in targets): + args = op.gate_args_copy() + for k in range(0, len(targets), 2): + yield stim.CircuitInstruction(op.name, targets[k : k + 2], args) + else: + yield op + + +def _split_targets_if_needed_m_basis( + op: stim.CircuitInstruction, +) -> list[stim.CircuitInstruction]: + """Splits an MPP operation into one operation for each Pauli product it measures.""" + targets = op.targets_copy() + args = op.gate_args_copy() + k = 0 + start = k + while k < len(targets): + if k + 1 == len(targets) or not targets[k + 1].is_combiner: + yield stim.CircuitInstruction(op.name, targets[start : k + 1], args) + k += 1 + start = k + else: + k += 2 + assert k == len(targets) + + +def _iter_split_op_moments( + circuit: stim.Circuit, + *, + immune_qubit_indices: AbstractSet[int], +) -> Iterator[stim.CircuitRepeatBlock | list[stim.CircuitInstruction]]: + """Splits a circuit into moments and some operations into pieces. + + Classical control system operations like CX rec[-1] 0 are split from quantum operations like CX 1 0. + + MPP operations are split into one operation per Pauli product. + + Yields: + Lists of operations corresponding to one moment in the circuit, with any problematic operations + like MPPs split into pieces. + + (A moment is the time between two TICKs.) + """ + cur_moment = [] + + for op in circuit: + if isinstance(op, stim.CircuitRepeatBlock): + if cur_moment: + yield cur_moment + cur_moment = [] + yield op + elif isinstance(op, stim.CircuitInstruction): + if op.name == "TICK": + yield cur_moment + cur_moment = [] + else: + cur_moment.extend( + _split_targets_if_needed( + op, immune_qubit_indices=immune_qubit_indices + ) + ) + if cur_moment: + yield cur_moment + + +def _measure_basis(*, split_op: stim.CircuitInstruction) -> str | None: + """Converts an operation into a string describing the Pauli product basis it measures. + + Returns: + None: This is not a measurement (or not *just* a measurement). + str: Pauli product string that the operation measures (e.g. "XX" or "Y"). + """ + result = OP_TO_MEASURE_BASES.get(split_op.name) + if result == "*": + result = "" + targets = split_op.targets_copy() + for k in range(0, len(targets), 2): + t = targets[k] + if t.is_x_target: + result += "X" + elif t.is_y_target: + result += "Y" + elif t.is_z_target: + result += "Z" + else: + raise NotImplementedError(f"{targets=}") + return result diff --git a/src/gen/_core/_noise_test.py b/src/gen/_core/_noise_test.py new file mode 100644 index 0000000..70cf9c0 --- /dev/null +++ b/src/gen/_core/_noise_test.py @@ -0,0 +1,309 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +import gen +from gen._core._noise import ( + _measure_basis, + _iter_split_op_moments, + occurs_in_classical_control_system, + NoiseModel, +) + + +def test_measure_basis(): + f = lambda e: _measure_basis(split_op=stim.Circuit(e)[0]) + assert f("H") is None + assert f("H 0") is None + assert f("R 0 1 2") is None + + assert f("MX") == "X" + assert f("MX(0.01) 1") == "X" + assert f("MY 0 1") == "Y" + assert f("MZ 0 1 2") == "Z" + assert f("M 0 1 2") == "Z" + + assert f("MRX") is None + + assert f("MPP X5") == "X" + assert f("MPP X0*X2") == "XX" + assert f("MPP Y0*Z2*X3") == "YZX" + + +def test_iter_split_op_moments(): + assert ( + list( + _iter_split_op_moments( + stim.Circuit( + """ + """ + ), + immune_qubit_indices=set(), + ) + ) + == [] + ) + + assert ( + list( + _iter_split_op_moments( + stim.Circuit( + """ + H 0 + """ + ), + immune_qubit_indices=set(), + ) + ) + == [[stim.CircuitInstruction("H", [0])]] + ) + + assert ( + list( + _iter_split_op_moments( + stim.Circuit( + """ + H 0 + TICK + """ + ), + immune_qubit_indices=set(), + ) + ) + == [[stim.CircuitInstruction("H", [0])]] + ) + + assert ( + list( + _iter_split_op_moments( + stim.Circuit( + """ + H 0 1 + TICK + """ + ), + immune_qubit_indices=set(), + ) + ) + == [[stim.CircuitInstruction("H", [0, 1])]] + ) + + assert ( + list( + _iter_split_op_moments( + stim.Circuit( + """ + H 0 1 + TICK + """ + ), + immune_qubit_indices={3}, + ) + ) + == [ + [stim.CircuitInstruction("H", [0]), stim.CircuitInstruction("H", [1])], + ] + ) + + assert ( + list( + _iter_split_op_moments( + stim.Circuit( + """ + H 0 + TICK + H 1 + """ + ), + immune_qubit_indices=set(), + ) + ) + == [ + [stim.CircuitInstruction("H", [0])], + [stim.CircuitInstruction("H", [1])], + ] + ) + + assert ( + list( + _iter_split_op_moments( + stim.Circuit( + """ + CX rec[-1] 0 1 2 3 4 + MPP X5*X6 Y5 + CX 8 9 10 11 + TICK + H 0 + """ + ), + immune_qubit_indices=set(), + ) + ) + == [ + [ + stim.CircuitInstruction("CX", [stim.target_rec(-1), 0]), + stim.CircuitInstruction("CX", [1, 2]), + stim.CircuitInstruction("CX", [3, 4]), + stim.CircuitInstruction( + "MPP", [stim.target_x(5), stim.target_combiner(), stim.target_x(6)] + ), + stim.CircuitInstruction("MPP", [stim.target_y(5)]), + stim.CircuitInstruction("CX", [8, 9, 10, 11]), + ], + [ + stim.CircuitInstruction("H", [0]), + ], + ] + ) + + +def test_occurs_in_classical_control_system(): + assert not occurs_in_classical_control_system(op=stim.CircuitInstruction("H", [0])) + assert not occurs_in_classical_control_system( + op=stim.CircuitInstruction("CX", [0, 1, 2, 3]) + ) + assert not occurs_in_classical_control_system( + op=stim.CircuitInstruction("M", [0, 1, 2, 3]) + ) + + assert occurs_in_classical_control_system( + op=stim.CircuitInstruction("CX", [stim.target_rec(-1), 0]) + ) + assert occurs_in_classical_control_system( + op=stim.CircuitInstruction("DETECTOR", [stim.target_rec(-1)]) + ) + assert occurs_in_classical_control_system(op=stim.CircuitInstruction("TICK", [])) + assert occurs_in_classical_control_system( + op=stim.CircuitInstruction("SHIFT_COORDS", []) + ) + + +def test_si_1000(): + model = NoiseModel.si1000(1e-3) + assert ( + model.noisy_circuit( + stim.Circuit( + """ + R 0 1 2 3 + TICK + ISWAP 0 1 2 3 4 5 + TICK + H 4 5 6 7 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + R 0 1 2 3 + X_ERROR(0.002) 0 1 2 3 + DEPOLARIZE1(0.0001) 4 5 6 7 + DEPOLARIZE1(0.002) 4 5 6 7 + TICK + ISWAP 0 1 2 3 4 5 + DEPOLARIZE2(0.001) 0 1 2 3 4 5 + DEPOLARIZE1(0.0001) 6 7 + TICK + H 4 5 6 7 + DEPOLARIZE1(0.0001) 4 5 6 7 0 1 2 3 + TICK + M(0.005) 0 1 2 3 + DEPOLARIZE1(0.001) 0 1 2 3 + DEPOLARIZE1(0.0001) 4 5 6 7 + DEPOLARIZE1(0.002) 4 5 6 7 + """ + ) + ) + + +def test_measure_any(): + model = NoiseModel( + any_clifford_1q_rule=gen.NoiseRule(after={}), + any_clifford_2q_rule=gen.NoiseRule(after={}), + any_measurement_rule=gen.NoiseRule( + after={"DEPOLARIZE1": 0.125}, flip_result=0.25 + ), + measure_rules={"XX": gen.NoiseRule(flip_result=0.375, after={})}, + ) + assert ( + model.noisy_circuit( + stim.Circuit( + """ + H 0 + TICK + CX 0 1 + TICK + M 0 1 + TICK + MPP Z0*Z1 X2*X3 X4*X5*X6 + """ + ) + ) + == stim.Circuit( + """ + H 0 + TICK + CX 0 1 + TICK + M(0.25) 0 1 + DEPOLARIZE1(0.125) 0 1 + TICK + MPP(0.25) Z0*Z1 + MPP(0.375) X2*X3 + MPP(0.25) X4*X5*X6 + DEPOLARIZE1(0.125) 0 1 4 5 6 + """ + ) + ) + + +def test_tick_depolarization(): + model = NoiseModel( + any_clifford_1q_rule=gen.NoiseRule(after={}), + any_clifford_2q_rule=gen.NoiseRule(after={}), + tick_noise=gen.NoiseRule(after={"DEPOLARIZE1": 0.375}), + any_measurement_rule=gen.NoiseRule(after={}), + ) + assert ( + model.noisy_circuit( + stim.Circuit( + """ + H 0 + TICK + CX 0 1 + TICK + M 0 1 + TICK + MPP Z0*Z1 X2*X3 X4*X5*X6 + """ + ) + ) + == stim.Circuit( + """ + H 0 + DEPOLARIZE1(0.375) 0 1 2 3 4 5 6 + TICK + CX 0 1 + DEPOLARIZE1(0.375) 0 1 2 3 4 5 6 + TICK + M 0 1 + DEPOLARIZE1(0.375) 0 1 2 3 4 5 6 + TICK + MPP Z0*Z1 X2*X3 X4*X5*X6 + DEPOLARIZE1(0.375) 0 1 2 3 4 5 6 + """ + ) + ) diff --git a/src/gen/_core/_patch.py b/src/gen/_core/_patch.py new file mode 100644 index 0000000..675225a --- /dev/null +++ b/src/gen/_core/_patch.py @@ -0,0 +1,190 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import functools +import pathlib +from typing import Iterable, Callable, Literal + +from gen._core._util import sorted_complex, min_max_complex +from gen._core._tile import Tile +from gen._util import write_file + + +DESIRED_Z_TO_ORIENTATION: dict[str, str] = { + "X": "ZX", + "Y": "ZY", + "Z": "XZ", +} + + +class Patch: + """A collection of annotated stabilizers to measure simultaneously.""" + + def __init__(self, tiles: Iterable[Tile], *, do_not_sort: bool = False): + if do_not_sort: + self.tiles = tuple(tiles) + else: + self.tiles = tuple(sorted_complex(tiles, key=lambda e: e.measurement_qubit)) + + def with_transformed_coords( + self, coord_transform: Callable[[complex], complex] + ) -> "Patch": + return Patch( + [e.with_transformed_coords(coord_transform) for e in self.tiles], + ) + + def after_basis_transform( + self, + basis_transform: Callable[[Literal["X", "Y", "Z"]], Literal["X", "Y", "Z"]], + ) -> "Patch": + return Patch( + [e.after_basis_transform(basis_transform) for e in self.tiles], + ) + + def with_only_x_tiles(self) -> "Patch": + return Patch([tile for tile in self.tiles if tile.basis == "X"]) + + def with_only_y_tiles(self) -> "Patch": + return Patch([tile for tile in self.tiles if tile.basis == "Y"]) + + def with_only_z_tiles(self) -> "Patch": + return Patch([tile for tile in self.tiles if tile.basis == "Z"]) + + def without_wraparound_tiles(self) -> "Patch": + p_min, p_max = min_max_complex(self.data_set, default=0) + w = p_max.real - p_min.real + h = p_max.imag - p_min.imag + left = p_min.real + w * 0.1 + right = p_min.real + w * 0.9 + top = p_min.imag + h * 0.1 + bot = p_min.imag + h * 0.9 + + def keep_tile(tile: Tile) -> bool: + t_min, t_max = min_max_complex(tile.data_set, default=0) + if t_min.real < left and t_max.real > right: + return False + if t_min.imag < top and t_max.imag > bot: + return False + return True + + return Patch([t for t in self.tiles if keep_tile(t)]) + + @functools.cached_property + def m2tile(self) -> dict[complex, Tile]: + return {e.measurement_qubit: e for e in self.tiles} + + def with_opposite_order(self) -> "Patch": + return Patch( + tiles=[ + Tile( + bases=tile.bases[::-1], + measurement_qubit=tile.measurement_qubit, + ordered_data_qubits=tile.ordered_data_qubits[::-1], + ) + for tile in self.tiles + ] + ) + + def write_svg( + self, + path: str | pathlib.Path, + *, + split_xz: bool = False, + other: Iterable["Patch"] | "Patch" = (), + show_order: bool | Literal["undirected", "3couplerspecial"] = False, + show_measure_qubits: bool = False, + show_data_qubits: bool = False, + system_qubits: Iterable[complex] = (), + opacity: float = 1, + wraparound_clip: bool = False, + ) -> None: + from gen._viz_patch_svg import patch_svg_viewer + + patches = [self] + ([other] if isinstance(other, Patch) else list(other)) + if split_xz: + patches = [ + p2 + for p in patches + for p2 in [ + p, + p.with_only_x_tiles(), + p.with_only_y_tiles(), + p.with_only_z_tiles(), + ] + if p2.tiles + ] + + viewer = patch_svg_viewer( + patches=patches, + show_measure_qubits=show_measure_qubits, + show_data_qubits=show_data_qubits, + show_order=show_order, + available_qubits=system_qubits, + opacity=opacity, + wraparound_clip=wraparound_clip + ) + write_file(path, viewer) + + def with_xz_flipped(self) -> "Patch": + trans = {"X": "Z", "Y": "Y", "Z": "X"} + return self.after_basis_transform(trans.__getitem__) + + @functools.cached_property + def used_set(self) -> frozenset[complex]: + result = set() + for e in self.tiles: + result |= e.used_set + return frozenset(result) + + @functools.cached_property + def data_set(self) -> frozenset[complex]: + result = set() + for e in self.tiles: + for q in e.ordered_data_qubits: + if q is not None: + result.add(q) + return frozenset(result) + + def __eq__(self, other): + if not isinstance(other, Patch): + return NotImplemented + return self.tiles == other.tiles + + def __ne__(self, other): + return not (self == other) + + @functools.cached_property + def measure_set(self) -> frozenset[complex]: + return frozenset(e.measurement_qubit for e in self.tiles) + + def __repr__(self): + return "\n".join( + [ + "gen.Patch(tiles=[", + *[f" {e!r},".replace("\n", "\n ") for e in self.tiles], + "])", + ] + ) + + def with_reverse_order(self) -> "Patch": + return Patch( + tiles=[ + Tile( + bases=plaq.bases[::-1], + measurement_qubit=plaq.measurement_qubit, + ordered_data_qubits=plaq.ordered_data_qubits[::-1], + ) + for plaq in self.tiles + ], + ) diff --git a/src/gen/_core/_patch_test.py b/src/gen/_core/_patch_test.py new file mode 100644 index 0000000..0ed0419 --- /dev/null +++ b/src/gen/_core/_patch_test.py @@ -0,0 +1,19 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +from gen._core._builder import Builder +from gen._core._patch import Patch +from gen._core._tile import Tile diff --git a/src/gen/_core/_pauli_string.py b/src/gen/_core/_pauli_string.py new file mode 100644 index 0000000..ab25e72 --- /dev/null +++ b/src/gen/_core/_pauli_string.py @@ -0,0 +1,158 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Callable, Literal, TYPE_CHECKING, cast, Iterable, Dict + +import stim + +from gen._core._util import sorted_complex + +if TYPE_CHECKING: + import gen + + +class PauliString: + """A qubit-to-pauli mapping.""" + + def __init__(self, qubits: dict[complex, Literal["X", "Y", "Z"]]): + self.qubits = {q: qubits[q] for q in sorted_complex(qubits.keys())} + self._hash: int = hash(tuple(self.qubits.items())) + + @staticmethod + def from_stim_pauli_string(stim_pauli_string: stim.PauliString) -> "PauliString": + return PauliString( + { + q: "_XYZ"[stim_pauli_string[q]] + for q in range(len(stim_pauli_string)) + if stim_pauli_string[q] + } + ) + + @staticmethod + def from_tile_data(tile: "gen.Tile") -> "PauliString": + return PauliString( + { + k: v + for k, v in zip(tile.ordered_data_qubits, tile.bases) + if k is not None + } + ) + + @staticmethod + def from_xyzs( + *, + xs: Iterable[complex] = (), + ys: Iterable[complex] = (), + zs: Iterable[complex] = (), + ) -> "PauliString": + qs: dict[complex, Literal["X", "Y", "Z"]] = {} + for q in xs: + qs[q] = "X" + for q in ys: + p = qs.get(q) + if p is None: + qs[q] = "Y" + elif p == "X": + qs[q] = "Z" + else: + raise NotImplementedError(f"{p=}") + for q in zs: + p = qs.get(q) + if p is None: + qs[q] = "Z" + elif p == "X": + qs[q] = "Y" + elif p == "Y": + qs[q] = "X" + else: + raise NotImplementedError(f"{p=}") + return PauliString(qs) + + @staticmethod + def from_b2q( + b2q: dict[Literal["X", "Y", "Z"], Iterable[complex]], + ) -> "PauliString": + return PauliString.from_xyzs( + xs=b2q.get("X", ()), + ys=b2q.get("Y", ()), + zs=b2q.get("Z", ()), + ) + + def __bool__(self) -> bool: + return bool(self.qubits) + + def __mul__(self, other: "PauliString") -> "PauliString": + result: dict[complex, Literal["X", "Y", "Z"]] = {} + for q in self.qubits.keys() | other.qubits.keys(): + a = self.qubits.get(q, "I") + b = other.qubits.get(q, "I") + ax = a in "XY" + az = a in "YZ" + bx = b in "XY" + bz = b in "YZ" + cx = ax ^ bx + cz = az ^ bz + c = "IXZY"[cx + cz * 2] + if c != "I": + result[q] = cast(Literal["X", "Y", "Z"], c) + return PauliString(result) + + def __repr__(self) -> str: + return f"gen.PauliString(qubits={self.qubits!r})" + + def __str__(self) -> str: + return "*".join( + f"{self.qubits[q]}{q}" for q in sorted_complex(self.qubits.keys()) + ) + + def with_xz_flipped(self) -> "PauliString": + return PauliString( + { + q: "Z" if p == "X" else "X" if p == "Z" else p + for q, p in self.qubits.items() + } + ) + + def commutes(self, other: "PauliString") -> bool: + return not self.anticommutes(other) + + def anticommutes(self, other: "PauliString") -> bool: + t = 0 + for q in self.qubits.keys() & other.qubits.keys(): + t += self.qubits[q] != other.qubits[q] + return t % 2 == 1 + + def with_transformed_coords( + self, transform: Callable[[complex], complex] + ) -> "PauliString": + return PauliString({transform(q): p for q, p in self.qubits.items()}) + + def to_tile(self) -> "gen.Tile": + from gen._core._tile import Tile + + qs = list(self.qubits.keys()) + m = qs[0] if qs else 0 + return Tile( + bases="".join(self.qubits.values()), + ordered_data_qubits=qs, + measurement_qubit=m, + ) + + def __hash__(self) -> int: + return self._hash + + def __eq__(self, other) -> bool: + if not isinstance(other, PauliString): + return NotImplemented + return self.qubits == other.qubits diff --git a/src/gen/_core/_pauli_string_test.py b/src/gen/_core/_pauli_string_test.py new file mode 100644 index 0000000..199eab2 --- /dev/null +++ b/src/gen/_core/_pauli_string_test.py @@ -0,0 +1,25 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from gen._core._pauli_string import PauliString + + +def test_mul(): + a = "IIIIXXXXYYYYZZZZ" + b = "IXYZ" * 4 + c = "IXYZXIZYYZIXZYXI" + a = PauliString({q: p for q, p in enumerate(a) if p != "I"}) + b = PauliString({q: p for q, p in enumerate(b) if p != "I"}) + c = PauliString({q: p for q, p in enumerate(c) if p != "I"}) + assert a * b == c diff --git a/src/gen/_core/_stabilizer_code.py b/src/gen/_core/_stabilizer_code.py new file mode 100644 index 0000000..d2ef34c --- /dev/null +++ b/src/gen/_core/_stabilizer_code.py @@ -0,0 +1,442 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pathlib +from typing import Iterable, Literal, Any, Callable, Sequence + +import stim + +from gen._core._builder import Builder, AtLayer +from gen._core._noise import NoiseRule, NoiseModel +from gen._core._patch import Patch +from gen._core._pauli_string import PauliString +from gen._core._util import sorted_complex +from gen._util import write_file + + +class StabilizerCode: + """This class stores the stabilizers and observables of a stabilizer code. + + The exact semantics of the class are somewhat loose. For example, by default + this class doesn't verify that its fields actually form a valid stabilizer + code. This is so that the class can be used as a sort of useful data dumping + ground even in cases where what is being built isn't a stabilizer code. For + example, you can store a gauge code in the fields... it's just that methods + like 'make_code_capacity_circuit' will no longer work. + + The stabilizers are defined by the 'tiles' of the code's 'patch'. Each tile + defines data qubits and a measurement qubit. The measurement qubit is also a + very loose concept; it may literally represent a single ancilla qubit used + for measuring the stabilizer. Or it may be more like a unique key identifying + the tile, with no relation to any real qubit. + """ + + def __init__( + self, + *, + patch: Patch, + observables_x: Iterable[PauliString], + observables_z: Iterable[PauliString], + ): + self.patch = patch + self.observables_x = tuple(observables_x) + self.observables_z = tuple(observables_z) + + @staticmethod + def from_patch_with_inferred_observables(patch: Patch) -> "StabilizerCode": + """Creates a code by finding degrees of freedom leftover from stabilizers. + + If there are M linearly independent stabilizers covering N qubits, then the + returned code will have N-M observables. + """ + q2i = {q: i for i, q in enumerate(sorted_complex(patch.data_set))} + i2q = {i: q for q, i in q2i.items()} + + stabilizers: list[stim.PauliString] = [] + for tile in patch.tiles: + stabilizer = stim.PauliString(len(q2i)) + for p, q in zip(tile.bases, tile.ordered_data_qubits): + if q is not None: + stabilizer[q2i[q]] = p + stabilizers.append(stabilizer) + + stabilizer_set: set[str] = set(str(e) for e in stabilizers) + solved_tableau = stim.Tableau.from_stabilizers( + stabilizers, + allow_redundant=True, + allow_underconstrained=True, + ) + + obs_xs = [] + obs_zs = [] + + k: int = len(solved_tableau) + while k > 0 and str(solved_tableau.z_output(k - 1)) not in stabilizer_set: + k -= 1 + obs_xs.append( + PauliString.from_stim_pauli_string( + solved_tableau.x_output(k) + ).with_transformed_coords(i2q.__getitem__) + ) + obs_zs.append( + PauliString.from_stim_pauli_string( + solved_tableau.z_output(k) + ).with_transformed_coords(i2q.__getitem__) + ) + + return StabilizerCode(patch=patch, observables_x=obs_xs, observables_z=obs_zs) + + def entangled_observables( + self, ancilla_qubits_for_xz_pairs: Sequence[complex] | None + ) -> tuple[list[PauliString], list[complex]]: + """Makes XZ observables commute by entangling them with ancilla qubits. + + This is useful when attempting to test all observables simultaneously. + As long as noise is not applied to the ancilla qubits, the observables + returned by this method cover the same noise as the original observables + but the returned observables can be simultaneously measured. + """ + num_common = min(len(self.observables_x), len(self.observables_z)) + if ancilla_qubits_for_xz_pairs is None: + a = ( + min(q.real for q in self.patch.data_set) + + min(q.imag for q in self.patch.data_set) * 1j + - 1j + ) + ancilla_qubits_for_xz_pairs = [a + k for k in range(num_common)] + else: + assert len(ancilla_qubits_for_xz_pairs) == num_common + observables = [] + for k, obs in enumerate(self.observables_x): + if k < len(ancilla_qubits_for_xz_pairs): + a = ancilla_qubits_for_xz_pairs[k] + obs = obs * PauliString({a: "X"}) + observables.append(obs) + for k, obs in enumerate(self.observables_z): + if k < len(ancilla_qubits_for_xz_pairs): + a = ancilla_qubits_for_xz_pairs[k] + obs = obs * PauliString({a: "Z"}) + observables.append(obs) + return observables, list(ancilla_qubits_for_xz_pairs) + + def check_commutation_relationships(self) -> None: + """Verifies observables and stabilizers relate as a stabilizer code.""" + for tile in self.patch.tiles: + t = tile.to_data_pauli_string() + for obs in self.observables_x + self.observables_z: + if not obs.commutes(t): + raise ValueError( + f"Tile stabilizer {tile=} anticommutes with {obs=}." + ) + all_obs = self.observables_x + self.observables_z + anticommuting_pairs = set() + for k in range(min(len(self.observables_x), len(self.observables_z))): + anticommuting_pairs.add((k, k + len(self.observables_x))) + for k1 in range(len(all_obs)): + for k2 in range(k1 + 1, len(all_obs)): + obs1 = all_obs[k1] + obs2 = all_obs[k2] + if (k1, k2) in anticommuting_pairs: + if obs1.commutes(obs2): + raise ValueError( + f"X/Z observable pair commutes: {obs1=}, {obs2=}." + ) + else: + if not obs1.commutes(obs2): + raise ValueError( + f"Unpaired observables should commute: {obs1=}, {obs2=}." + ) + + def write_svg( + self, + path: str | pathlib.Path, + *, + show_order: bool | Literal["undirected", "3couplerspecial"] = False, + show_measure_qubits: bool = False, + show_data_qubits: bool = True, + system_qubits: Iterable[complex] = (), + opacity: float = 1, + ) -> None: + if not system_qubits: + if show_measure_qubits and show_data_qubits: + system_qubits = self.patch.used_set + elif show_measure_qubits: + system_qubits = self.patch.measure_set + elif show_data_qubits: + system_qubits = self.patch.data_set + + obs_patches = [] + for k in range(max(len(self.observables_x), len(self.observables_z))): + obs_tiles = [] + if k < len(self.observables_x): + obs_tiles.append(self.observables_x[k].to_tile()) + if k < len(self.observables_z): + obs_tiles.append(self.observables_z[k].to_tile()) + obs_patches.append(Patch(obs_tiles)) + + self.patch.write_svg( + path=path, + show_order=show_order, + show_data_qubits=show_data_qubits, + show_measure_qubits=show_measure_qubits, + system_qubits=system_qubits, + opacity=opacity, + other=obs_patches, + ) + + def with_transformed_coords( + self, coord_transform: Callable[[complex], complex] + ) -> "StabilizerCode": + return StabilizerCode( + patch=self.patch.with_transformed_coords(coord_transform), + observables_x=[ + e.with_transformed_coords(coord_transform) for e in self.observables_x + ], + observables_z=[ + e.with_transformed_coords(coord_transform) for e in self.observables_z + ], + ) + + def make_code_capacity_circuit( + self, + *, + noise: float | NoiseRule, + debug_out_dir: pathlib.Path | None = None, + ) -> stim.Circuit: + """Creates a circuit implementing this code with a code capacity noise model. + + A code capacity noise model represents transmission over a noisy network + with a noiseless sender and noiseless receiver. There is no noise from + applying operations or measuring stabilizers, and there aren't multiple rounds. + Encoding is done perfectly, then noise is applied to every data qubit, then + decoding is done perfectly. + + Args: + noise: Noise to apply to each data qubit, between the perfect encoding and + perfect decoding. If this is a float, it refers to the strength of a + `DEPOLARIZE1` noise channel. If it's a noise rule, the `after` specifies + the noise to apply to each data qubit (whereas any `flip_result` noise + specified by the rule will have no effect). + debug_out_dir: A location to write files useful for debugging, like a + picture of the stabilizers. + + Returns: + A stim circuit that encodes the code perfectly, applies code capacity noise, + then decodes the code. The circuit will check all observables simultaneously, + using noiseless ancilla qubits if necessary in order to turn anticommuting + observable pairs into commuting observables. + """ + if isinstance(noise, (int, float)): + noise = NoiseRule(after={"DEPOLARIZE1": noise}) + assert noise.flip_result == 0 + if debug_out_dir is not None: + self.write_svg(debug_out_dir / "code.svg") + self.patch.without_wraparound_tiles().write_svg( + debug_out_dir / "patch.svg", show_order=False + ) + circuit = _make_code_capacity_circuit_for_stabilizer_code( + code=self, + noise=noise, + ) + if debug_out_dir is not None: + from gen._viz_circuit_html import stim_circuit_html_viewer + + write_file(debug_out_dir / "detslice.svg", circuit.diagram("detslice-svg")) + write_file( + debug_out_dir / "graph.html", circuit.diagram("match-graph-3d-html") + ) + write_file( + debug_out_dir / "ideal_circuit.html", + stim_circuit_html_viewer(circuit, patch=self.patch), + ) + write_file( + debug_out_dir / "circuit.html", + stim_circuit_html_viewer(circuit.without_noise(), patch=self.patch), + ) + return circuit + + def make_phenom_circuit( + self, + *, + noise: float | NoiseRule | NoiseModel, + rounds: int, + debug_out_dir: pathlib.Path | None = None, + ) -> stim.Circuit: + """Creates a circuit implementing this code with a phenomenological noise model. + + A phenomenological noise model applies noise to data qubits between layers of + stabilizer measurements and to the measurement results produced by those + measurements. There is no noise accumulated between stabilizer measurements + in the same layer, or within one stabilizer measurement (like would happen + in a full circuit noise model where it was decomposed into multiple gates). + + Args: + noise: If this is a float, it refers to the strength of a `DEPOLARIZE1` noise + channel applied between each round and also the probability of flipping + each measurement result. If it's a noise rule, its `after` specifies + the noise to apply to each data qubit between each round, and its + `flip_result` is the probability of flipping each measurement result. + rounds: The number of times that the patch stabilizers are noisily measured. + There is an additional noiseless layer of measurements at the start and + at the end, to terminate the problem. Note that data noise is applied + both between normal rounds, and also between a round and one of these + special start/end layers. This means measurement noise is applied `rounds` + times, whereas between-round measurement is applied `rounds+1` times. So + code capacity noise occurs at `rounds=0`. + + TODO: redefine this so code cap noise is at rounds=1. + debug_out_dir: A location to write files useful for debugging, like a + picture of the stabilizers. + + Returns: + A stim circuit that encodes the code perfectly, performs R rounds of + phenomenological noise. then decodes the code perfect;y. The circuit + will check all observables simultaneously, using noiseless ancilla qubits + if necessary in order to turn anticommuting observable pairs into commuting observables. + """ + + if isinstance(noise, NoiseModel): + noise = NoiseRule( + after=noise.idle_noise.after, + flip_result=(noise.any_measurement_rule or noise.measure_rules['Z']).flip_result, + ) + if isinstance(noise, (int, float)): + noise = NoiseRule(after={"DEPOLARIZE1": noise}, flip_result=noise) + if debug_out_dir is not None: + self.write_svg(debug_out_dir / "code.svg") + self.patch.without_wraparound_tiles().write_svg( + debug_out_dir / "patch.svg", show_order=False + ) + circuit = _make_phenom_circuit_for_stabilizer_code( + code=self, + noise=noise, + rounds=rounds, + ) + if debug_out_dir is not None: + from gen._viz_circuit_html import stim_circuit_html_viewer + + write_file(debug_out_dir / "detslice.svg", circuit.diagram("detslice-svg")) + write_file( + debug_out_dir / "graph.html", circuit.diagram("match-graph-3d-html") + ) + write_file( + debug_out_dir / "ideal_circuit.html", + stim_circuit_html_viewer(circuit, patch=self.patch), + ) + write_file( + debug_out_dir / "circuit.html", + stim_circuit_html_viewer(circuit.without_noise(), patch=self.patch), + ) + return circuit + + def __repr__(self) -> str: + def indented(x: str) -> str: + return x.replace("\n", "\n ") + + def indented_repr(x: Any) -> str: + if isinstance(x, tuple): + return indented( + indented("[\n" + ",\n".join(indented_repr(e) for e in x)) + ",\n]" + ) + return indented(repr(x)) + + return f"""gen.StabilizerCode( + patch={indented_repr(self.patch)}, + observables_x={indented_repr(self.observables_x)}, + observables_z={indented_repr(self.observables_z)}, +)""" + + def __eq__(self, other) -> bool: + if not isinstance(other, StabilizerCode): + return NotImplemented + return ( + self.patch == other.patch + and self.observables_x == other.observables_x + and self.observables_z == other.observables_z + ) + + def __ne__(self, other) -> bool: + return not (self == other) + + +def _make_phenom_circuit_for_stabilizer_code( + *, + code: StabilizerCode, + noise: NoiseRule, + suggested_ancilla_qubits: list[complex] | None = None, + rounds: int, +) -> stim.Circuit: + observables, immune = code.entangled_observables( + ancilla_qubits_for_xz_pairs=suggested_ancilla_qubits, + ) + immune = set(immune) + builder = Builder.for_qubits(code.patch.data_set | immune) + + for k, obs in enumerate(observables): + builder.measure_pauli_string(obs, key=f"OBS_START{k}") + builder.obs_include([f"OBS_START{k}"], obs_index=k) + builder.measure_patch(code.patch, save_layer="init") + builder.tick() + + loop = builder.fork() + for k, p in noise.after.items(): + loop.circuit.append( + k, [builder.q2i[q] for q in sorted_complex(code.patch.data_set - immune)], p + ) + loop.measure_patch( + code.patch, save_layer="loop", cmp_layer="init", noise=noise.flip_result + ) + loop.shift_coords(dt=1) + loop.tick() + builder.circuit += loop.circuit * rounds + + builder.measure_patch(code.patch, save_layer="end", cmp_layer="loop") + for k, obs in enumerate(observables): + builder.measure_pauli_string(obs, key=f"OBS_END{k}") + builder.obs_include([f"OBS_END{k}"], obs_index=k) + + return builder.circuit + + +def _make_code_capacity_circuit_for_stabilizer_code( + *, + code: StabilizerCode, + noise: NoiseRule, + suggested_ancilla_qubits: list[complex] | None = None, +) -> stim.Circuit: + assert noise.flip_result == 0 + observables, immune = code.entangled_observables( + ancilla_qubits_for_xz_pairs=suggested_ancilla_qubits, + ) + immune = set(immune) + builder = Builder.for_qubits(code.patch.data_set | immune) + + for k, obs in enumerate(observables): + builder.measure_pauli_string(obs, key=f"OBS_START{k}") + builder.obs_include([f"OBS_START{k}"], obs_index=k) + builder.measure_patch(code.patch, save_layer="init") + builder.tick() + + for k, p in noise.after.items(): + builder.circuit.append( + k, [builder.q2i[q] for q in sorted_complex(code.patch.data_set - immune)], p + ) + builder.tick() + + builder.measure_patch(code.patch, save_layer="end", cmp_layer="init") + for k, obs in enumerate(observables): + builder.measure_pauli_string(obs, key=f"OBS_END{k}") + builder.obs_include([f"OBS_END{k}"], obs_index=k) + + return builder.circuit diff --git a/src/gen/_core/_stabilizer_code_test.py b/src/gen/_core/_stabilizer_code_test.py new file mode 100644 index 0000000..7915093 --- /dev/null +++ b/src/gen/_core/_stabilizer_code_test.py @@ -0,0 +1,160 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +import gen + + +def test_make_phenom_circuit_for_stabilizer_code(): + patch = gen.Patch( + [ + gen.Tile( + bases="Z", + ordered_data_qubits=[0, 1, 1j, 1 + 1j], + measurement_qubit=0.5 + 0.5j, + ), + gen.Tile( + bases="X", + ordered_data_qubits=[0, 1], + measurement_qubit=0.5, + ), + gen.Tile( + bases="X", + ordered_data_qubits=[0 + 1j, 1 + 1j], + measurement_qubit=0.5 + 1j, + ), + ] + ) + obs_x = gen.PauliString({0: "X", 1j: "X"}) + obs_z = gen.PauliString({0: "Z", 1: "Z"}) + + assert gen.StabilizerCode( + patch=patch, + observables_x=[obs_x], + observables_z=[obs_z], + ).make_phenom_circuit( + noise=gen.NoiseRule(flip_result=0.125, after={"DEPOLARIZE1": 0.25}), + rounds=100, + ) == stim.Circuit( + """ + QUBIT_COORDS(0, -1) 0 + QUBIT_COORDS(0, 0) 1 + QUBIT_COORDS(0, 1) 2 + QUBIT_COORDS(1, 0) 3 + QUBIT_COORDS(1, 1) 4 + MPP X0*X1*X2 + OBSERVABLE_INCLUDE(0) rec[-1] + MPP Z0*Z1*Z3 + OBSERVABLE_INCLUDE(1) rec[-1] + MPP X1*X3 Z1*Z2*Z3*Z4 X2*X4 + TICK + REPEAT 100 { + DEPOLARIZE1(0.25) 1 2 3 4 + MPP(0.125) X1*X3 Z1*Z2*Z3*Z4 X2*X4 + DETECTOR(0.5, 0, 0) rec[-6] rec[-3] + DETECTOR(0.5, 0.5, 0) rec[-5] rec[-2] + DETECTOR(0.5, 1, 0) rec[-4] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + } + MPP X1*X3 Z1*Z2*Z3*Z4 X2*X4 + DETECTOR(0.5, 0, 0) rec[-6] rec[-3] + DETECTOR(0.5, 0.5, 0) rec[-5] rec[-2] + DETECTOR(0.5, 1, 0) rec[-4] rec[-1] + MPP X0*X1*X2 + OBSERVABLE_INCLUDE(0) rec[-1] + MPP Z0*Z1*Z3 + OBSERVABLE_INCLUDE(1) rec[-1] + """ + ) + + +def test_make_code_capacity_circuit_for_stabilizer_code(): + patch = gen.Patch( + [ + gen.Tile( + bases="Z", + ordered_data_qubits=[0, 1, 1j, 1 + 1j], + measurement_qubit=0.5 + 0.5j, + ), + gen.Tile( + bases="X", + ordered_data_qubits=[0, 1], + measurement_qubit=0.5, + ), + gen.Tile( + bases="X", + ordered_data_qubits=[0 + 1j, 1 + 1j], + measurement_qubit=0.5 + 1j, + ), + ] + ) + obs_x = gen.PauliString({0: "X", 1j: "X"}) + obs_z = gen.PauliString({0: "Z", 1: "Z"}) + + assert gen.StabilizerCode( + patch=patch, + observables_x=[obs_x], + observables_z=[obs_z], + ).make_code_capacity_circuit( + noise=gen.NoiseRule(after={"DEPOLARIZE1": 0.25}), + ) == stim.Circuit( + """ + QUBIT_COORDS(0, -1) 0 + QUBIT_COORDS(0, 0) 1 + QUBIT_COORDS(0, 1) 2 + QUBIT_COORDS(1, 0) 3 + QUBIT_COORDS(1, 1) 4 + MPP X0*X1*X2 + OBSERVABLE_INCLUDE(0) rec[-1] + MPP Z0*Z1*Z3 + OBSERVABLE_INCLUDE(1) rec[-1] + MPP X1*X3 Z1*Z2*Z3*Z4 X2*X4 + TICK + DEPOLARIZE1(0.25) 1 2 3 4 + TICK + MPP X1*X3 Z1*Z2*Z3*Z4 X2*X4 + DETECTOR(0.5, 0, 0) rec[-6] rec[-3] + DETECTOR(0.5, 0.5, 0) rec[-5] rec[-2] + DETECTOR(0.5, 1, 0) rec[-4] rec[-1] + MPP X0*X1*X2 + OBSERVABLE_INCLUDE(0) rec[-1] + MPP Z0*Z1*Z3 + OBSERVABLE_INCLUDE(1) rec[-1] + """ + ) + + +def test_from_patch_with_inferred_observables(): + code = gen.StabilizerCode.from_patch_with_inferred_observables( + gen.Patch( + [ + gen.Tile( + bases="XZZX", ordered_data_qubits=[0, 1, 2, 3], measurement_qubit=0 + ), + gen.Tile( + bases="XZZX", ordered_data_qubits=[1, 2, 3, 4], measurement_qubit=1 + ), + gen.Tile( + bases="XZZX", ordered_data_qubits=[2, 3, 4, 0], measurement_qubit=2 + ), + gen.Tile( + bases="XZZX", ordered_data_qubits=[3, 4, 0, 1], measurement_qubit=3 + ), + ] + ) + ) + code.check_commutation_relationships() + assert len(code.observables_x) == len(code.observables_z) == 1 diff --git a/src/gen/_core/_tile.py b/src/gen/_core/_tile.py new file mode 100644 index 0000000..4c3a001 --- /dev/null +++ b/src/gen/_core/_tile.py @@ -0,0 +1,167 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import functools +from typing import Iterable, Callable, Literal, TYPE_CHECKING +from typing import cast + +if TYPE_CHECKING: + import gen + + +class Tile: + """A stabilizer with additional information related to how it is measured. + + Annotates the order in which data qubits are touched, the relevant basis of + each data qubit, and also the measurement ancilla. + """ + + def __init__( + self, + *, + bases: str, + measurement_qubit: complex, + ordered_data_qubits: Iterable[complex | None], + extra_coords: Iterable[float] = (), + ): + """ + Args: + bases: Basis of the stabilizer. A string of XYZ characters the same + length as the ordered_data_qubits argument. It is permitted to + give a single-character string, which will automatically be + expanded to the full length. For example, "X" will become "XXXX" + if there are four data qubits. + measurement_qubit: The ancilla qubit used to measure the stabilizer. + ordered_data_qubits: The data qubits in the stabilizer, in the order + that they are interacted with. Some entries may be None, + indicating that no data qubit is interacted with during the + corresponding interaction layer. + extra_coords: Extra coordinate data that can be used for custom + purposes. + """ + self.ordered_data_qubits = tuple(ordered_data_qubits) + self.measurement_qubit = measurement_qubit + if len(bases) == 1: + bases *= len(self.ordered_data_qubits) + self.bases: str = bases + self.extra_coords = tuple(extra_coords) + if len(self.bases) != len(self.ordered_data_qubits): + raise ValueError("len(self.bases_2) != len(self.data_qubits_order)") + + def to_data_pauli_string(self) -> "gen.PauliString": + from gen._core._pauli_string import PauliString + + return PauliString( + { + q: b + for q, b in zip(self.ordered_data_qubits, self.bases) + if q is not None + } + ) + + def with_data_qubit_cleared(self, q: complex) -> "Tile": + return Tile( + bases=self.bases, + measurement_qubit=self.measurement_qubit, + ordered_data_qubits=[ + None if d == q else d for d in self.ordered_data_qubits + ], + ) + + def with_xz_flipped(self) -> "Tile": + f = {"X": "Z", "Y": "Y", "Z": "X"} + return Tile( + bases="".join(f[e] for e in self.bases), + measurement_qubit=self.measurement_qubit, + ordered_data_qubits=self.ordered_data_qubits, + extra_coords=self.extra_coords, + ) + + def __eq__(self, other): + if not isinstance(other, Tile): + return False + return ( + self.ordered_data_qubits == other.ordered_data_qubits + and self.measurement_qubit == other.measurement_qubit + and self.bases == other.bases + and self.extra_coords == other.extra_coords + ) + + def __ne__(self, other): + return not (self == other) + + def __hash__(self): + return hash( + ( + Tile, + self.ordered_data_qubits, + self.measurement_qubit, + self.bases, + self.extra_coords, + ) + ) + + def __repr__(self): + b = self.basis or self.bases + extra = ( + "" + if not self.extra_coords + else f"\n extra_coords={self.extra_coords!r}," "" + ) + return f"""gen.Tile( + ordered_data_qubits={self.ordered_data_qubits!r}, + measurement_qubit={self.measurement_qubit!r}, + bases={b!r},{extra} +)""" + + def with_transformed_coords( + self, coord_transform: Callable[[complex], complex] + ) -> "Tile": + return Tile( + bases=self.bases, + ordered_data_qubits=[ + None if d is None else coord_transform(d) + for d in self.ordered_data_qubits + ], + measurement_qubit=coord_transform(self.measurement_qubit), + extra_coords=self.extra_coords, + ) + + def after_basis_transform( + self, + basis_transform: Callable[[Literal["X", "Y", "Z"]], Literal["X", "Y", "Z"]], + ) -> "Tile": + return Tile( + bases="".join( + basis_transform(cast(Literal["X", "Y", "Z"], e)) for e in self.bases + ), + ordered_data_qubits=self.ordered_data_qubits, + measurement_qubit=self.measurement_qubit, + extra_coords=self.extra_coords, + ) + + @functools.cached_property + def data_set(self) -> frozenset[complex]: + return frozenset(e for e in self.ordered_data_qubits if e is not None) + + @functools.cached_property + def used_set(self) -> frozenset[complex]: + return self.data_set | frozenset([self.measurement_qubit]) + + @functools.cached_property + def basis(self) -> Literal["X", "Y", "Z"] | None: + bs = {b for q, b in zip(self.ordered_data_qubits, self.bases) if q is not None} + if len(bs) != 1: + return None + return next(iter(bs)) diff --git a/src/gen/_core/_tile_test.py b/src/gen/_core/_tile_test.py new file mode 100644 index 0000000..7e978d2 --- /dev/null +++ b/src/gen/_core/_tile_test.py @@ -0,0 +1,32 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from gen._core._tile import Tile + + +def test_basis(): + tile = Tile(bases="XYZX", measurement_qubit=0, ordered_data_qubits=(1, 2, None, 3)) + assert tile.basis is None + + tile = Tile(bases="XXZX", measurement_qubit=0, ordered_data_qubits=(1, 2, None, 3)) + assert tile.basis == "X" + + tile = Tile(bases="XXX", measurement_qubit=0, ordered_data_qubits=(1, 2, 3)) + assert tile.basis == "X" + + tile = Tile(bases="ZZZ", measurement_qubit=0, ordered_data_qubits=(1, 2, 3)) + assert tile.basis == "Z" + + tile = Tile(bases="ZXZ", measurement_qubit=0, ordered_data_qubits=(1, 2, 3)) + assert tile.basis == None diff --git a/src/gen/_core/_util.py b/src/gen/_core/_util.py new file mode 100644 index 0000000..1dc29cc --- /dev/null +++ b/src/gen/_core/_util.py @@ -0,0 +1,56 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Callable, Iterable, TypeVar, Any + +TItem = TypeVar("TItem") + + +def complex_key(c: complex) -> Any: + return c.real != int(c.real), c.real, c.imag + + +def sorted_complex( + values: Iterable[TItem], *, key: Callable[[TItem], Any] = lambda e: e +) -> list[TItem]: + return sorted(values, key=lambda e: complex_key(key(e))) + + +def min_max_complex( + coords: Iterable[complex], *, default: complex | None = None +) -> tuple[complex, complex]: + """Computes the bounding box of a collection of complex numbers. + + Args: + coords: The complex numbers to place a bounding box around. + default: If no elements are included, the bounding box will cover this + single value when the collection of complex numbers is empty. If + this argument isn't set (or is set to None), an exception will be + raised instead when given an empty collection. + + Returns: + A pair of complex values (c_min, c_max) where c_min's real component + where c_min is the minimum corner of the bounding box and c_max is the + maximum corner of the bounding box. + """ + coords = list(coords) + if not coords and default is not None: + return default, default + real = [c.real for c in coords] + imag = [c.imag for c in coords] + min_r = min(real) + min_i = min(imag) + max_r = max(real) + max_i = max(imag) + return min_r + min_i * 1j, max_r + max_i * 1j diff --git a/src/gen/_core/_util_test.py b/src/gen/_core/_util_test.py new file mode 100644 index 0000000..c4d5fc4 --- /dev/null +++ b/src/gen/_core/_util_test.py @@ -0,0 +1,31 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +from gen._core._util import min_max_complex, sorted_complex + + +def test_sorted_complex(): + assert sorted_complex([1, 2j, 2, 1 + 2j]) == [2j, 1, 1 + 2j, 2] + + +def test_min_max_complex(): + with pytest.raises(ValueError): + min_max_complex([]) + assert min_max_complex([], default=0) == (0, 0) + assert min_max_complex([], default=1 + 2j) == (1 + 2j, 1 + 2j) + assert min_max_complex([1j], default=0) == (1j, 1j) + assert min_max_complex([1j, 2]) == (0, 2 + 1j) + assert min_max_complex([1j + 1, 2]) == (1, 2 + 1j) diff --git a/src/gen/_flows/__init__.py b/src/gen/_flows/__init__.py new file mode 100644 index 0000000..8ed085c --- /dev/null +++ b/src/gen/_flows/__init__.py @@ -0,0 +1,28 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from gen._flows._chunk import ( + Chunk, + ChunkLoop, +) +from gen._flows._flow import ( + Flow, +) +from gen._flows._flow_util import ( + compile_chunks_into_circuit, + magic_measure_for_flows, +) +from gen._flows._flow_verifier import ( + FlowStabilizerVerifier, +) diff --git a/src/gen/_flows/_chunk.py b/src/gen/_flows/_chunk.py new file mode 100644 index 0000000..0e902b1 --- /dev/null +++ b/src/gen/_flows/_chunk.py @@ -0,0 +1,344 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pathlib +from typing import Iterable, Callable, Union + +import sinter +import stim + +from gen._core._patch import Patch +from gen._core._tile import Tile +from gen._flows._flow import Flow, PauliString +from gen._util import stim_circuit_with_transformed_coords, write_file + + +class Chunk: + """A circuit chunk with accompanying stabilizer flow assertions.""" + + def __init__( + self, + circuit: stim.Circuit, + q2i: dict[complex, int], + flows: Iterable[Flow], + magic: bool = False, + discarded_inputs: Iterable[PauliString] = (), + discarded_outputs: Iterable[PauliString] = (), + ): + """ + Args: + circuit: The circuit implementing the chunk's functionality. + q2i: The coordinate-to-index mapping used by the circuit. + flows: A series of stabilizer flows that the circuit implements. + discarded_inputs: Explicitly rejected in flows. For example, a data + measurement chunk might reject flows for stabilizers from the + anticommuting basis. If they are not rejected, then compilation + will fail when attempting to combine this chunk with a preceding + chunk that has those stabilizers from the anticommuting basis + flowing out. + discarded_outputs: Explicitly rejected out flows. For example, an + initialization chunk might reject flows for stabilizers from the + anticommuting basis. If they are not rejected, then compilation + will fail when attempting to combine this chunk with a following + chunk that has those stabilizers from the anticommuting basis + flowing in. + magic: Whether or not the circuit is relying on magical noiseless + operations like noiselessly measuring entire observables. This + is useful when testing and debugging and initially building + circuits, but prevents them from being run on hardware. + """ + self.q2i = q2i + self.magic = magic + self.circuit = circuit + self.flows = tuple(flows) + self.discarded_inputs = discarded_inputs + self.discarded_outputs = discarded_outputs + + def __eq__(self, other): + if not isinstance(other, Chunk): + return NotImplemented + return ( + self.q2i == other.q2i + and self.magic == other.magic + and self.circuit == other.circuit + and self.flows == other.flows + and self.discarded_inputs == other.discarded_inputs + and self.discarded_outputs == other.discarded_outputs + ) + + def write_viewer( + self, path: str | pathlib.Path, *, patch: Patch | None = None + ) -> None: + from gen import stim_circuit_html_viewer + + if patch is None: + patch = self.start_patch() + if len(patch.tiles) == 0: + patch = self.end_patch() + write_file(path, stim_circuit_html_viewer(self.circuit, patch=patch)) + + def with_flows_postselected( + self, flow_predicate: Callable[[Flow], bool] + ) -> "Chunk": + return Chunk( + circuit=self.circuit, + q2i=self.q2i, + magic=self.magic, + flows=[ + flow.postselected() if flow_predicate(flow) else flow + for flow in self.flows + ], + discarded_inputs=self.discarded_inputs, + discarded_outputs=self.discarded_outputs, + ) + + def __mul__(self, other: int) -> "ChunkLoop": + return ChunkLoop([self], repetitions=other) + + def with_repetitions(self, repetitions: int) -> "ChunkLoop": + return ChunkLoop([self], repetitions=repetitions) + + def verify(self): + """Checks that this chunk's circuit actually implements its flows.""" + for key, group in sinter.group_by( + self.flows, key=lambda flow: (flow.start, flow.obs_index) + ).items(): + if key[0] and len(group) > 1: + raise ValueError(f"Multiple flows with same non-empty end: {group}") + for key, group in sinter.group_by( + self.flows, key=lambda flow: (flow.end, flow.obs_index) + ).items(): + if key[0] and len(group) > 1: + raise ValueError(f"Multiple flows with same non-empty end: {group}") + + from gen._flows._flow_verifier import FlowStabilizerVerifier + + FlowStabilizerVerifier.verify(self) + + def inverted(self) -> "Chunk": + """Checks that this chunk's circuit actually implements its flows.""" + from gen._flows._flow_verifier import FlowStabilizerVerifier + + return FlowStabilizerVerifier.invert(self) + + def with_xz_flipped(self) -> "Chunk": + return Chunk( + q2i=self.q2i, + magic=self.magic, + circuit=circuit_with_xz_flipped(self.circuit), + flows=[flow.with_xz_flipped() for flow in self.flows], + discarded_inputs=[p.with_xz_flipped() for p in self.discarded_inputs], + discarded_outputs=[p.with_xz_flipped() for p in self.discarded_outputs], + ) + + def with_transformed_coords( + self, transform: Callable[[complex], complex] + ) -> "Chunk": + return Chunk( + q2i={transform(q): i for q, i in self.q2i.items()}, + magic=self.magic, + circuit=stim_circuit_with_transformed_coords(self.circuit, transform), + flows=[flow.with_transformed_coords(transform) for flow in self.flows], + discarded_inputs=[ + p.with_transformed_coords(transform) for p in self.discarded_inputs + ], + discarded_outputs=[ + p.with_transformed_coords(transform) for p in self.discarded_outputs + ], + ) + + def magic_init_chunk(self) -> "Chunk": + """Returns a chunk that initializes the stabilizers needed by this one. + + The stabilizers are initialized using direct measurement by MPP, with + no care for connectivity or physical limitations of hardware. + """ + from gen._flows._flow_util import magic_init_for_chunk + + return magic_init_for_chunk(self) + + def magic_end_chunk(self) -> "Chunk": + """Returns a chunk that terminates the stabilizers produced by this one. + + The stabilizers are initialized using direct measurement by MPP, with + no care for connectivity or physical limitations of hardware. + """ + from gen._flows._flow_util import magic_measure_for_chunk + + return magic_measure_for_chunk(self) + + def _boundary_patch(self, end: bool) -> Patch: + tiles = [] + for flow in self.flows: + r = flow.end if end else flow.start + if r.qubits and flow.obs_index is None: + tiles.append( + Tile( + ordered_data_qubits=r.qubits.keys(), + bases="".join(r.qubits.values()), + measurement_qubit=list(r.qubits.keys())[0], + ) + ) + return Patch(tiles) + + def start_patch(self) -> Patch: + return self._boundary_patch(False) + + def flattened(self) -> list["Chunk"]: + return [self] + + def end_patch(self) -> Patch: + return self._boundary_patch(True) + + def tick_count(self) -> int: + return self.circuit.num_ticks + 1 + + +class ChunkLoop: + def __init__(self, chunks: Iterable[Union[Chunk, "ChunkLoop"]], repetitions: int): + self.chunks = tuple(chunks) + self.repetitions = repetitions + + @property + def magic(self) -> bool: + return any(c.magic for c in self.chunks) + + def verify(self): + for c in self.chunks: + c.verify() + for k in range(len(self.chunks)): + before: Chunk = self.chunks[k - 1] + after: Chunk = self.chunks[k] + after_in = {} + before_out = {} + for flow in before.flows: + if flow.end: + before_out[flow.end] = flow.obs_index + for flow in after.flows: + if flow.start: + after_in[flow.start] = flow.obs_index + for ps in before.discarded_outputs: + after_in.pop(ps) + for ps in after.discarded_inputs: + before_out.pop(ps) + if after_in != before_out: + raise ValueError("Flows don't match between chunks.") + + def __mul__(self, other: int) -> "ChunkLoop": + return self.with_repetitions(other * self.repetitions) + + def with_repetitions(self, new_repetitions: int) -> "ChunkLoop": + return ChunkLoop(chunks=self.chunks, repetitions=new_repetitions) + + def magic_init_chunk(self) -> "Chunk": + return self.chunks[0].magic_init_chunk() + + def magic_end_chunk(self) -> "Chunk": + return self.chunks[-1].magic_end_chunk() + + def start_patch(self) -> Patch: + return self.chunks[0].start_patch() + + def end_patch(self) -> Patch: + return self.chunks[-1].end_patch() + + def tick_count(self) -> int: + return sum(e.tick_count() for e in self.chunks) * self.repetitions + + def flattened(self) -> list["Chunk"]: + return [e for c in self.chunks for e in c.flattened()] + + +XZ_FLIPPED = { + "I": "I", + "X": "Z", + "Y": "Y", + "Z": "X", + "C_XYZ": "C_ZYX", + "C_ZYX": "C_XYZ", + "H": "H", + "H_XY": "H_YZ", + "H_XZ": "H_XZ", + "H_YZ": "H_XY", + "S": "SQRT_X", + "SQRT_X": "S", + "SQRT_X_DAG": "S_DAG", + "SQRT_Y": "SQRT_Y", + "SQRT_Y_DAG": "SQRT_Y_DAG", + "S_DAG": "SQRT_X_DAG", + "CX": "XCZ", + "CY": "XCY", + "CZ": "XCX", + "ISWAP": None, + "ISWAP_DAG": None, + "SQRT_XX": "SQRT_ZZ", + "SQRT_XX_DAG": "SQRT_ZZ_DAG", + "SQRT_YY": "SQRT_YY", + "SQRT_YY_DAG": "SQRT_YY_DAG", + "SQRT_ZZ": "SQRT_XX", + "SQRT_ZZ_DAG": "SQRT_XX_DAG", + "SWAP": "SWAP", + "XCX": "CZ", + "XCY": "CY", + "XCZ": "CX", + "YCX": "YCZ", + "YCY": "YCY", + "YCZ": "YCX", + "DEPOLARIZE1": "DEPOLARIZE1", + "DEPOLARIZE2": "DEPOLARIZE2", + "E": None, + "ELSE_CORRELATED_ERROR": None, + "PAULI_CHANNEL_1": None, + "PAULI_CHANNEL_2": None, + "X_ERROR": "Z_ERROR", + "Y_ERROR": "Y_ERROR", + "Z_ERROR": "X_ERROR", + "M": "MX", + "MPP": None, + "MR": "MRX", + "MRX": "MRZ", + "MRY": "MRY", + "MX": "M", + "MY": "MY", + "R": "RX", + "RX": "R", + "RY": "RY", + "DETECTOR": "DETECTOR", + "OBSERVABLE_INCLUDE": "OBSERVABLE_INCLUDE", + "QUBIT_COORDS": "QUBIT_COORDS", + "SHIFT_COORDS": "SHIFT_COORDS", + "TICK": "TICK", +} + + +def circuit_with_xz_flipped(circuit: stim.Circuit) -> stim.Circuit: + result = stim.Circuit() + for inst in circuit: + if isinstance(inst, stim.CircuitRepeatBlock): + result.append( + stim.CircuitRepeatBlock( + body=circuit_with_xz_flipped(inst.body_copy()), + repeat_count=inst.repeat_count, + ) + ) + else: + other = XZ_FLIPPED.get(inst.name) + if other is None: + raise NotImplementedError(f"{inst=}") + result.append( + stim.CircuitInstruction( + other, inst.targets_copy(), inst.gate_args_copy() + ) + ) + return result diff --git a/src/gen/_flows/_chunk_test.py b/src/gen/_flows/_chunk_test.py new file mode 100644 index 0000000..236065f --- /dev/null +++ b/src/gen/_flows/_chunk_test.py @@ -0,0 +1,112 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Iterable, Callable + +import stim + +import gen + + +def test_inverse_flows(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + R 0 1 2 3 4 + CX 2 0 + M 0 + """ + ), + q2i={0: 0, 1: 1, 2: 2, 3: 3, 4: 4}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({}), + measurement_indices=[0], + end=gen.PauliString({1: "Z"}), + ), + ], + ) + + inverted = chunk.inverted() + inverted.verify() + assert len(inverted.flows) == len(chunk.flows) + assert inverted.circuit == stim.Circuit( + """ + R 0 + CX 2 0 + M 4 3 2 1 0 + """ + ) + + +def test_inverse_circuit(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + R 0 1 2 3 4 + CX 2 0 3 4 + X 1 + M 0 + """ + ), + q2i={0: 0, 1: 1, 2: 2, 3: 3, 4: 4}, + flows=[], + ) + + inverted = chunk.inverted() + inverted.verify() + assert len(inverted.flows) == len(chunk.flows) + assert inverted.circuit == stim.Circuit( + """ + R 0 + X 1 + CX 3 4 2 0 + M 4 3 2 1 0 + """ + ) + + +def test_with_flows_postselected(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + R 0 + """ + ), + q2i={0: 0}, + flows=[ + gen.Flow( + center=0, + end=gen.PauliString({0: "Z"}), + ) + ], + ) + assert chunk.with_flows_postselected(lambda f: False) == chunk + assert chunk.with_flows_postselected(lambda f: True) != chunk + assert chunk.with_flows_postselected(lambda f: f.center == 1) == chunk + assert chunk.with_flows_postselected(lambda f: f.center == 0) == gen.Chunk( + circuit=stim.Circuit( + """ + R 0 + """ + ), + q2i={0: 0}, + flows=[ + gen.Flow( + center=0, + end=gen.PauliString({0: "Z"}), + ).postselected() + ], + ) diff --git a/src/gen/_flows/_flow.py b/src/gen/_flows/_flow.py new file mode 100644 index 0000000..29b63c7 --- /dev/null +++ b/src/gen/_flows/_flow.py @@ -0,0 +1,119 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Iterable, Any, Callable + +from gen._core import PauliString + + +class Flow: + """A rule for how a stabilizer travels into, through, and/or out of a chunk.""" + + def __init__( + self, + *, + start: PauliString | None = None, + end: PauliString | None = None, + measurement_indices: Iterable[int] = (), + obs_index: Any = None, + additional_coords: Iterable[float] = (), + center: complex, + postselect: bool = False, + allow_vacuous: bool = False, + ): + if not allow_vacuous: + assert start or end or measurement_indices, "vacuous flow" + self.start = PauliString({}) if start is None else start + self.end = PauliString({}) if end is None else end + self.measurement_indices: tuple[int, ...] = tuple(measurement_indices) + self.additional_coords = tuple(additional_coords) + self.obs_index = obs_index + self.center = center + self.postselect = postselect + + def __eq__(self, other): + if not isinstance(other, Flow): + return NotImplemented + return ( + self.start == other.start + and self.end == other.end + and self.measurement_indices == other.measurement_indices + and self.obs_index == other.obs_index + and self.additional_coords == other.additional_coords + and self.center == other.center + and self.postselect == other.postselect + ) + + def __repr__(self): + return ( + f"Flow(start={self.start!r}, " + f"end={self.end!r}, " + f"measurement_indices={self.measurement_indices!r}, " + f"additional_coords={self.additional_coords!r}, " + f"obs_index={self.obs_index!r}, " + f"postselect={self.postselect!r})" + ) + + def postselected(self) -> "Flow": + return Flow( + start=self.start, + end=self.end, + measurement_indices=self.measurement_indices, + obs_index=self.obs_index, + additional_coords=self.additional_coords, + center=self.center, + postselect=True, + ) + + def with_xz_flipped(self) -> "Flow": + return Flow( + start=self.start.with_xz_flipped(), + end=self.end.with_xz_flipped(), + measurement_indices=self.measurement_indices, + obs_index=self.obs_index, + additional_coords=self.additional_coords, + center=self.center, + postselect=self.postselect, + ) + + def with_transformed_coords( + self, transform: Callable[[complex], complex] + ) -> "Flow": + return Flow( + start=self.start.with_transformed_coords(transform), + end=self.end.with_transformed_coords(transform), + measurement_indices=self.measurement_indices, + obs_index=self.obs_index, + additional_coords=self.additional_coords, + center=transform(self.center), + postselect=self.postselect, + ) + + def concat(self, other: "Flow", other_measure_offset: int) -> "Flow": + if other.start != self.end: + raise ValueError("other.start != self.end") + if other.obs_index != self.obs_index: + raise ValueError("other.obs_index != self.obs_index") + if other.additional_coords != self.additional_coords: + raise ValueError("other.additional_coords != self.additional_coords") + return Flow( + start=self.start, + end=other.end, + center=(self.center + other.center) / 2, + measurement_indices=self.measurement_indices + + tuple(m + other_measure_offset for m in other.measurement_indices), + obs_index=self.obs_index, + additional_coords=self.additional_coords, + postselect=self.postselect or other.postselect, + ) diff --git a/src/gen/_flows/_flow_test.py b/src/gen/_flows/_flow_test.py new file mode 100644 index 0000000..4ee3ed2 --- /dev/null +++ b/src/gen/_flows/_flow_test.py @@ -0,0 +1,26 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from gen._flows._flow import Flow +from gen._core._pauli_string import PauliString + + +def test_with_xz_flipped(): + assert Flow( + start=PauliString({1: "X", 2: "Z"}), + center=0, + ).with_xz_flipped() == Flow( + start=PauliString({1: "Z", 2: "X"}), + center=0, + ) diff --git a/src/gen/_flows/_flow_util.py b/src/gen/_flows/_flow_util.py new file mode 100644 index 0000000..0c46b08 --- /dev/null +++ b/src/gen/_flows/_flow_util.py @@ -0,0 +1,406 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Union, Any, Literal, Iterable + +import stim + +from gen._core._builder import MeasurementTracker, Builder, AtLayer +from gen._core._util import sorted_complex +from gen._flows._chunk import Chunk, ChunkLoop +from gen._flows._flow import PauliString, Flow + + +def magic_init_for_chunk( + chunk: Chunk, +) -> Chunk: + builder = Builder( + q2i=chunk.q2i, + circuit=stim.Circuit(), + tracker=MeasurementTracker(), + ) + index = 0 + flows = [] + for flow in chunk.flows: + if flow.start: + builder.measure_pauli_string(flow.start, key=AtLayer(index, "solo")) + flows.append( + Flow( + center=flow.center, + end=flow.start, + measurement_indices=[index], + obs_index=flow.obs_index, + additional_coords=flow.additional_coords, + ) + ) + index += 1 + + return Chunk( + circuit=builder.circuit, + q2i=builder.q2i, + flows=flows, + magic=True, + ) + + +def magic_measure_for_chunk( + chunk: Chunk, +) -> Chunk: + return magic_measure_for_flows(chunk.flows) + + +def magic_measure_for_flows( + flows: list[Flow], +) -> Chunk: + all_qubits = sorted_complex({q for flow in flows for q in (flow.end.qubits or [])}) + q2i = {q: i for i, q in enumerate(all_qubits)} + builder = Builder( + q2i=q2i, + circuit=stim.Circuit(), + tracker=MeasurementTracker(), + ) + index = 0 + out_flows = [] + for flow in flows: + if flow.end: + key = AtLayer(index, "solo") + builder.measure_pauli_string(flow.end, key=key) + out_flows.append( + Flow( + center=flow.center, + start=flow.end, + measurement_indices=[index], + obs_index=flow.obs_index, + additional_coords=flow.additional_coords, + ) + ) + index += 1 + + return Chunk( + circuit=builder.circuit, + q2i=builder.q2i, + flows=out_flows, + magic=True, + ) + + +def _append_circuit_with_reindexed_qubits_to_circuit( + *, + circuit: stim.Circuit, + old_q2i: dict[complex, int], + new_q2i: dict[complex, int], + out: stim.Circuit, +) -> None: + i2i = {i: new_q2i[q] for q, i in old_q2i.items()} + + for inst in circuit: + if isinstance(inst, stim.CircuitRepeatBlock): + block = stim.Circuit() + _append_circuit_with_reindexed_qubits_to_circuit( + circuit=inst.body_copy(), + old_q2i=old_q2i, + new_q2i=new_q2i, + out=block, + ) + out.append( + stim.CircuitRepeatBlock(repeat_count=inst.repeat_count, body=block) + ) + elif isinstance(inst, stim.CircuitInstruction): + if inst.name == "QUBIT_COORDS": + continue + targets = [] + for t in inst.targets_copy(): + if t.is_qubit_target: + targets.append(i2i[t.value]) + elif t.is_x_target: + targets.append(stim.target_x(i2i[t.value])) + elif t.is_y_target: + targets.append(stim.target_y(i2i[t.value])) + elif t.is_z_target: + targets.append(stim.target_z(i2i[t.value])) + elif t.is_combiner: + targets.append(t) + elif t.is_measurement_record_target: + targets.append(t) + else: + raise NotImplementedError(f"{inst=}") + out.append(inst.name, targets, inst.gate_args_copy()) + else: + raise NotImplementedError(f"{inst=}") + + +class _ChunkCompileState: + def __init__( + self, + *, + open_flows: dict[tuple[PauliString, Any], Union[Flow, Literal["discard"]]], + measure_offset: int, + ): + self.open_flows = open_flows + self.measure_offset = measure_offset + + +def _compile_chunk_into_circuit_many_repetitions( + *, + chunk_loop: ChunkLoop, + state: _ChunkCompileState, + include_detectors: bool, + ignore_errors: bool, + out_circuit: stim.Circuit, + q2i: dict[complex, int], +) -> _ChunkCompileState: + if chunk_loop.repetitions == 0: + return state + if chunk_loop.repetitions == 1: + return _compile_chunk_into_circuit_sequence( + chunks=chunk_loop.chunks, + state=state, + include_detectors=include_detectors, + ignore_errors=ignore_errors, + out_circuit=out_circuit, + q2i=q2i, + ) + assert chunk_loop.repetitions > 1 + + no_reps_loop = chunk_loop.with_repetitions(1) + circuits = [] + measure_offset_start_of_loop = state.measure_offset + while len(circuits) < chunk_loop.repetitions: + fully_in_loop = ( + len(circuits) > 0 + and min( + [ + m + for flow in state.open_flows.values() + if isinstance(flow, Flow) + for m in flow.measurement_indices + ], + default=measure_offset_start_of_loop, + ) + >= measure_offset_start_of_loop + ) + + circuits.append(stim.Circuit()) + state = _compile_chunk_into_circuit( + chunk=no_reps_loop, + state=state, + include_detectors=include_detectors, + ignore_errors=ignore_errors, + out_circuit=circuits[-1], + q2i=q2i, + ) + + if fully_in_loop: + # The circuit is guaranteed to repeat now. Don't do each iteration individually. + finish_reps = chunk_loop.repetitions - len(circuits) + 1 + while len(circuits) > 1 and circuits[-1] == circuits[-2]: + finish_reps += 1 + circuits.pop() + circuits[-1] *= finish_reps + break + + # Fuse iterations that happened to be equal. + k = 0 + while k < len(circuits): + k2 = k + 1 + while k2 < len(circuits) and circuits[k2] == circuits[k]: + k2 += 1 + out_circuit += circuits[k] * (k2 - k) + k = k2 + + return state + + +def _compile_chunk_into_circuit_sequence( + *, + chunks: Iterable[Union[Chunk, ChunkLoop]], + state: _ChunkCompileState, + include_detectors: bool, + ignore_errors: bool, + out_circuit: stim.Circuit, + q2i: dict[complex, int], +) -> _ChunkCompileState: + for sub_chunk in chunks: + state = _compile_chunk_into_circuit( + chunk=sub_chunk, + state=state, + include_detectors=include_detectors, + ignore_errors=ignore_errors, + out_circuit=out_circuit, + q2i=q2i, + ) + return state + + +def _compile_chunk_into_circuit_atomic( + *, + chunk: Chunk, + state: _ChunkCompileState, + include_detectors: bool, + ignore_errors: bool, + out_circuit: stim.Circuit, + q2i: dict[complex, int], +) -> _ChunkCompileState: + prev_flows = dict(state.open_flows) + next_flows: dict[tuple[PauliString, Any], Union[Flow, Literal["discard"]]] = {} + dumped_flows: list[Flow] = [] + if include_detectors: + for flow in chunk.flows: + flow = Flow( + center=flow.center, + start=flow.start, + end=flow.end, + obs_index=flow.obs_index, + measurement_indices=[ + m + state.measure_offset for m in flow.measurement_indices + ], + postselect=flow.postselect, + additional_coords=flow.additional_coords, + ) + if flow.start: + prev = prev_flows.pop((flow.start, flow.obs_index), None) + if prev is None: + if ignore_errors: + continue + else: + raise ValueError(f"Missing prev {flow!r} have {prev_flows!r}") + elif prev == "discard": + if flow.end: + next_flows[(flow.end, flow.obs_index)] = "discard" + continue + flow = prev.concat(flow, 0) + if flow.end: + if flow.obs_index is not None and flow.measurement_indices: + dumped_flows.append(flow) + flow = Flow( + start=flow.start, + end=flow.end, + obs_index=flow.obs_index, + center=flow.center, + ) + next_flows[(flow.end, flow.obs_index)] = flow + else: + dumped_flows.append(flow) + for discarded in chunk.discarded_inputs: + prev_flows.pop((discarded, None), None) + for discarded in chunk.discarded_outputs: + assert (discarded, None) not in next_flows + next_flows[(discarded, None)] = "discard" + for flow, val in prev_flows.items(): + if val != "discard" and not ignore_errors: + raise ValueError( + f"Some flows were left over (not matched) when moving into chunk: {list(prev_flows.values())!r}" + ) + + new_measure_offset = state.measure_offset + chunk.circuit.num_measurements + _append_circuit_with_reindexed_qubits_to_circuit( + circuit=chunk.circuit, out=out_circuit, old_q2i=chunk.q2i, new_q2i=q2i + ) + if include_detectors: + any_detectors = False + for flow in dumped_flows: + targets = [] + for m in flow.measurement_indices: + targets.append(stim.target_rec(m - new_measure_offset)) + if flow.obs_index is None: + coords = (flow.center.real, flow.center.imag, 0) + if flow.additional_coords: + coords += flow.additional_coords + if flow.postselect: + coords += (999,) + out_circuit.append("DETECTOR", targets, coords) + any_detectors = True + else: + out_circuit.append("OBSERVABLE_INCLUDE", targets, flow.obs_index) + if any_detectors: + out_circuit.append("SHIFT_COORDS", [], (0, 0, 1)) + if len(out_circuit) > 0 and out_circuit[-1].name != "TICK": + out_circuit.append("TICK") + + return _ChunkCompileState( + measure_offset=new_measure_offset, + open_flows=next_flows, + ) + + +def _compile_chunk_into_circuit( + *, + chunk: Union[Chunk, ChunkLoop], + state: _ChunkCompileState, + include_detectors: bool, + ignore_errors: bool, + out_circuit: stim.Circuit, + q2i: dict[complex, int], +) -> _ChunkCompileState: + if isinstance(chunk, ChunkLoop): + return _compile_chunk_into_circuit_many_repetitions( + chunk_loop=chunk, + state=state, + include_detectors=include_detectors, + ignore_errors=ignore_errors, + out_circuit=out_circuit, + q2i=q2i, + ) + + return _compile_chunk_into_circuit_atomic( + chunk=chunk, + state=state, + include_detectors=include_detectors, + ignore_errors=ignore_errors, + out_circuit=out_circuit, + q2i=q2i, + ) + + +def compile_chunks_into_circuit( + chunks: list[Union[Chunk, ChunkLoop]], + *, + include_detectors: bool = True, + ignore_errors: bool = False, +) -> stim.Circuit: + all_qubits = set() + + def _process(sub_chunk: Union[Chunk, ChunkLoop]): + nonlocal all_qubits + if isinstance(sub_chunk, ChunkLoop): + for sub_sub_chunk in sub_chunk.chunks: + _process(sub_sub_chunk) + elif isinstance(sub_chunk, Chunk): + all_qubits |= sub_chunk.q2i.keys() + else: + raise NotImplementedError(f"{sub_chunk=}") + + for c in chunks: + _process(c) + + q2i = {q: i for i, q in enumerate(sorted_complex(set(all_qubits)))} + full_circuit = stim.Circuit() + for q, i in q2i.items(): + full_circuit.append("QUBIT_COORDS", i, [q.real, q.imag]) + + state = _ChunkCompileState(open_flows={}, measure_offset=0) + for k, chunk in enumerate(chunks): + state = _compile_chunk_into_circuit( + chunk=chunk, + state=state, + include_detectors=include_detectors, + ignore_errors=ignore_errors, + out_circuit=full_circuit, + q2i=q2i, + ) + if include_detectors: + if state.open_flows: + if not ignore_errors: + raise ValueError("Unterminated") + return full_circuit diff --git a/src/gen/_flows/_flow_util_test.py b/src/gen/_flows/_flow_util_test.py new file mode 100644 index 0000000..f0f8463 --- /dev/null +++ b/src/gen/_flows/_flow_util_test.py @@ -0,0 +1,189 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +import gen + + +def test_magic_init_for_chunk(): + chunk = gen.Chunk( + circuit=stim.Circuit(), + q2i={0: 0, 1j: 1, 2j: 2}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1j: "Y", 2j: "Z"}), + ), + gen.Flow( + center=0, + start=gen.PauliString({0: "Y", 1j: "X", 2j: "Z"}), + obs_index=1, + ), + ], + ) + c2 = chunk.magic_init_chunk() + c2.verify() + + +def test_compile_postselected_chunks(): + chunk1 = gen.Chunk( + circuit=stim.Circuit( + """ + R 0 + """ + ), + q2i={0: 0}, + flows=[ + gen.Flow( + center=0, + end=gen.PauliString({0: "Z"}), + ) + ], + ) + chunk2 = gen.Chunk( + circuit=stim.Circuit( + """ + M 0 + """ + ), + q2i={0: 0}, + flows=[ + gen.Flow( + center=0, + end=gen.PauliString({0: "Z"}), + measurement_indices=[0], + ), + gen.Flow( + center=0, + start=gen.PauliString({0: "Z"}), + measurement_indices=[0], + ), + ], + ) + chunk3 = gen.Chunk( + circuit=stim.Circuit( + """ + MR 0 + """ + ), + q2i={0: 0}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "Z"}), + measurement_indices=[0], + ) + ], + ) + + assert gen.compile_chunks_into_circuit( + [ + chunk1, + chunk2, + chunk3, + ] + ).flattened() == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + R 0 + TICK + M 0 + DETECTOR(0, 0, 0) rec[-1] + TICK + MR 0 + DETECTOR(0, 0, 1) rec[-2] rec[-1] + TICK + """ + ) + + assert gen.compile_chunks_into_circuit( + [ + chunk1.with_flows_postselected(lambda f: True), + chunk2, + chunk3, + ] + ).flattened() == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + R 0 + TICK + M 0 + DETECTOR(0, 0, 0, 999) rec[-1] + TICK + MR 0 + DETECTOR(0, 0, 1) rec[-2] rec[-1] + TICK + """ + ) + + assert gen.compile_chunks_into_circuit( + [ + chunk1, + chunk2.with_flows_postselected(lambda f: True), + chunk3, + ] + ).flattened() == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + R 0 + TICK + M 0 + DETECTOR(0, 0, 0, 999) rec[-1] + TICK + MR 0 + DETECTOR(0, 0, 1, 999) rec[-2] rec[-1] + TICK + """ + ) + + assert gen.compile_chunks_into_circuit( + [ + chunk1, + chunk2, + chunk3.with_flows_postselected(lambda f: True), + ] + ).flattened() == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + R 0 + TICK + M 0 + DETECTOR(0, 0, 0) rec[-1] + TICK + MR 0 + DETECTOR(0, 0, 1, 999) rec[-2] rec[-1] + TICK + """ + ) + + assert gen.compile_chunks_into_circuit( + [ + chunk1, + chunk2.with_flows_postselected(lambda f: f.start), + chunk3, + ] + ).flattened() == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + R 0 + TICK + M 0 + DETECTOR(0, 0, 0, 999) rec[-1] + TICK + MR 0 + DETECTOR(0, 0, 1) rec[-2] rec[-1] + TICK + """ + ) diff --git a/src/gen/_flows/_flow_verifier.py b/src/gen/_flows/_flow_verifier.py new file mode 100644 index 0000000..bcf438c --- /dev/null +++ b/src/gen/_flows/_flow_verifier.py @@ -0,0 +1,593 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import collections +from typing import Iterable + +import numpy as np +import stim + +from gen._flows._flow import Flow +from gen._flows._chunk import Chunk + + +FLIP_REV_SET = { + "CX", + "CY", + "CZ", + "XCY", +} +REV_DICT = { + "I": "I", + "X": "X", + "Y": "Y", + "Z": "Z", + "C_XYZ": "C_ZYX", + "C_ZYX": "C_XYZ", + "H": "H", + "H_XY": "H_XY", + "H_XZ": "H_XZ", + "H_YZ": "H_YZ", + "S": "S", + "SQRT_X": "SQRT_X", + "SQRT_X_DAG": "SQRT_X", + "SQRT_Y": "SQRT_Y", + "SQRT_Y_DAG": "SQRT_Y", + "S_DAG": "S", + "CX": "XCZ", + "CY": "YCZ", + "CZ": "CZ", + "ISWAP": "ISWAP", + "ISWAP_DAG": "ISWAP", + "SQRT_XX": "SQRT_XX", + "SQRT_XX_DAG": "SQRT_XX", + "SQRT_YY": "SQRT_YY", + "SQRT_YY_DAG": "SQRT_YY", + "SQRT_ZZ": "SQRT_ZZ", + "SQRT_ZZ_DAG": "SQRT_ZZ", + "SWAP": "SWAP", + "XCX": "XCX", + "CXSWAP": "CXSWAP", + "SWAPCX": "SWAPCX", + "XCY": "YCX", + "XCZ": "CX", + "YCX": "XCY", + "YCY": "YCY", + "YCZ": "CY", + "SHIFT_COORDS": "SHIFT_COORDS", + "TICK": "TICK", +} + + +class FlowStabilizerVerifier: + def __init__( + self, next_measurement: int, q2i: dict[complex, int], flows: Iterable[Flow] + ): + self.flows: tuple[Flow, ...] = tuple(flows) + self.q2i = q2i + self.i2m = collections.defaultdict(list) + self.measurement_to_can_be_destructive: set[int] = set() + self.reset_index = 0 + self.next_measurement = next_measurement + self.reset_to_flow_indices: collections.defaultdict[ + int, list[int] + ] = collections.defaultdict(list) + num_qubits = max(q2i.values()) + 1 + self.xs = np.zeros(shape=(num_qubits, len(self.flows)), dtype=np.bool_) + self.zs = np.zeros(shape=(num_qubits, len(self.flows)), dtype=np.bool_) + for k in range(len(self.flows)): + flow: Flow = self.flows[k] + for m in flow.measurement_indices: + self.i2m[m].append(k) + for q, p in flow.end.qubits.items(): + assert p == "X" or p == "Y" or p == "Z" + self.xs[q2i[q], k] = p == "X" or p == "Y" + self.zs[q2i[q], k] = p == "Z" or p == "Y" + + def fail_if(self, mask: np.ndarray, msg: str): + if np.any(mask): + for k in range(len(mask)): + if mask[k]: + self.fail(k, msg) + + def pauli_terms(self, k: int) -> str: + i2q = {i: q for q, i in self.q2i.items()} + terms = [] + for q in range(self.xs.shape[0]): + x = self.xs[q, k] + z = self.zs[q, k] + if x or z: + terms.append("_XZY"[x + z * 2] + repr(i2q[q])) + return "*".join(terms) + + def fail(self, k: int, msg: str): + raise ValueError( + f"{msg} for flow {self.flows[k]} with current value {self.pauli_terms(k)}" + ) + + def finish(self): + for k in range(len(self.flows)): + for q, p in self.flows[k].start.qubits.items(): + assert p == "X" or p == "Y" or p == "Z" + self.xs[self.q2i[q], k] ^= p == "X" or p == "Y" + self.zs[self.q2i[q], k] ^= p == "Z" or p == "Y" + if np.any(self.xs) or np.any(self.zs): + for k in range(len(self.flows)): + if np.any(self.xs[:, k]) or np.any(self.zs[:, k]): + self.fail(k, "Mismatch at start") + + @staticmethod + def verify(chunk: "Chunk") -> "FlowStabilizerVerifier": + verifier = FlowStabilizerVerifier( + q2i=chunk.q2i, + flows=chunk.flows, + next_measurement=chunk.circuit.num_measurements - 1, + ) + for inst in chunk.circuit.flattened()[::-1]: + verifier.rev_apply(inst) + verifier.finish() + return verifier + + @staticmethod + def invert(chunk: "Chunk") -> Chunk: + v = FlowStabilizerVerifier.verify(chunk) + measurement_to_flow_indices: collections.defaultdict[ + int, list[int] + ] = collections.defaultdict(list) + for k, flow in enumerate(chunk.flows): + for m in flow.measurement_indices: + measurement_to_flow_indices[m].append(k) + + header = stim.Circuit() + rev_circuit = stim.Circuit() + new_flow_measurements: list[list[int]] = [[] for _ in range(len(v.flows))] + reset_index = 0 + new_measure_index = 0 + old_measure_index = chunk.circuit.num_measurements + for inst in chunk.circuit.flattened()[::-1]: + if inst.name in FLIP_REV_SET: + old_targets = inst.targets_copy() + new_targets = [ + old_targets[k + i] + for k in range(0, len(old_targets), 2)[::-1] + for i in range(2) + ] + rev_circuit.append(inst.name, new_targets, inst.gate_args_copy()) + elif inst.name in REV_DICT: + rev_circuit.append( + REV_DICT[inst.name], + inst.targets_copy()[::-1], + inst.gate_args_copy(), + ) + elif inst.name in ["R", "RX", "RY"]: + ts = inst.targets_copy()[::-1] + rev_circuit.append( + inst.name.replace("R", "M"), ts, inst.gate_args_copy() + ) + for k in range(len(ts)): + for f in v.reset_to_flow_indices[reset_index]: + new_flow_measurements[f].append(new_measure_index) + new_measure_index += 1 + reset_index += 1 + elif inst.name in ["M", "MX", "MY"]: + ts = inst.targets_copy()[::-1] + if all( + old_measure_index - k - 1 in v.measurement_to_can_be_destructive + for k in range(len(ts)) + ): + rev_circuit.append( + inst.name.replace("M", "R"), ts, inst.gate_args_copy() + ) + old_measure_index -= len(ts) + else: + rev_circuit.append(inst.name, ts, inst.gate_args_copy()) + for k in range(len(ts)): + for f in measurement_to_flow_indices[old_measure_index]: + new_flow_measurements[f].append(new_measure_index) + old_measure_index -= 1 + new_measure_index += 1 + elif inst.name == "QUBIT_COORDS": + header.append(inst) + else: + raise NotImplementedError(f"{inst=}") + + return Chunk( + circuit=header + rev_circuit, + q2i=chunk.q2i, + flows=[ + Flow( + center=flow.center, + start=flow.end, + end=flow.start, + measurement_indices=new_flow_measurements[k], + additional_coords=flow.additional_coords, + obs_index=flow.obs_index, + allow_vacuous=True, + ) + for k, flow in enumerate(chunk.flows) + ], + discarded_inputs=chunk.discarded_outputs, + discarded_outputs=chunk.discarded_inputs, + ) + + def rev_apply(self, inst: stim.CircuitInstruction): + if inst.name == "H" or inst.name == "SQRT_Y" or inst.name == "SQRT_Y_DAG": + for t in inst.targets_copy()[::-1]: + assert t.is_qubit_target + q = t.value + tmp = self.xs[q].copy() + self.xs[q, :] = self.zs[q] + self.zs[q, :] = tmp + elif ( + inst.name == "I" or inst.name == "Z" or inst.name == "X" or inst.name == "Y" + ): + pass + elif inst.name == "S" or inst.name == "S_DAG" or inst.name == "H_XY": + for t in inst.targets_copy()[::-1]: + assert t.is_qubit_target + q = t.value + self.zs[q, :] ^= self.xs[q] + elif inst.name == "SQRT_X" or inst.name == "SQRT_X_DAG" or inst.name == "H_YZ": + for t in inst.targets_copy()[::-1]: + assert t.is_qubit_target + q = t.value + self.xs[q, :] ^= self.zs[q] + elif inst.name == "C_XYZ": + for t in inst.targets_copy()[::-1]: + assert t.is_qubit_target + q = t.value + self.zs[q, :] ^= self.xs[q] + self.xs[q, :] ^= self.zs[q] + elif inst.name == "C_ZYX": + for t in inst.targets_copy()[::-1]: + assert t.is_qubit_target + q = t.value + self.xs[q, :] ^= self.zs[q] + self.zs[q, :] ^= self.xs[q] + elif inst.name == "RY": + for t in inst.targets_copy()[::-1]: + assert t.is_qubit_target + q = t.value + self.fail_if(self.xs[q] ^ self.zs[q], "Anticommuted with RY") + for k in range(len(self.flows)): + if self.xs[q, k] and self.zs[q, k]: + self.reset_to_flow_indices[self.reset_index].append(k) + self.reset_index += 1 + self.xs[q, :] = 0 + self.zs[q, :] = 0 + elif inst.name == "RX": + for t in inst.targets_copy()[::-1]: + assert t.is_qubit_target + q = t.value + self.fail_if(self.zs[q], "Anticommuted with RX") + for k in range(len(self.flows)): + if self.xs[q, k]: + self.reset_to_flow_indices[self.reset_index].append(k) + self.reset_index += 1 + self.xs[q, :] = 0 + elif inst.name == "R": + for t in inst.targets_copy()[::-1]: + assert t.is_qubit_target + q = t.value + self.fail_if(self.xs[q], "Anticommuted with R") + for k in range(len(self.flows)): + if self.zs[q, k]: + self.reset_to_flow_indices[self.reset_index].append(k) + self.reset_index += 1 + self.zs[q, :] = 0 + elif inst.name == "M": + for t in inst.targets_copy()[::-1]: + assert t.is_qubit_target + q = t.value + m = self.next_measurement + self.next_measurement -= 1 + self.fail_if(self.xs[q], "Anticommuted with M") + if not np.any(self.xs[q, :]) and not np.any(self.zs[q, :]): + self.measurement_to_can_be_destructive.add(m) + for s in self.i2m[m]: + self.zs[q, s] ^= True + elif inst.name == "MR": + for gate in "RM": + self.rev_apply( + stim.CircuitInstruction( + name=gate, + targets=inst.targets_copy(), + gate_args=inst.gate_args_copy(), + ) + ) + elif inst.name == "CXSWAP": + for gate in ["SWAP", "CX"]: + self.rev_apply( + stim.CircuitInstruction( + name=gate, + targets=inst.targets_copy(), + gate_args=inst.gate_args_copy(), + ) + ) + elif inst.name == "SWAPCX": + for gate in ["CX", "SWAP"]: + self.rev_apply( + stim.CircuitInstruction( + name=gate, + targets=inst.targets_copy(), + gate_args=inst.gate_args_copy(), + ) + ) + elif inst.name == "MRX": + for gate in ["RX", "MX"]: + self.rev_apply( + stim.CircuitInstruction( + name=gate, + targets=inst.targets_copy(), + gate_args=inst.gate_args_copy(), + ) + ) + elif inst.name == "MRY": + for gate in ["RY", "MY"]: + self.rev_apply( + stim.CircuitInstruction( + name=gate, + targets=inst.targets_copy(), + gate_args=inst.gate_args_copy(), + ) + ) + elif inst.name == "MY": + for t in inst.targets_copy()[::-1]: + assert t.is_qubit_target + q = t.value + m = self.next_measurement + self.next_measurement -= 1 + self.fail_if(self.xs[q] ^ self.zs[q], "Anticommuted with M") + if not np.any(self.xs[q, :]) and not np.any(self.zs[q, :]): + self.measurement_to_can_be_destructive.add(m) + for s in self.i2m[m]: + self.xs[q, s] ^= True + self.zs[q, s] ^= True + elif inst.name == "MX": + for t in inst.targets_copy()[::-1]: + assert t.is_qubit_target + q = t.value + m = self.next_measurement + self.next_measurement -= 1 + self.fail_if(self.zs[q], "Anticommuted with MX") + if not np.any(self.xs[q, :]) and not np.any(self.zs[q, :]): + self.measurement_to_can_be_destructive.add(m) + for s in self.i2m[m]: + self.xs[q, s] ^= True + elif inst.name == "XCZ": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + assert t1.is_qubit_target + assert t2.is_qubit_target + q1 = t1.value + q2 = t2.value + self.xs[q1] ^= self.xs[q2] + self.zs[q2] ^= self.zs[q1] + elif inst.name == "CX": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + assert t2.is_qubit_target + q2 = t2.value + if t1.is_measurement_record_target: + m = self.next_measurement + t1.value + 1 + for s in np.flatnonzero(self.zs[q2, :]): + self.i2m[m].append(s) + else: + assert t1.is_qubit_target + q1 = t1.value + self.xs[q2] ^= self.xs[q1] + self.zs[q1] ^= self.zs[q2] + elif inst.name == "CZ": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + assert t2.is_qubit_target + q2 = t2.value + if t1.is_measurement_record_target: + m = self.next_measurement + t1.value + 1 + for s in np.flatnonzero(self.xs[q2, :]): + self.i2m[m].append(s) + else: + assert t1.is_qubit_target + q1 = t1.value + self.zs[q2] ^= self.xs[q1] + self.zs[q1] ^= self.xs[q2] + elif inst.name == "CY" or inst.name == "YCZ": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + if inst.name == "YCZ": + t1, t2 = t2, t1 + assert t1.is_qubit_target + assert t2.is_qubit_target + q1 = t1.value + q2 = t2.value + yt = self.xs[q2] ^ self.zs[q2] + self.zs[q1] ^= yt + self.zs[q2] ^= self.xs[q1] + self.xs[q2] ^= self.xs[q1] + elif inst.name == "ISWAP" or inst.name == "ISWAP_DAG": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + assert t1.is_qubit_target + assert t2.is_qubit_target + q1 = t1.value + q2 = t2.value + # swap + for bs in [self.xs, self.zs]: + bs[q1] ^= bs[q2] + bs[q2] ^= bs[q1] + bs[q1] ^= bs[q2] + # cz + self.zs[q2] ^= self.xs[q1] + self.zs[q1] ^= self.xs[q2] + # s s + self.zs[q1, :] ^= self.xs[q1] + self.zs[q2, :] ^= self.xs[q2] + elif inst.name == "SQRT_ZZ" or inst.name == "SQRT_ZZ_DAG": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + assert t1.is_qubit_target + assert t2.is_qubit_target + q1 = t1.value + q2 = t2.value + # cz + self.zs[q2] ^= self.xs[q1] + self.zs[q1] ^= self.xs[q2] + # s s + self.zs[q1, :] ^= self.xs[q1] + self.zs[q2, :] ^= self.xs[q2] + elif inst.name == "XCX": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + assert t1.is_qubit_target + assert t2.is_qubit_target + q1 = t1.value + q2 = t2.value + self.xs[q2] ^= self.zs[q1] + self.xs[q1] ^= self.zs[q2] + elif inst.name == "YCY": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + assert t1.is_qubit_target + assert t2.is_qubit_target + q1 = t1.value + q2 = t2.value + # s s + self.zs[q1, :] ^= self.xs[q1] + self.zs[q2, :] ^= self.xs[q2] + # xcx + self.xs[q2] ^= self.zs[q1] + self.xs[q1] ^= self.zs[q2] + # s s + self.zs[q1, :] ^= self.xs[q1] + self.zs[q2, :] ^= self.xs[q2] + elif inst.name == "SQRT_YY" or inst.name == "SQRT_YY_DAG": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + assert t1.is_qubit_target + assert t2.is_qubit_target + q1 = t1.value + q2 = t2.value + # s s + self.zs[q1, :] ^= self.xs[q1] + self.zs[q2, :] ^= self.xs[q2] + # xcx + self.xs[q2] ^= self.zs[q1] + self.xs[q1] ^= self.zs[q2] + # sqrt_x sqrt_x + self.xs[q1, :] ^= self.zs[q1] + self.xs[q2, :] ^= self.zs[q2] + # s s + self.zs[q1, :] ^= self.xs[q1] + self.zs[q2, :] ^= self.xs[q2] + elif inst.name == "SQRT_XX" or inst.name == "SQRT_XX_DAG": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + assert t1.is_qubit_target + assert t2.is_qubit_target + q1 = t1.value + q2 = t2.value + # xcx + self.xs[q2] ^= self.zs[q1] + self.xs[q1] ^= self.zs[q2] + # sqrt_x sqrt_x + self.xs[q1, :] ^= self.zs[q1] + self.xs[q2, :] ^= self.zs[q2] + elif inst.name == "SWAP": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + assert t1.is_qubit_target + assert t2.is_qubit_target + q1 = t1.value + q2 = t2.value + for bs in [self.xs, self.zs]: + bs[q1] ^= bs[q2] + bs[q2] ^= bs[q1] + bs[q1] ^= bs[q2] + elif inst.name == "XCY" or inst.name == "YCX": + ts = inst.targets_copy() + for k in range(0, len(ts), 2)[::-1]: + t1 = ts[k] + t2 = ts[k + 1] + if inst.name == "YCX": + t1, t2 = t2, t1 + assert t1.is_qubit_target + assert t2.is_qubit_target + q1 = t1.value + q2 = t2.value + yt = self.xs[q2] ^ self.zs[q2] + self.xs[q1] ^= yt + self.zs[q2] ^= self.zs[q1] + self.xs[q2] ^= self.zs[q1] + elif inst.name == "MPP": + targets = inst.targets_copy()[::-1] + start = 0 + while start < len(targets): + end = start + 1 + while end < len(targets) and targets[end].is_combiner: + end += 2 + + x_mask = np.zeros(shape=self.xs.shape[0], dtype=np.bool_) + z_mask = np.zeros(shape=self.xs.shape[0], dtype=np.bool_) + for t in targets[start:end:2]: + if t.is_x_target: + x_mask[t.value] ^= True + elif t.is_y_target: + x_mask[t.value] ^= True + z_mask[t.value] ^= True + elif t.is_z_target: + z_mask[t.value] ^= True + else: + raise NotImplementedError(f"{inst=}") + + for k in range(self.xs.shape[1]): + x_combos = np.sum(np.bitwise_and(self.xs[:, k], z_mask), axis=0) + z_combos = np.sum(np.bitwise_and(self.zs[:, k], x_mask), axis=0) + if np.any((x_combos + z_combos) & 1): + raise ValueError("Anticommuted with MPP") + m = self.next_measurement + self.next_measurement -= 1 + for s in self.i2m[m]: + self.zs[:, s] ^= z_mask + self.xs[:, s] ^= x_mask + + start = end + + elif inst.name == "TICK": + pass + elif inst.name == "QUBIT_COORDS": + pass + else: + raise NotImplementedError(f"{inst=}") diff --git a/src/gen/_flows/_flow_verifier_test.py b/src/gen/_flows/_flow_verifier_test.py new file mode 100644 index 0000000..19bc2b1 --- /dev/null +++ b/src/gen/_flows/_flow_verifier_test.py @@ -0,0 +1,833 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +import stim + +import gen + + +def test_verify_h(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + H 0 + """ + ), + q2i={1j: 0}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({1j: "X"}), + end=gen.PauliString({1j: "Z"}), + ) + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + H 0 + """ + ), + q2i={1j: 0}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({1j: "X"}), + end=gen.PauliString({1j: "Y"}), + ) + ], + ) + with pytest.raises(ValueError): + chunk.verify() + + +def test_verify_r(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + R 0 + """ + ), + q2i={1j: 0}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({1j: "Z"}), + end=gen.PauliString({}), + ) + ], + ) + with pytest.raises(ValueError): + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + R 0 + """ + ), + q2i={1j: 0}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({}), + end=gen.PauliString({1j: "Z"}), + ) + ], + ) + chunk.verify() + + +def test_verify_measurement(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + R 1 + CX 0 1 2 1 + M 1 3 + H 0 + """ + ), + q2i={0: 0, 1j: 1, 2j: 2, 3j: 3}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "Z", 2j: "Z"}), + measurement_indices=[0], + ), + gen.Flow( + center=0, + end=gen.PauliString({0: "X", 2j: "Z"}), + measurement_indices=[0], + ), + ], + ) + chunk.verify() + + +def test_verify_mpp(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + MPP X0*Y1*Z2 + """ + ), + q2i={0: 0, 1j: 1, 2j: 2, 3j: 3}, + flows=[ + gen.Flow( + center=0, + end=gen.PauliString({0: "X", 1j: "Y", 2j: "Z"}), + measurement_indices=[0], + ), + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + MPP X0*Y1*Z2 + MPP X0*X1*Z2 + """ + ), + q2i={0: 0, 1j: 1, 2j: 2, 3j: 3}, + flows=[ + gen.Flow( + center=0, + end=gen.PauliString({0: "X", 1j: "Y", 2j: "Z"}), + measurement_indices=[0], + ), + ], + ) + with pytest.raises(ValueError, match="Anticommuted with MPP"): + chunk.verify() + + +def test_verify_c_xyz(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + C_XYZ 0 1 2 + """ + ), + q2i={0: 0, 1: 1, 2: 2}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1: "Y", 2: "Z"}), + end=gen.PauliString({0: "Y", 1: "Z", 2: "X"}), + ), + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + C_ZYX 0 1 2 + """ + ), + q2i={0: 0, 1: 1, 2: 2}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1: "Y", 2: "Z"}), + end=gen.PauliString({0: "Z", 1: "X", 2: "Y"}), + ), + ], + ) + chunk.verify() + + +def test_verify_s(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + S 0 1 2 + """ + ), + q2i={0: 0, 1: 1, 2: 2}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1: "Y", 2: "Z"}), + end=gen.PauliString({0: "Y", 1: "X", 2: "Z"}), + ), + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + S_DAG 0 1 2 + """ + ), + q2i={0: 0, 1: 1, 2: 2}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1: "Y", 2: "Z"}), + end=gen.PauliString({0: "Y", 1: "X", 2: "Z"}), + ), + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + H_XY 0 1 2 + """ + ), + q2i={0: 0, 1: 1, 2: 2}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1: "Y", 2: "Z"}), + end=gen.PauliString({0: "Y", 1: "X", 2: "Z"}), + ), + ], + ) + chunk.verify() + + +def test_verify_sqrt_x(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + SQRT_X 0 1 2 + """ + ), + q2i={0: 0, 1: 1, 2: 2}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1: "Y", 2: "Z"}), + end=gen.PauliString({0: "X", 1: "Z", 2: "Y"}), + ), + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + SQRT_X_DAG 0 1 2 + """ + ), + q2i={0: 0, 1: 1, 2: 2}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1: "Y", 2: "Z"}), + end=gen.PauliString({0: "X", 1: "Z", 2: "Y"}), + ), + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + H_YZ 0 1 2 + """ + ), + q2i={0: 0, 1: 1, 2: 2}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1: "Y", 2: "Z"}), + end=gen.PauliString({0: "X", 1: "Z", 2: "Y"}), + ), + ], + ) + chunk.verify() + + +def test_verify_cy(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + CY 0 1 2 3 4 5 + """ + ), + q2i={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1: "Y", 2: "Y", 3: "Y", 4: "Z"}), + end=gen.PauliString({0: "X", 2: "Y", 4: "Z"}), + ), + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + CY 0 1 2 3 4 5 + """ + ), + q2i={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 2: "Y", 4: "Z"}), + end=gen.PauliString({0: "X", 1: "Y", 2: "Y", 3: "Y", 4: "Z"}), + ), + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + CY 0 1 2 3 4 5 + """ + ), + q2i={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1: "X", 2: "Y", 3: "X", 4: "Z", 5: "X"}), + end=gen.PauliString({0: "Y", 1: "Z", 2: "X", 3: "Z", 5: "X"}), + ), + ], + ) + chunk.verify() + + +@pytest.mark.parametrize( + "gate", + [ + "I", + "X", + "Y", + "Z", + "C_XYZ", + "C_ZYX", + "H", + "H_XY", + "H_XZ", + "H_YZ", + "S", + "SQRT_X", + "SQRT_X_DAG", + "SQRT_Y", + "SQRT_Y_DAG", + "SQRT_Z", + "SQRT_Z_DAG", + "S_DAG", + "CXSWAP", + "SWAPCX", + "CNOT", + "CX", + "CY", + "CZ", + "ISWAP", + "ISWAP_DAG", + "SQRT_XX", + "SQRT_XX_DAG", + "SQRT_YY", + "SQRT_YY_DAG", + "SQRT_ZZ", + "SQRT_ZZ_DAG", + "SWAP", + "XCX", + "XCY", + "XCZ", + "YCX", + "YCY", + "YCZ", + "ZCX", + "ZCY", + "ZCZ", + ], +) +def test_verify_gate_flows_vs_stim_tableau(gate: str): + circuit = stim.Circuit(f"{gate} 0 1") + tableau = stim.Tableau.from_circuit(circuit) + flows = [] + if len(tableau) == 2: + for p0 in "IXYZ": + for p1 in "IXYZ": + i = stim.PauliString(p0 + p1) + flows.append((i, tableau(i))) + elif len(tableau) == 1: + for p0 in "IXYZ": + i = stim.PauliString(p0) + flows.append((i, tableau(i))) + else: + raise NotImplementedError() + for flow in flows: + chunk = gen.Chunk( + circuit=circuit, + q2i={0: 0, 1: 1}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString.from_stim_pauli_string(flow[0]), + end=gen.PauliString.from_stim_pauli_string(flow[1]), + allow_vacuous=True, + ), + ], + ) + chunk.verify() + inverse = chunk.inverted() + inverse.verify() + + +def test_verify_swap(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + SWAP 0 1 2 3 4 5 + """ + ), + q2i={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 2: "Y", 3: "Y", 4: "Z", 5: "Y"}), + end=gen.PauliString({1: "X", 3: "Y", 2: "Y", 5: "Z", 4: "Y"}), + ), + ], + ) + chunk.verify() + + +def test_verify_xcy(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + XCY 0 1 2 3 4 5 + """ + ), + q2i={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 2: "Y", 3: "Y", 4: "Z", 5: "Y"}), + end=gen.PauliString({0: "X", 2: "Y", 4: "Z"}), + ), + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + YCX 1 0 3 2 5 4 + """ + ), + q2i={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 2: "Y", 3: "Y", 4: "Z", 5: "Y"}), + end=gen.PauliString({0: "X", 2: "Y", 4: "Z"}), + ), + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + XCY 0 1 2 3 4 5 + """ + ), + q2i={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 2: "Y", 4: "Z"}), + end=gen.PauliString({0: "X", 2: "Y", 3: "Y", 4: "Z", 5: "Y"}), + ), + ], + ) + chunk.verify() + + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + XCY 0 1 2 3 4 5 + """ + ), + q2i={0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X", 1: "X", 2: "Y", 3: "X", 4: "Z", 5: "X"}), + end=gen.PauliString({1: "X", 2: "Z", 3: "Z", 4: "Y", 5: "Z"}), + ), + ], + ) + chunk.verify() + + +def test_reset_analysis(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + R 0 1 2 3 4 + CX 2 0 + M 0 + """ + ), + q2i={0: 0, 1: 1, 2: 2, 3: 3, 4: 4}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({}), + measurement_indices=[0], + end=gen.PauliString({1: "Z"}), + ), + ], + ) + f = gen.FlowStabilizerVerifier.verify(chunk) + assert f.reset_to_flow_indices == {2: [0], 3: [0], 4: [0]} + + inverted = gen.FlowStabilizerVerifier.invert(chunk) + inverted.verify() + assert len(inverted.flows) == len(chunk.flows) + assert inverted.circuit == stim.Circuit( + """ + R 0 + CX 2 0 + M 4 3 2 1 0 + """ + ) + + +def test_verify_mr(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + MR 0 + """ + ), + q2i={0: 0, 1: 1}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "Z"}), + measurement_indices=[0], + ), + gen.Flow( + center=0, + end=gen.PauliString({0: "Z"}), + ), + ], + ) + chunk.verify() + + +def test_verify_feedback_cx(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + MR 0 + CX rec[-1] 1 + """ + ), + q2i={0: 0, 1: 1}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "Z", 1: "Y"}), + end=gen.PauliString({1: "Y"}), + ), + gen.Flow( + center=0, + start=gen.PauliString({0: "Z"}), + end=gen.PauliString({}), + measurement_indices=[0], + ), + gen.Flow( + center=0, + start=gen.PauliString({}), + end=gen.PauliString({0: "Z"}), + measurement_indices=[], + ), + gen.Flow( + center=0, + start=gen.PauliString({1: "Z"}), + end=gen.PauliString({1: "Z"}), + measurement_indices=[0], + ), + gen.Flow( + center=0, + start=gen.PauliString({1: "X"}), + end=gen.PauliString({1: "X"}), + measurement_indices=[], + ), + ], + ) + chunk2 = gen.Chunk( + circuit=stim.Circuit( + """ + MR 0 + CX rec[-1] 1 + """ + ), + q2i={0: 0, 1: 1}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({1: "Y"}), + end=gen.PauliString({1: "Y"}), + measurement_indices=[0], + ), + ], + ) + chunk.verify() + chunk2.verify() + + +def test_verify_feedback_cz(): + chunk = gen.Chunk( + circuit=stim.Circuit( + """ + MR 0 + CZ rec[-1] 1 + """ + ), + q2i={0: 0, 1: 1}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "Z", 1: "Y"}), + end=gen.PauliString({1: "Y"}), + ), + gen.Flow( + center=0, + start=gen.PauliString({0: "Z"}), + end=gen.PauliString({}), + measurement_indices=[0], + ), + gen.Flow( + center=0, + start=gen.PauliString({}), + end=gen.PauliString({0: "Z"}), + measurement_indices=[], + ), + gen.Flow( + center=0, + start=gen.PauliString({1: "X"}), + end=gen.PauliString({1: "X"}), + measurement_indices=[0], + ), + gen.Flow( + center=0, + start=gen.PauliString({1: "Z"}), + end=gen.PauliString({1: "Z"}), + measurement_indices=[], + ), + ], + ) + chunk2 = gen.Chunk( + circuit=stim.Circuit( + """ + MR 0 + CX rec[-1] 1 + """ + ), + q2i={0: 0, 1: 1}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({1: "Y"}), + end=gen.PauliString({1: "Y"}), + measurement_indices=[0], + ), + ], + ) + chunk.verify() + chunk2.verify() + + +def test_verify_feedback_passthrough(): + gen.Chunk( + circuit=stim.Circuit( + """ + M 0 + R 0 + CX rec[-1] 0 + """ + ), + q2i={0: 0}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "Z"}), + end=gen.PauliString({0: "Z"}), + ), + ], + ).verify() + + gen.Chunk( + circuit=stim.Circuit( + """ + M 0 + R 0 + CX rec[-1] 0 + """ + ), + q2i={0: 0}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "Z"}), + measurement_indices=[0], + ), + ], + ).verify() + + gen.Chunk( + circuit=stim.Circuit( + """ + M 0 + R 0 + CX rec[-1] 0 + """ + ), + q2i={0: 0}, + flows=[ + gen.Flow( + center=0, + end=gen.PauliString({0: "Z"}), + measurement_indices=[0], + ), + ], + ).verify() + + gen.Chunk( + circuit=stim.Circuit( + """ + MX 0 + RX 0 + CZ rec[-1] 0 + """ + ), + q2i={0: 0}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X"}), + end=gen.PauliString({0: "X"}), + ), + ], + ).verify() + gen.Chunk( + circuit=stim.Circuit( + """ + MX 0 + RX 0 + CZ rec[-1] 0 + """ + ), + q2i={0: 0}, + flows=[ + gen.Flow( + center=0, + start=gen.PauliString({0: "X"}), + measurement_indices=[0], + ), + ], + ).verify() + gen.Chunk( + circuit=stim.Circuit( + """ + MX 0 + RX 0 + CZ rec[-1] 0 + """ + ), + q2i={0: 0}, + flows=[ + gen.Flow( + center=0, + end=gen.PauliString({0: "X"}), + measurement_indices=[0], + ), + ], + ).verify() + + +def test_reproduce_feedback_verification_failure(): + gen.Chunk( + circuit=stim.Circuit( + """ + MRX 1 + CZ rec[-1] 1 + """ + ), + q2i={ + 1j: 0, + 2j: 1, + 3j: 2, + }, # Note: extra coordinates were key to triggering the bug. + flows=[ + gen.Flow( + end=gen.PauliString({2j: "X"}), + measurement_indices=[0], + center=0, + ), + ], + ).verify() diff --git a/src/gen/_layers/__init__.py b/src/gen/_layers/__init__.py new file mode 100644 index 0000000..c04fb48 --- /dev/null +++ b/src/gen/_layers/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Works with circuits in a layered representation that's easy to operate on. +""" +from gen._layers._transpile import ( + transpile_to_z_basis_interaction_circuit, +) diff --git a/src/gen/_layers/_data.py b/src/gen/_layers/_data.py new file mode 100644 index 0000000..c70b1fb --- /dev/null +++ b/src/gen/_layers/_data.py @@ -0,0 +1,59 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Literal + +import numpy as np + +R_XYZ = 0 +R_XZY = 1 +R_YXZ = 2 +R_YZX = 3 +R_ZXY = 4 +R_ZYX = 5 +PERMUTATIONS: list[dict[Literal["X", "Y", "Z"], Literal["X", "Y", "Z"]]] = [ + {"X": "X", "Y": "Y", "Z": "Z"}, + {"X": "X", "Y": "Z", "Z": "Y"}, + {"X": "Y", "Y": "X", "Z": "Z"}, + {"X": "Y", "Y": "Z", "Z": "X"}, + {"X": "Z", "Y": "X", "Z": "Y"}, + {"X": "Z", "Y": "Y", "Z": "X"}, +] +INVERSE_PERMUTATIONS: list[dict[Literal["X", "Y", "Z"], Literal["X", "Y", "Z"]]] = [ + {"X": "X", "Y": "Y", "Z": "Z"}, + {"X": "X", "Y": "Z", "Z": "Y"}, + {"X": "Y", "Y": "X", "Z": "Z"}, + {"X": "Z", "Y": "X", "Z": "Y"}, + {"X": "Y", "Y": "Z", "Z": "X"}, + {"X": "Z", "Y": "Y", "Z": "X"}, +] +ORIENTATIONS = [ + "I", + "SQRT_X", + "S", + "C_XYZ", + "C_ZYX", + "H", +] +ORIENTATION_MULTIPLICATION_TABLE = np.array( + [ + [0, 1, 2, 3, 4, 5], + [1, 0, 4, 5, 2, 3], + [2, 3, 0, 1, 5, 4], + [3, 2, 5, 4, 0, 1], + [4, 5, 1, 0, 3, 2], + [5, 4, 3, 2, 1, 0], + ], + dtype=np.uint8, +) diff --git a/src/gen/_layers/_det_obs_annotation_layer.py b/src/gen/_layers/_det_obs_annotation_layer.py new file mode 100644 index 0000000..40302c7 --- /dev/null +++ b/src/gen/_layers/_det_obs_annotation_layer.py @@ -0,0 +1,39 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses + +import stim + +from gen._layers._layer import Layer + + +@dataclasses.dataclass +class DetObsAnnotationLayer(Layer): + circuit: stim.Circuit = dataclasses.field(default_factory=stim.Circuit) + + def copy(self) -> "DetObsAnnotationLayer": + return DetObsAnnotationLayer(circuit=self.circuit.copy()) + + def touched(self) -> set[int]: + return set() + + def requires_tick_before(self) -> bool: + return False + + def implies_eventual_tick_after(self) -> bool: + return False + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + out += self.circuit diff --git a/src/gen/_layers/_empty_layer.py b/src/gen/_layers/_empty_layer.py new file mode 100644 index 0000000..462fd89 --- /dev/null +++ b/src/gen/_layers/_empty_layer.py @@ -0,0 +1,37 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses + +import stim + +from gen._layers._layer import Layer + + +@dataclasses.dataclass +class EmptyLayer(Layer): + def copy(self) -> "EmptyLayer": + return EmptyLayer() + + def touched(self) -> set[int]: + return set() + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + pass + + def locally_optimized(self, next_layer: None | Layer) -> list[Layer | None]: + return [next_layer] + + def is_vacuous(self) -> bool: + return True diff --git a/src/gen/_layers/_feedback_layer.py b/src/gen/_layers/_feedback_layer.py new file mode 100644 index 0000000..987de46 --- /dev/null +++ b/src/gen/_layers/_feedback_layer.py @@ -0,0 +1,67 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses +from typing import TYPE_CHECKING, Literal + +import stim + +from gen._layers._data import INVERSE_PERMUTATIONS +from gen._layers._layer import Layer + +if TYPE_CHECKING: + from gen._layers._rotation_layer import RotationLayer + + +@dataclasses.dataclass +class FeedbackLayer(Layer): + controls: list[stim.GateTarget] = dataclasses.field(default_factory=list) + targets: list[int] = dataclasses.field(default_factory=list) + bases: list[Literal["X", "Y", "Z"]] = dataclasses.field(default_factory=list) + + def copy(self) -> "FeedbackLayer": + return FeedbackLayer( + targets=list(self.targets), + controls=list(self.controls), + bases=list(self.bases), + ) + + def touched(self) -> set[int]: + return set(self.targets) + + def requires_tick_before(self) -> bool: + return False + + def implies_eventual_tick_after(self) -> bool: + return False + + def before(self, layer: "RotationLayer") -> "FeedbackLayer": + return FeedbackLayer( + controls=list(self.controls), + targets=list(self.targets), + bases=[ + _basis_before_rotation(b, layer.rotations.get(t, 0)) + for b, t in zip(self.bases, self.targets) + ], + ) + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + for c, t, b in zip(self.controls, self.targets, self.bases): + out.append("C" + b, [c, t]) + + +def _basis_before_rotation( + basis: Literal["X", "Y", "Z"], rotation: int +) -> Literal["X", "Y", "Z"]: + return INVERSE_PERMUTATIONS[rotation][basis] diff --git a/src/gen/_layers/_feedback_layer_test.py b/src/gen/_layers/_feedback_layer_test.py new file mode 100644 index 0000000..d99e0f0 --- /dev/null +++ b/src/gen/_layers/_feedback_layer_test.py @@ -0,0 +1,24 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +from gen._layers._data import R_ZXY +from gen._layers._feedback_layer import _basis_before_rotation + + +def test_basis_before_rotation(): + assert _basis_before_rotation("X", R_ZXY) == "Y" + assert _basis_before_rotation("Y", R_ZXY) == "Z" + assert _basis_before_rotation("Z", R_ZXY) == "X" diff --git a/src/gen/_layers/_interact_layer.py b/src/gen/_layers/_interact_layer.py new file mode 100644 index 0000000..4e4c89d --- /dev/null +++ b/src/gen/_layers/_interact_layer.py @@ -0,0 +1,93 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import collections +import dataclasses + +import stim + +from gen._layers._data import R_XYZ, R_ZYX, R_XZY +from gen._layers._layer import Layer + + +@dataclasses.dataclass +class InteractLayer(Layer): + targets1: list[int] = dataclasses.field(default_factory=list) + targets2: list[int] = dataclasses.field(default_factory=list) + bases1: list[str] = dataclasses.field(default_factory=list) + bases2: list[str] = dataclasses.field(default_factory=list) + + def touched(self) -> set[int]: + return set(self.targets1 + self.targets2) + + def copy(self) -> "InteractLayer": + return InteractLayer( + targets1=list(self.targets1), + targets2=list(self.targets2), + bases1=list(self.bases1), + bases2=list(self.bases2), + ) + + def _rot_layer(self): + from gen._layers._rotation_layer import RotationLayer + + result = RotationLayer() + for targets, bases in [ + (self.targets1, self.bases1), + (self.targets2, self.bases2), + ]: + for q, b in zip(targets, bases): + result.rotations[q] = ( + R_XYZ if b == "Z" else R_ZYX if b == "X" else R_XZY + ) + return result + + def to_z_basis(self) -> list["Layer"]: + rot = self._rot_layer() + return [ + rot, + InteractLayer( + targets1=list(self.targets1), + targets2=list(self.targets2), + bases1=["Z"] * len(self.targets1), + bases2=["Z"] * len(self.targets2), + ), + rot.copy(), + ] + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + groups = collections.defaultdict(list) + for k in range(len(self.targets1)): + gate = self.bases1[k] + "C" + self.bases2[k] + t1 = self.targets1[k] + t2 = self.targets2[k] + if gate in ["XCZ", "YCZ", "YCX"]: + t1, t2 = t2, t1 + gate = gate[::-1] + if gate in ["XCX", "YCY", "ZCZ"]: + t1, t2 = sorted([t1, t2]) + groups[gate].append((t1, t2)) + for gate in sorted(groups.keys()): + for pair in sorted(groups[gate]): + out.append(gate, pair) + + def locally_optimized(self, next_layer: Layer | None) -> list[Layer | None]: + from gen._layers._swap_layer import SwapLayer + from gen._layers._interact_swap_layer import InteractSwapLayer + + if isinstance(next_layer, SwapLayer): + return [ + InteractSwapLayer(i_layer=self.copy(), swap_layer=next_layer.copy()) + ] + return [self, next_layer] diff --git a/src/gen/_layers/_interact_swap_layer.py b/src/gen/_layers/_interact_swap_layer.py new file mode 100644 index 0000000..63d2fb3 --- /dev/null +++ b/src/gen/_layers/_interact_swap_layer.py @@ -0,0 +1,68 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses + +import stim + +from gen._layers._data import R_YXZ +from gen._layers._interact_layer import InteractLayer +from gen._layers._iswap_layer import ISwapLayer +from gen._layers._layer import Layer +from gen._layers._rotation_layer import RotationLayer +from gen._layers._swap_layer import SwapLayer + + +@dataclasses.dataclass +class InteractSwapLayer(Layer): + i_layer: InteractLayer = dataclasses.field(default_factory=InteractLayer) + swap_layer: SwapLayer = dataclasses.field(default_factory=SwapLayer) + + def copy(self) -> "InteractSwapLayer": + return InteractSwapLayer( + i_layer=self.i_layer.copy(), swap_layer=self.swap_layer.copy() + ) + + def touched(self) -> set[int]: + return self.i_layer.touched() | self.swap_layer.touched() + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + self.i_layer.append_into_stim_circuit(out) + out.append("TICK") + self.swap_layer.append_into_stim_circuit(out) + + def to_z_basis(self) -> list["Layer"]: + pairs_1 = { + frozenset([a, b]) + for a, b in zip(self.i_layer.targets1, self.i_layer.targets2) + } + pairs_2 = { + frozenset([a, b]) + for a, b in zip(self.swap_layer.targets1, self.swap_layer.targets2) + } + assert pairs_1 == pairs_2 + pre: RotationLayer + post: RotationLayer + pre, _, post = self.i_layer.to_z_basis() + for x, y in zip(self.swap_layer.targets1, self.swap_layer.targets2): + post.rotations[x], post.rotations[y] = post.rotations[y], post.rotations[x] + post.prepend_rotation(R_YXZ, x) + post.prepend_rotation(R_YXZ, y) + mid = ISwapLayer( + targets1=self.swap_layer.targets1, targets2=self.swap_layer.targets2 + ) + return [pre, mid, post] + + def locally_optimized(self, next_layer: Layer | None) -> list[Layer | None]: + return [self, next_layer] diff --git a/src/gen/_layers/_iswap_layer.py b/src/gen/_layers/_iswap_layer.py new file mode 100644 index 0000000..e98f039 --- /dev/null +++ b/src/gen/_layers/_iswap_layer.py @@ -0,0 +1,44 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses + +import stim + +from gen._layers._layer import Layer + + +@dataclasses.dataclass +class ISwapLayer(Layer): + targets1: list[int] = dataclasses.field(default_factory=list) + targets2: list[int] = dataclasses.field(default_factory=list) + + def copy(self) -> "ISwapLayer": + return ISwapLayer(targets1=list(self.targets1), targets2=list(self.targets2)) + + def touched(self) -> set[int]: + return set(self.targets1 + self.targets2) + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + pairs = [] + for k in range(len(self.targets1)): + t1 = self.targets1[k] + t2 = self.targets2[k] + t1, t2 = sorted([t1, t2]) + pairs.append((t1, t2)) + for pair in sorted(pairs): + out.append("ISWAP", pair) + + def locally_optimized(self, next_layer: Layer | None) -> list[Layer | None]: + return [self, next_layer] diff --git a/src/gen/_layers/_layer.py b/src/gen/_layers/_layer.py new file mode 100644 index 0000000..7898fd8 --- /dev/null +++ b/src/gen/_layers/_layer.py @@ -0,0 +1,45 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Optional + +import stim + + +class Layer: + def copy(self) -> "Layer": + raise NotImplementedError() + + def touched(self) -> set[int]: + raise NotImplementedError() + + def to_z_basis(self) -> list["Layer"]: + return [self] + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + raise NotImplementedError() + + def locally_optimized( + self, next_layer: Optional["Layer"] + ) -> list[Optional["Layer"]]: + return [self, next_layer] + + def is_vacuous(self) -> bool: + return False + + def requires_tick_before(self) -> bool: + return True + + def implies_eventual_tick_after(self) -> bool: + return True diff --git a/src/gen/_layers/_layer_circuit.py b/src/gen/_layers/_layer_circuit.py new file mode 100644 index 0000000..1b98fff --- /dev/null +++ b/src/gen/_layers/_layer_circuit.py @@ -0,0 +1,594 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses +from typing import TypeVar, Type, cast, Literal + +import stim + +from gen._layers._data import R_ZYX, R_YXZ, R_XZY, R_YZX, R_ZXY, R_XYZ +from gen._layers._det_obs_annotation_layer import DetObsAnnotationLayer +from gen._layers._empty_layer import EmptyLayer +from gen._layers._feedback_layer import FeedbackLayer +from gen._layers._interact_layer import InteractLayer +from gen._layers._interact_swap_layer import InteractSwapLayer +from gen._layers._iswap_layer import ISwapLayer +from gen._layers._layer import Layer +from gen._layers._loop_layer import LoopLayer +from gen._layers._measure_layer import MeasureLayer +from gen._layers._mpp_layer import MppLayer +from gen._layers._noise_layer import NoiseLayer +from gen._layers._qubit_coord_annotation_layer import QubitCoordAnnotationLayer +from gen._layers._reset_layer import ResetLayer +from gen._layers._rotation_layer import RotationLayer +from gen._layers._shift_coord_annotation_layer import ShiftCoordAnnotationLayer +from gen._layers._sqrt_pp_layer import SqrtPPLayer +from gen._layers._swap_layer import SwapLayer + +TLayer = TypeVar("TLayer") + + +@dataclasses.dataclass +class LayerCircuit: + layers: list[Layer] = dataclasses.field(default_factory=list) + + def touched(self) -> set[int]: + result = set() + for layer in self.layers: + result |= layer.touched() + return result + + def copy(self) -> "LayerCircuit": + return LayerCircuit(layers=[e.copy() for e in self.layers]) + + def to_z_basis(self) -> "LayerCircuit": + result = LayerCircuit() + for layer in self.layers: + result.layers.extend(layer.to_z_basis()) + return result + + def _feed(self, kind: Type[TLayer]) -> TLayer: + if not self.layers: + self.layers.append(kind()) + elif isinstance(self.layers[-1], EmptyLayer): + self.layers[-1] = kind() + elif not isinstance(self.layers[-1], kind): + self.layers.append(kind()) + return self.layers[-1] + + def _feed_reset( + self, basis: Literal["X", "Y", "Z"], targets: list[stim.GateTarget] + ): + layer = self._feed(ResetLayer) + for t in targets: + layer.targets[t.value] = basis + + def _feed_m(self, basis: Literal["X", "Y", "Z"], targets: list[stim.GateTarget]): + layer = self._feed(MeasureLayer) + for t in targets: + layer.bases.append(basis) + layer.targets.append(t.value) + + def _feed_mpp(self, targets: list[stim.GateTarget]): + layer = self._feed(MppLayer) + start = 0 + end = 1 + while start < len(targets): + while end < len(targets) and targets[end].is_combiner: + end += 2 + layer.targets.append(targets[start:end:2]) + start = end + end += 1 + + def _feed_qubit_coords( + self, targets: list[stim.GateTarget], gate_args: list[float] + ): + layer = self._feed(QubitCoordAnnotationLayer) + for target in targets: + assert target.is_qubit_target + q = target.value + if q in layer.coords: + raise ValueError(f"Qubit coords specified twice for {q}") + layer.coords[q] = list(gate_args) + + def _feed_shift_coords(self, gate_args: list[float]): + self._feed(ShiftCoordAnnotationLayer).offset_by(gate_args) + + def _feed_rotate(self, rotation: int, targets: list[stim.GateTarget]): + layer = self._feed(RotationLayer) + for t in targets: + layer.append_rotation(rotation, t.value) + + def _feed_swap(self, targets: list[stim.GateTarget]): + layer = self._feed(SwapLayer) + for k in range(0, len(targets), 2): + layer.targets1.append(targets[k].value) + layer.targets2.append(targets[k + 1].value) + + def _feed_cxswap(self, targets: list[stim.GateTarget]): + layer = self._feed(InteractSwapLayer) + for k in range(0, len(targets), 2): + layer.i_layer.targets1.append(targets[k].value) + layer.i_layer.targets2.append(targets[k + 1].value) + layer.i_layer.bases1.append("Z") + layer.i_layer.bases2.append("X") + layer.swap_layer.targets1.append(targets[k].value) + layer.swap_layer.targets2.append(targets[k + 1].value) + + def _feed_swapcx(self, targets: list[stim.GateTarget]): + layer = self._feed(InteractSwapLayer) + for k in range(0, len(targets), 2): + layer.i_layer.targets1.append(targets[k].value) + layer.i_layer.targets2.append(targets[k + 1].value) + layer.i_layer.bases1.append("X") + layer.i_layer.bases2.append("Z") + layer.swap_layer.targets1.append(targets[k].value) + layer.swap_layer.targets2.append(targets[k + 1].value) + + def _feed_iswap(self, targets: list[stim.GateTarget]): + layer = self._feed(ISwapLayer) + for k in range(0, len(targets), 2): + layer.targets1.append(targets[k].value) + layer.targets2.append(targets[k + 1].value) + + def _feed_sqrt_pp( + self, basis: Literal["X", "Y", "Z"], targets: list[stim.GateTarget] + ): + layer = self._feed(SqrtPPLayer) + for k in range(0, len(targets), 2): + layer.targets1.append(targets[k].value) + layer.targets2.append(targets[k + 1].value) + layer.bases.append(basis) + + def _feed_c( + self, + basis1: Literal["X", "Y", "Z"], + basis2: Literal["X", "Y", "Z"], + targets: list[stim.GateTarget], + ): + is_feedback = any( + t.is_sweep_bit_target or t.is_measurement_record_target for t in targets + ) + if is_feedback: + layer = self._feed(FeedbackLayer) + for k in range(0, len(targets), 2): + c = targets[k] + t = targets[k + 1] + if t.is_sweep_bit_target or t.is_measurement_record_target: + c, t = t, c + layer.bases.append(basis1) + else: + layer.bases.append(basis2) + layer.controls.append(c) + layer.targets.append(t.value) + else: + layer = self._feed(InteractLayer) + for k in range(0, len(targets), 2): + layer.bases1.append(basis1) + layer.bases2.append(basis2) + layer.targets1.append(targets[k].value) + layer.targets2.append(targets[k + 1].value) + + @staticmethod + def from_stim_circuit(circuit: stim.Circuit) -> "LayerCircuit": + result = LayerCircuit() + for instruction in circuit: + if isinstance(instruction, stim.CircuitRepeatBlock): + result.layers.append( + LoopLayer( + body=LayerCircuit.from_stim_circuit(instruction.body_copy()), + repetitions=instruction.repeat_count, + ) + ) + + elif instruction.name == "R": + result._feed_reset("Z", instruction.targets_copy()) + elif instruction.name == "RX": + result._feed_reset("X", instruction.targets_copy()) + elif instruction.name == "RY": + result._feed_reset("Y", instruction.targets_copy()) + + elif instruction.name == "M": + result._feed_m("Z", instruction.targets_copy()) + elif instruction.name == "MX": + result._feed_m("X", instruction.targets_copy()) + elif instruction.name == "MY": + result._feed_m("Y", instruction.targets_copy()) + + elif instruction.name == "MR": + result._feed_m("Z", instruction.targets_copy()) + result._feed_reset("Z", instruction.targets_copy()) + elif instruction.name == "MRX": + result._feed_m("X", instruction.targets_copy()) + result._feed_reset("X", instruction.targets_copy()) + elif instruction.name == "MRY": + result._feed_m("Y", instruction.targets_copy()) + result._feed_reset("Y", instruction.targets_copy()) + + elif instruction.name == "XCX": + result._feed_c("X", "X", instruction.targets_copy()) + elif instruction.name == "XCY": + result._feed_c("X", "Y", instruction.targets_copy()) + elif instruction.name == "XCZ": + result._feed_c("X", "Z", instruction.targets_copy()) + elif instruction.name == "YCX": + result._feed_c("Y", "X", instruction.targets_copy()) + elif instruction.name == "YCY": + result._feed_c("Y", "Y", instruction.targets_copy()) + elif instruction.name == "YCZ": + result._feed_c("Y", "Z", instruction.targets_copy()) + elif instruction.name == "CX": + result._feed_c("Z", "X", instruction.targets_copy()) + elif instruction.name == "CY": + result._feed_c("Z", "Y", instruction.targets_copy()) + elif instruction.name == "CZ": + result._feed_c("Z", "Z", instruction.targets_copy()) + + elif instruction.name in ["H", "SQRT_Y", "SQRT_Y_DAG"]: + result._feed_rotate(R_ZYX, instruction.targets_copy()) + elif instruction.name in ["H_XY", "S", "S_DAG"]: + result._feed_rotate(R_YXZ, instruction.targets_copy()) + elif instruction.name in ["H_YZ", "SQRT_X", "SQRT_X_DAG"]: + result._feed_rotate(R_XZY, instruction.targets_copy()) + elif instruction.name == "C_XYZ": + result._feed_rotate(R_YZX, instruction.targets_copy()) + elif instruction.name == "C_ZYX": + result._feed_rotate(R_ZXY, instruction.targets_copy()) + elif instruction.name in ["I", "X", "Y", "Z"]: + result._feed_rotate(R_XYZ, instruction.targets_copy()) + + elif instruction.name == "QUBIT_COORDS": + result._feed_qubit_coords( + instruction.targets_copy(), instruction.gate_args_copy() + ) + elif instruction.name == "SHIFT_COORDS": + result._feed_shift_coords(instruction.gate_args_copy()) + elif instruction.name in ["DETECTOR", "OBSERVABLE_INCLUDE"]: + result._feed(DetObsAnnotationLayer).circuit.append(instruction) + + elif instruction.name in ["ISWAP", "ISWAP_DAG"]: + result._feed_iswap(instruction.targets_copy()) + elif instruction.name == "MPP": + result._feed_mpp(instruction.targets_copy()) + elif instruction.name == "SWAP": + result._feed_swap(instruction.targets_copy()) + elif instruction.name == "CXSWAP": + result._feed_cxswap(instruction.targets_copy()) + elif instruction.name == "SWAPCX": + result._feed_swapcx(instruction.targets_copy()) + + elif instruction.name == "TICK": + result.layers.append(EmptyLayer()) + + elif instruction.name == "SQRT_XX" or instruction.name == "SQRT_XX_DAG": + result._feed_sqrt_pp("X", instruction.targets_copy()) + elif instruction.name == "SQRT_YY" or instruction.name == "SQRT_YY_DAG": + result._feed_sqrt_pp("Y", instruction.targets_copy()) + elif instruction.name == "SQRT_ZZ" or instruction.name == "SQRT_ZZ_DAG": + result._feed_sqrt_pp("Z", instruction.targets_copy()) + elif ( + instruction.name == "DEPOLARIZE1" + or instruction.name == "X_ERROR" + or instruction.name == "Y_ERROR" + or instruction.name == "Z_ERROR" + or instruction.name == "DEPOLARIZE2" + ): + result._feed(NoiseLayer).circuit.append(instruction) + + else: + raise NotImplementedError(f"{instruction=}") + return result + + def __repr__(self) -> str: + result = ["LayerCircuit(layers=["] + for layer in self.layers: + r = repr(layer) + for line in r.split("\n"): + result.append("\n " + line) + result.append(",") + result.append("\n])") + return "".join(result) + + def with_qubit_coords_at_start(self) -> "LayerCircuit": + k = len(self.layers) + merged_layer = QubitCoordAnnotationLayer() + rev_layers = [] + while k > 0: + k -= 1 + layer = self.layers[k] + if isinstance(layer, QubitCoordAnnotationLayer): + intersection = merged_layer.coords.keys() & layer.coords.keys() + if intersection: + raise ValueError( + f"Qubit coords specified twice for qubits {sorted(intersection)}" + ) + merged_layer.coords.update(layer.coords) + elif isinstance(layer, ShiftCoordAnnotationLayer): + merged_layer.offset_by(layer.shift) + rev_layers.append(layer) + elif isinstance(layer, LoopLayer): + if merged_layer.coords: + raise NotImplementedError("Moving qubit coords across a loop.") + rev_layers.append(layer) + else: + rev_layers.append(layer) + rev_layers.append(merged_layer) + return LayerCircuit(layers=rev_layers[::-1]) + + def with_locally_optimized_layers(self) -> "LayerCircuit": + """Iterates over the circuit aggregating layer.optimized(second_layer).""" + new_layers = [] + + def do_layer(layer: Layer | None): + if new_layers: + new_layers[-1:] = new_layers[-1].locally_optimized(layer) + else: + new_layers.append(layer) + while new_layers and ( + new_layers[-1] is None or new_layers[-1].is_vacuous() + ): + new_layers.pop() + + for e in self.layers: + for opt in e.locally_optimized(None): + do_layer(opt) + do_layer(None) + return LayerCircuit(layers=new_layers) + + def _resets_at_layer(self, k: int, *, end_resets: set[int]) -> set[int]: + if k >= len(self.layers): + return end_resets + + layer = self.layers[k] + if isinstance(layer, ResetLayer): + return layer.touched() + if isinstance(layer, LoopLayer): + return layer.body._resets_at_layer(0, end_resets=set()) + return set() + + def with_rotations_before_resets_removed( + self, loop_boundary_resets: set[int] | None = None + ) -> "LayerCircuit": + all_touched = self.touched() + if loop_boundary_resets is None: + loop_boundary_resets = set() + sets = [layer.touched() for layer in self.layers] + sets.append(all_touched) + resets = [ + self._resets_at_layer(k, end_resets=all_touched) + for k in range(len(self.layers)) + ] + if loop_boundary_resets is None: + resets.append(all_touched) + else: + resets.append( + loop_boundary_resets & (set() if len(resets) == 0 else resets[0]) + ) + new_layers = [layer.copy() for layer in self.layers] + + for k, layer in enumerate(new_layers): + if isinstance(layer, LoopLayer): + layer.body = layer.body.with_rotations_before_resets_removed( + loop_boundary_resets=self._resets_at_layer( + k + 1, end_resets=all_touched + ) + ) + elif isinstance(layer, RotationLayer): + drops = [] + for q, r in layer.rotations.items(): + if r: + k2 = k + 1 + while k2 < len(sets): + if q in sets[k2]: + if q in resets[k2]: + drops.append(q) + break + k2 += 1 + for q in drops: + del layer.rotations[q] + + return LayerCircuit([layer for layer in new_layers if not layer.is_vacuous()]) + + def with_clearable_rotation_layers_cleared(self) -> "LayerCircuit": + """Removes rotation layers where every rotation in the layer can be moved to another layer. + + Each individual rotation can move through intermediate non-rotation layers as long as those + layers don't touch the qubit being rotated. + """ + sets = [layer.touched() for layer in self.layers] + + def scan(qubit: int, start_layer: int, delta: int) -> int | None: + while True: + start_layer += delta + if start_layer < 0 or start_layer >= len(sets): + return None + if ( + isinstance(new_layers[start_layer], RotationLayer) + and not new_layers[start_layer].is_vacuous() + ): + return start_layer + if qubit in sets[start_layer]: + return None + + new_layers = [layer.copy() for layer in self.layers] + cur_layer_index = 0 + while cur_layer_index < len(new_layers): + layer = new_layers[cur_layer_index] + if isinstance(layer, RotationLayer): + rewrites = {} + for q, r in layer.rotations.items(): + if not r: + continue + new_layer_index = scan(q, cur_layer_index, -1) + if new_layer_index is None: + new_layer_index = scan(q, cur_layer_index, +1) + if new_layer_index is not None: + rewrites[q] = new_layer_index + else: + break + else: + for q, r in layer.rotations.items(): + if not r: + continue + new_layer_index = rewrites[q] + new_layer: RotationLayer = cast( + RotationLayer, new_layers[new_layer_index] + ) + if new_layer_index > cur_layer_index: + new_layer.prepend_rotation(r, q) + else: + new_layer.append_rotation(r, q) + if new_layer.rotations.get(q): + sets[new_layer_index].add(q) + elif q in sets[new_layer_index]: + sets[new_layer_index].remove(q) + layer.rotations.clear() + sets[cur_layer_index].clear() + elif isinstance(layer, LoopLayer): + layer.body = layer.body.with_clearable_rotation_layers_cleared() + cur_layer_index += 1 + return LayerCircuit([layer for layer in new_layers if not layer.is_vacuous()]) + + def with_rotations_rolled_from_end_of_loop_to_start_of_loop(self) -> "LayerCircuit": + """Rewrites loops so that they only have rotations at the start, not the end. + + This is useful for ensuring loops don't redundantly rotate at the loop boundary, + by merging the rotations at the end with the rotations at the start or by + making it clear rotations at the end were not needed because of the + operations coming next. + + For example, this: + + REPEAT 5 { + S 2 3 4 + R 0 1 + ... + M 0 1 + H 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + DETECTOR rec[-1] + } + + will become this: + + REPEAT 5 { + H 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + S 2 3 4 + R 0 1 + ... + M 0 1 + DETECTOR rec[-1] + } + + which later optimization passes can then reduce further. + """ + + new_layers = [] + for layer in self.layers: + handled = False + if isinstance(layer, LoopLayer): + loop_layers = list(layer.body.layers) + rot_layer_index = len(loop_layers) - 1 + while rot_layer_index > 0: + if isinstance( + loop_layers[rot_layer_index], + (DetObsAnnotationLayer, ShiftCoordAnnotationLayer), + ): + rot_layer_index -= 1 + continue + if isinstance(loop_layers[rot_layer_index], RotationLayer): + break + # Loop didn't end with a rotation layer; give up. + rot_layer_index = 0 + if rot_layer_index > 0: + handled = True + popped = cast(RotationLayer, loop_layers.pop(rot_layer_index)) + loop_layers.insert(0, popped) + + new_layers.append(popped.inverse()) + new_layers.append( + LoopLayer( + body=LayerCircuit(loop_layers), + repetitions=layer.repetitions, + ) + ) + new_layers.append(popped.copy()) + if not handled: + new_layers.append(layer) + return LayerCircuit([layer for layer in new_layers if not layer.is_vacuous()]) + + def with_rotations_merged_earlier(self) -> "LayerCircuit": + sets = [layer.touched() for layer in self.layers] + + def scan(qubit: int, start_layer: int) -> int | None: + while True: + start_layer -= 1 + if start_layer < 0: + return None + l = new_layers[start_layer] + if isinstance(l, RotationLayer) and qubit in l.rotations: + return start_layer + if qubit in sets[start_layer]: + return None + + new_layers = [layer.copy() for layer in self.layers] + cur_layer_index = 0 + while cur_layer_index < len(new_layers): + layer = new_layers[cur_layer_index] + if isinstance(layer, RotationLayer): + rewrites = {} + for q, r in layer.rotations.items(): + if not r: + continue + v = scan(q, cur_layer_index) + if v is not None: + rewrites[q] = v + for q, dst in rewrites.items(): + new_layer: RotationLayer = cast(RotationLayer, new_layers[dst]) + new_layer.append_rotation(layer.rotations.pop(q), q) + sets[cur_layer_index].remove(q) + if new_layer.rotations.get(q): + sets[dst].add(q) + elif q in sets[dst]: + sets[dst].remove(q) + elif isinstance(layer, LoopLayer): + layer.body = layer.body.with_rotations_merged_earlier() + cur_layer_index += 1 + return LayerCircuit([layer for layer in new_layers if not layer.is_vacuous()]) + + def with_irrelevant_tail_layers_removed(self) -> "LayerCircuit": + irrelevant_layer_types_at_end = ( + ResetLayer, + InteractLayer, + FeedbackLayer, + RotationLayer, + SwapLayer, + ISwapLayer, + InteractSwapLayer, + EmptyLayer, + ) + result = list(self.layers) + while len(result) > 0 and isinstance(result[-1], irrelevant_layer_types_at_end): + result.pop() + return LayerCircuit(result) + + def to_stim_circuit(self) -> stim.Circuit: + circuit = stim.Circuit() + tick_coming = False + for layer in self.layers: + if tick_coming and layer.requires_tick_before(): + circuit.append("TICK") + tick_coming = False + layer.append_into_stim_circuit(circuit) + tick_coming |= layer.implies_eventual_tick_after() + return circuit diff --git a/src/gen/_layers/_layer_circuit_test.py b/src/gen/_layers/_layer_circuit_test.py new file mode 100644 index 0000000..71be4e4 --- /dev/null +++ b/src/gen/_layers/_layer_circuit_test.py @@ -0,0 +1,354 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +from gen._layers._layer_circuit import LayerCircuit + + +def test_with_squashed_rotations(): + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + S 0 1 2 3 + TICK + CZ 1 2 + TICK + H 0 3 + TICK + CZ 1 2 + TICK + S 0 1 2 3 + """ + ) + ) + .with_clearable_rotation_layers_cleared() + .to_stim_circuit() + == stim.Circuit( + """ + C_XYZ 0 3 + S 1 2 + TICK + CZ 1 2 + TICK + CZ 1 2 + TICK + S 0 1 2 3 + """ + ) + ) + + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + S 0 1 2 3 + TICK + CZ 0 2 + TICK + H 0 3 + TICK + CZ 1 2 + TICK + S 0 1 2 3 + """ + ) + ) + .with_clearable_rotation_layers_cleared() + .to_stim_circuit() + == stim.Circuit( + """ + C_XYZ 3 + S 0 1 2 + TICK + CZ 0 2 + TICK + CZ 1 2 + TICK + C_ZYX 0 + S 1 2 3 + """ + ) + ) + + +def test_with_rotations_before_resets_removed(): + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + H 0 1 2 3 + TICK + R 0 1 + """ + ) + ) + .with_rotations_before_resets_removed() + .to_stim_circuit() + == stim.Circuit( + """ + H 2 3 + TICK + R 0 1 + """ + ) + ) + + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + H 0 1 2 3 + TICK + REPEAT 100 { + R 0 1 + TICK + H 0 1 2 3 + TICK + } + R 1 2 + TICK + """ + ) + ) + .with_rotations_before_resets_removed() + .to_stim_circuit() + == stim.Circuit( + """ + H 2 3 + TICK + REPEAT 100 { + R 0 1 + TICK + H 0 2 3 + TICK + } + R 1 2 + """ + ) + ) + + +def test_with_rotations_merged_earlier(): + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + S 0 1 2 3 + TICK + CZ 1 2 3 4 + TICK + H 0 1 2 3 + TICK + CZ 1 2 + TICK + S 0 1 2 3 + """ + ) + ) + .with_rotations_merged_earlier() + .to_stim_circuit() + == stim.Circuit( + """ + S 1 2 3 + SQRT_X 0 + TICK + CZ 1 2 3 4 + TICK + C_ZYX 3 + H 1 2 + TICK + CZ 1 2 + TICK + S 1 2 + """ + ) + ) + + +def test_with_qubit_coords_at_start(): + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + QUBIT_COORDS(2, 3) 0 + SHIFT_COORDS(0, 0, 100) + QUBIT_COORDS(5, 7) 1 + SHIFT_COORDS(0, 200) + QUBIT_COORDS(11, 13) 2 + SHIFT_COORDS(300) + R 0 1 + TICK + QUBIT_COORDS(17) 3 + H 3 + TICK + QUBIT_COORDS(19, 23, 29) 4 + REPEAT 10 { + M 0 1 2 3 + DETECTOR rec[-1] + } + """ + ) + ) + .with_qubit_coords_at_start() + .to_stim_circuit() + == stim.Circuit( + """ + QUBIT_COORDS(2, 3) 0 + QUBIT_COORDS(5, 7) 1 + QUBIT_COORDS(11, 213) 2 + QUBIT_COORDS(317) 3 + QUBIT_COORDS(319, 223, 129) 4 + SHIFT_COORDS(0, 0, 100) + SHIFT_COORDS(0, 200) + SHIFT_COORDS(300) + R 0 1 + TICK + H 3 + TICK + REPEAT 10 { + M 0 1 2 3 + DETECTOR rec[-1] + TICK + } + """ + ) + ) + + +def test_merge_shift_coords(): + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + SHIFT_COORDS(300) + SHIFT_COORDS(0, 0, 100) + SHIFT_COORDS(0, 200) + """ + ) + ) + .with_locally_optimized_layers() + .to_stim_circuit() + == stim.Circuit( + """ + SHIFT_COORDS(300, 200, 100) + """ + ) + ) + + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + SHIFT_COORDS(300) + TICK + SHIFT_COORDS(0, 0, 100) + TICK + SHIFT_COORDS(0, 200) + TICK + """ + ) + ) + .with_locally_optimized_layers() + .to_stim_circuit() + == stim.Circuit( + """ + SHIFT_COORDS(300, 200, 100) + """ + ) + ) + + +def test_merge_resets_and_measurements(): + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + RX 0 1 + TICK + RY 2 3 + """ + ) + ) + .with_locally_optimized_layers() + .to_stim_circuit() + == stim.Circuit( + """ + RX 0 1 + RY 2 3 + """ + ) + ) + + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + RX 0 1 + TICK + RY 1 2 3 + """ + ) + ) + .with_locally_optimized_layers() + .to_stim_circuit() + == stim.Circuit( + """ + RX 0 + RY 1 2 3 + """ + ) + ) + + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + MX 0 1 + TICK + MY 2 3 + """ + ) + ) + .with_locally_optimized_layers() + .to_stim_circuit() + == stim.Circuit( + """ + MX 0 1 + MY 2 3 + """ + ) + ) + + assert ( + LayerCircuit.from_stim_circuit( + stim.Circuit( + """ + MX 0 1 + TICK + MY 1 2 3 + """ + ) + ) + .with_locally_optimized_layers() + .to_stim_circuit() + == stim.Circuit( + """ + MX 0 1 + TICK + MY 1 2 3 + """ + ) + ) diff --git a/src/gen/_layers/_loop_layer.py b/src/gen/_layers/_loop_layer.py new file mode 100644 index 0000000..b632b19 --- /dev/null +++ b/src/gen/_layers/_loop_layer.py @@ -0,0 +1,58 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses +from typing import TYPE_CHECKING + +import stim + +from gen._layers._layer import Layer + +if TYPE_CHECKING: + from gen._layers._layer_circuit import LayerCircuit + + +@dataclasses.dataclass +class LoopLayer(Layer): + body: "LayerCircuit" + repetitions: int + + def copy(self) -> "LoopLayer": + return LoopLayer(body=self.body.copy(), repetitions=self.repetitions) + + def touched(self) -> set[int]: + return self.body.touched() + + def to_z_basis(self) -> list["Layer"]: + return [ + LoopLayer( + body=self.body.to_z_basis(), + repetitions=self.repetitions, + ) + ] + + def locally_optimized(self, next_layer: Layer | None) -> list[Layer | None]: + optimized = LoopLayer( + body=self.body.with_locally_optimized_layers(), + repetitions=self.repetitions, + ) + return [optimized, next_layer] + + def implies_eventual_tick_after(self) -> bool: + return False + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + body = self.body.to_stim_circuit() + body.append("TICK") + out.append(stim.CircuitRepeatBlock(repeat_count=self.repetitions, body=body)) diff --git a/src/gen/_layers/_measure_layer.py b/src/gen/_layers/_measure_layer.py new file mode 100644 index 0000000..b4e3863 --- /dev/null +++ b/src/gen/_layers/_measure_layer.py @@ -0,0 +1,62 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses + +import stim + +from gen._layers._data import R_ZYX, R_XYZ, R_XZY +from gen._layers._layer import Layer +from gen._layers._rotation_layer import RotationLayer + + +@dataclasses.dataclass +class MeasureLayer(Layer): + targets: list[int] = dataclasses.field(default_factory=list) + bases: list[str] = dataclasses.field(default_factory=list) + + def copy(self) -> "MeasureLayer": + return MeasureLayer(targets=list(self.targets), bases=list(self.bases)) + + def touched(self) -> set[int]: + return set(self.targets) + + def to_z_basis(self) -> list["Layer"]: + rot = RotationLayer( + { + q: R_XYZ if b == "Z" else R_ZYX if b == "X" else R_XZY + for q, b in zip(self.targets, self.bases) + } + ) + return [ + rot, + MeasureLayer(targets=list(self.targets), bases=["Z"] * len(self.targets)), + rot.copy(), + ] + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + for t, b in zip(self.targets, self.bases): + out.append("M" + b, [t]) + + def locally_optimized(self, next_layer: Layer | None) -> list[Layer | None]: + if isinstance(next_layer, MeasureLayer) and set(self.targets).isdisjoint( + next_layer.targets + ): + return [ + MeasureLayer( + targets=self.targets + next_layer.targets, + bases=self.bases + next_layer.bases, + ) + ] + return [self, next_layer] diff --git a/src/gen/_layers/_mpp_layer.py b/src/gen/_layers/_mpp_layer.py new file mode 100644 index 0000000..7eb4b26 --- /dev/null +++ b/src/gen/_layers/_mpp_layer.py @@ -0,0 +1,63 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses + +import stim + +from gen._layers._data import R_ZYX, R_XZY +from gen._layers._layer import Layer +from gen._layers._rotation_layer import RotationLayer + + +@dataclasses.dataclass +class MppLayer(Layer): + targets: list[list[stim.GateTarget]] = dataclasses.field(default_factory=list) + + def copy(self) -> "MppLayer": + return MppLayer(targets=[list(e) for e in self.targets]) + + def touched(self) -> set[int]: + return set(t.value for mpp in self.targets for t in mpp) + + def to_z_basis(self) -> list["Layer"]: + assert len(self.touched()) == sum(len(e) for e in self.targets) + rot = RotationLayer() + new_targets: list[list[stim.GateTarget]] = [] + for groups in self.targets: + new_group: list[stim.GateTarget] = [] + for t in groups: + new_group.append(stim.target_z(t.value)) + if t.is_x_target: + rot.append_rotation(R_ZYX, t.value) + elif t.is_y_target: + rot.append_rotation(R_XZY, t.value) + elif not t.is_z_target: + raise NotImplementedError(f"{t=}") + new_targets.append(new_group) + + return [ + rot, + MppLayer(targets=new_targets), + rot.copy(), + ] + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + flat_targets = [] + for group in self.targets: + for t in group: + flat_targets.append(t) + flat_targets.append(stim.target_combiner()) + flat_targets.pop() + out.append("MPP", flat_targets) diff --git a/src/gen/_layers/_noise_layer.py b/src/gen/_layers/_noise_layer.py new file mode 100644 index 0000000..3ff2798 --- /dev/null +++ b/src/gen/_layers/_noise_layer.py @@ -0,0 +1,43 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses + +import stim + +from gen._layers._layer import Layer + + +@dataclasses.dataclass +class NoiseLayer(Layer): + circuit: stim.Circuit = dataclasses.field(default_factory=stim.Circuit) + + def copy(self) -> "NoiseLayer": + return NoiseLayer(circuit=self.circuit.copy()) + + def touched(self) -> set[int]: + return { + target.qubit_value + for instruction in self.circuit + for target in instruction.targets_copy() + } + + def requires_tick_before(self) -> bool: + return False + + def implies_eventual_tick_after(self) -> bool: + return False + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + out += self.circuit diff --git a/src/gen/_layers/_qubit_coord_annotation_layer.py b/src/gen/_layers/_qubit_coord_annotation_layer.py new file mode 100644 index 0000000..0c2ff71 --- /dev/null +++ b/src/gen/_layers/_qubit_coord_annotation_layer.py @@ -0,0 +1,48 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses +from typing import Iterable + +import stim + +from gen._layers._layer import Layer + + +@dataclasses.dataclass +class QubitCoordAnnotationLayer(Layer): + coords: dict[int, list[float]] = dataclasses.field(default_factory=dict) + + def offset_by(self, args: Iterable[float]): + for index, offset in enumerate(args): + if offset: + for q, qubit_coords in self.coords.items(): + if index < len(qubit_coords): + qubit_coords[index] += offset + + def copy(self) -> "Layer": + return QubitCoordAnnotationLayer(coords=dict(self.coords)) + + def touched(self) -> set[int]: + return set() + + def requires_tick_before(self) -> bool: + return False + + def implies_eventual_tick_after(self) -> bool: + return False + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + for q in sorted(self.coords.keys()): + out.append("QUBIT_COORDS", [q], self.coords[q]) diff --git a/src/gen/_layers/_reset_layer.py b/src/gen/_layers/_reset_layer.py new file mode 100644 index 0000000..83a3442 --- /dev/null +++ b/src/gen/_layers/_reset_layer.py @@ -0,0 +1,65 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses +from typing import Literal + +import stim + +from gen._layers._data import R_XYZ, R_ZYX, R_XZY +from gen._layers._layer import Layer +from gen._layers._rotation_layer import RotationLayer + + +@dataclasses.dataclass +class ResetLayer(Layer): + targets: dict[int, Literal["X", "Y", "Z"]] = dataclasses.field(default_factory=dict) + + def copy(self) -> "ResetLayer": + return ResetLayer(targets=dict(self.targets)) + + def touched(self) -> set[int]: + return set(self.targets.keys()) + + def to_z_basis(self) -> list["Layer"]: + return [ + ResetLayer(targets={q: "Z" for q in self.targets.keys()}), + RotationLayer( + { + q: R_XYZ if b == "Z" else R_ZYX if b == "X" else R_XZY + for q, b in self.targets.items() + } + ), + ] + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + outs = {"X": [], "Y": [], "Z": []} + for t, b in self.targets.items(): + outs[b].append(t) + for b, vs in outs.items(): + if vs: + out.append("R" + b, vs) + + def locally_optimized(self, next_layer: Layer | None) -> list[Layer | None]: + if isinstance(next_layer, ResetLayer): + return [ + ResetLayer( + targets={ + t: b + for layer in [self, next_layer] + for t, b in layer.targets.items() + } + ) + ] + return [self, next_layer] diff --git a/src/gen/_layers/_rotation_layer.py b/src/gen/_layers/_rotation_layer.py new file mode 100644 index 0000000..42e094c --- /dev/null +++ b/src/gen/_layers/_rotation_layer.py @@ -0,0 +1,89 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses + +import sinter +import stim + +from gen._layers._data import ( + R_ZXY, + R_YZX, + ORIENTATIONS, + R_XYZ, + ORIENTATION_MULTIPLICATION_TABLE, +) +from gen._layers._layer import Layer + + +@dataclasses.dataclass +class RotationLayer(Layer): + rotations: dict[int, int] = dataclasses.field(default_factory=dict) + + def touched(self) -> set[int]: + return {k for k, v in self.rotations.items() if v} + + def copy(self) -> "RotationLayer": + return RotationLayer(dict(self.rotations)) + + def inverse(self) -> "RotationLayer": + return RotationLayer( + rotations={ + q: R_YZX if r == R_ZXY else R_ZXY if r == R_YZX else r + for q, r in self.rotations.items() + } + ) + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + v = sinter.group_by(self.rotations.items(), key=lambda e: e[1]) + for r, items in sorted(v.items(), key=lambda e: ORIENTATIONS[e[0]]): + if r: + out.append(ORIENTATIONS[r], sorted(q for q, _ in items)) + + def prepend_rotation(self, rotation_index: int, target: int): + r1 = self.rotations.setdefault(target, R_XYZ) + self.rotations[target] = ORIENTATION_MULTIPLICATION_TABLE[r1][rotation_index] + + def append_rotation(self, rotation_index: int, target: int): + r1 = self.rotations.setdefault(target, R_XYZ) + self.rotations[target] = ORIENTATION_MULTIPLICATION_TABLE[rotation_index][r1] + + def is_vacuous(self) -> bool: + return not any(self.rotations.values()) + + def locally_optimized(self, next_layer: Layer | None) -> list[Layer | None]: + from gen._layers._det_obs_annotation_layer import DetObsAnnotationLayer + from gen._layers._feedback_layer import FeedbackLayer + from gen._layers._reset_layer import ResetLayer + from gen._layers._shift_coord_annotation_layer import ShiftCoordAnnotationLayer + + if isinstance(next_layer, (DetObsAnnotationLayer, ShiftCoordAnnotationLayer)): + return [next_layer, self] + if isinstance(next_layer, FeedbackLayer): + return [next_layer.before(self), self] + if isinstance(next_layer, ResetLayer): + trimmed = self.copy() + for t in next_layer.targets.keys(): + if t in trimmed.rotations: + del trimmed.rotations[t] + if trimmed.rotations: + return [trimmed, next_layer] + else: + return [next_layer] + if isinstance(next_layer, RotationLayer): + result = RotationLayer(rotations=dict(self.rotations)) + for q, r in next_layer.rotations.items(): + result.append_rotation(r, q) + return [result] + return [self, next_layer] diff --git a/src/gen/_layers/_shift_coord_annotation_layer.py b/src/gen/_layers/_shift_coord_annotation_layer.py new file mode 100644 index 0000000..f7b6504 --- /dev/null +++ b/src/gen/_layers/_shift_coord_annotation_layer.py @@ -0,0 +1,54 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses +from typing import Iterable + +import stim + +from gen._layers._layer import Layer + + +@dataclasses.dataclass +class ShiftCoordAnnotationLayer(Layer): + shift: list[float] = dataclasses.field(default_factory=list) + + def offset_by(self, args: Iterable[float]): + for k, arg in enumerate(args): + if k >= len(self.shift): + self.shift.append(arg) + else: + self.shift[k] += arg + + def copy(self) -> "ShiftCoordAnnotationLayer": + return ShiftCoordAnnotationLayer(shift=self.shift) + + def touched(self) -> set[int]: + return set() + + def requires_tick_before(self) -> bool: + return False + + def implies_eventual_tick_after(self) -> bool: + return False + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + out.append("SHIFT_COORDS", [], self.shift) + + def locally_optimized(self, next_layer: Layer | None) -> list[Layer | None]: + if isinstance(next_layer, ShiftCoordAnnotationLayer): + result = self.copy() + result.offset_by(next_layer.shift) + return [result] + return [self, next_layer] diff --git a/src/gen/_layers/_sqrt_pp_layer.py b/src/gen/_layers/_sqrt_pp_layer.py new file mode 100644 index 0000000..fbb2885 --- /dev/null +++ b/src/gen/_layers/_sqrt_pp_layer.py @@ -0,0 +1,75 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import collections +import dataclasses + +import stim + +from gen._layers._data import R_XZY, R_ZYX, R_YXZ +from gen._layers._interact_layer import InteractLayer +from gen._layers._layer import Layer +from gen._layers._rotation_layer import RotationLayer + + +@dataclasses.dataclass +class SqrtPPLayer(Layer): + targets1: list[int] = dataclasses.field(default_factory=list) + targets2: list[int] = dataclasses.field(default_factory=list) + bases: list[str] = dataclasses.field(default_factory=list) + + def touched(self) -> set[int]: + return set(self.targets1 + self.targets2) + + def copy(self) -> "SqrtPPLayer": + return SqrtPPLayer( + targets1=list(self.targets1), + targets2=list(self.targets2), + bases=list(self.bases), + ) + + def to_z_basis(self) -> list["Layer"]: + interact = InteractLayer() + rot = RotationLayer() + for q1, q2, b in zip(self.targets1, self.targets2, self.bases): + interact.targets1.append(q1) + interact.targets2.append(q2) + interact.bases1.append(b) + interact.bases1.append(b) + if b == "X": + r = R_XZY + elif b == "Y": + r = R_ZYX + elif b == "Z": + r = R_YXZ + else: + raise NotImplementedError(f"{b=}") + rot.append_rotation(r, q1) + rot.append_rotation(r, q2) + + return [ + rot, + *interact.to_z_basis(), + ] + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + groups = collections.defaultdict(list) + for q1, q2, b in zip(self.targets1, self.targets2, self.bases): + gate = f"SQRT_{b}{b}" + if q2 < q1: + q1, q2 = q2, q1 + groups[gate].append((q1, q2)) + for gate in sorted(groups.keys()): + for pair in sorted(groups[gate]): + out.append(gate, pair) diff --git a/src/gen/_layers/_swap_layer.py b/src/gen/_layers/_swap_layer.py new file mode 100644 index 0000000..7dc1e9c --- /dev/null +++ b/src/gen/_layers/_swap_layer.py @@ -0,0 +1,51 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dataclasses + +import stim + +from gen._layers._interact_layer import InteractLayer +from gen._layers._layer import Layer + + +@dataclasses.dataclass +class SwapLayer(Layer): + targets1: list[int] = dataclasses.field(default_factory=list) + targets2: list[int] = dataclasses.field(default_factory=list) + + def touched(self) -> set[int]: + return set(self.targets1 + self.targets2) + + def copy(self) -> "SwapLayer": + return SwapLayer(targets1=list(self.targets1), targets2=list(self.targets2)) + + def append_into_stim_circuit(self, out: stim.Circuit) -> None: + pairs = [] + for k in range(len(self.targets1)): + t1 = self.targets1[k] + t2 = self.targets2[k] + t1, t2 = sorted([t1, t2]) + pairs.append((t1, t2)) + for pair in sorted(pairs): + out.append("SWAP", pair) + + def locally_optimized(self, next_layer: Layer | None) -> list[Layer | None]: + if isinstance(next_layer, InteractLayer): + from gen._layers._interact_swap_layer import InteractSwapLayer + + i = next_layer.copy() + i.targets1, i.targets2 = i.targets2, i.targets1 + return [InteractSwapLayer(i_layer=i, swap_layer=self.copy())] + return [self, next_layer] diff --git a/src/gen/_layers/_transpile.py b/src/gen/_layers/_transpile.py new file mode 100644 index 0000000..1b9fe1c --- /dev/null +++ b/src/gen/_layers/_transpile.py @@ -0,0 +1,41 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +from gen._layers._layer_circuit import LayerCircuit + + +def transpile_to_z_basis_interaction_circuit( + circuit: stim.Circuit, *, is_entire_circuit: bool = True +) -> stim.Circuit: + """Converts to a circuit using CZ, ISWAP, and MZZ as appropriate. + + This method mostly focuses on inserting single qubit rotations to convert + interactions into their Z basis variant. It also does some optimizations + that remove redundant rotations which would tend to be introduced by this + process. + """ + c = LayerCircuit.from_stim_circuit(circuit) + c = c.with_qubit_coords_at_start() + c = c.with_locally_optimized_layers() + c = c.to_z_basis() + c = c.with_rotations_rolled_from_end_of_loop_to_start_of_loop() + c = c.with_locally_optimized_layers() + c = c.with_clearable_rotation_layers_cleared() + c = c.with_rotations_merged_earlier() + c = c.with_rotations_before_resets_removed() + if is_entire_circuit: + c = c.with_irrelevant_tail_layers_removed() + return c.to_stim_circuit() diff --git a/src/gen/_layers/_transpile_test.py b/src/gen/_layers/_transpile_test.py new file mode 100644 index 0000000..fd3511b --- /dev/null +++ b/src/gen/_layers/_transpile_test.py @@ -0,0 +1,569 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +from gen import transpile_to_z_basis_interaction_circuit + + +def test_to_cz_circuit_rotation_folding(): + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + """ + ) + ) + == stim.Circuit( + """ + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + C_XYZ 0 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + C_XYZ 0 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + I 0 + TICK + C_XYZ 0 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + C_XYZ 0 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + C_XYZ 0 + TICK + I 0 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + C_XYZ 0 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + H 0 + TICK + H 0 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + H 0 1 2 3 4 5 + TICK + I 0 + H_YZ 1 + H_XY 2 + C_XYZ 3 + C_ZYX 4 + H 5 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + C_XYZ 1 + C_ZYX 2 + H 0 + S 4 + SQRT_X 3 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + H_XY 0 1 2 3 4 5 + TICK + I 0 + H_YZ 1 + H_XY 2 + C_XYZ 3 + C_ZYX 4 + H 5 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + C_XYZ 5 + C_ZYX 1 + H 3 + S 0 + SQRT_X 4 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + H_YZ 0 1 2 3 4 5 + TICK + I 0 + H_YZ 1 + H_XY 2 + C_XYZ 3 + C_ZYX 4 + H 5 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + C_XYZ 2 + C_ZYX 5 + H 4 + S 3 + SQRT_X 0 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + C_XYZ 0 1 2 3 4 5 + TICK + I 0 + H_YZ 1 + H_XY 2 + C_XYZ 3 + C_ZYX 4 + H 5 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + C_XYZ 0 + C_ZYX 3 + H 1 + S 5 + SQRT_X 2 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + C_ZYX 0 1 2 3 4 5 + TICK + I 0 + H_YZ 1 + H_XY 2 + C_XYZ 3 + C_ZYX 4 + H 5 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + C_XYZ 4 + C_ZYX 0 + H 2 + S 1 + SQRT_X 5 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + I 0 1 2 3 4 5 + TICK + I 0 + H_YZ 1 + H_XY 2 + C_XYZ 3 + C_ZYX 4 + H 5 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + C_XYZ 3 + C_ZYX 4 + H 5 + S 2 + SQRT_X 1 + TICK + M 0 1 2 3 + """ + ) + ) + + +def test_to_cz_circuit_loop_boundary_folding(): + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + H 2 + TICK + CX rec[-1] 2 + TICK + S 2 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + CZ rec[-1] 2 + C_ZYX 2 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + MRX 0 + DETECTOR rec[-1] + TICK + M 0 + TICK + H 0 + """ + ) + ) + == stim.Circuit( + """ + H 0 + TICK + M 0 + TICK + R 0 + DETECTOR rec[-1] + TICK + H 0 + TICK + M 0 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + REPEAT 100 { + C_XYZ 0 + TICK + CZ 0 1 + TICK + H 0 + TICK + } + M 0 + """ + ) + ) + == stim.Circuit( + """ + H 0 + TICK + REPEAT 100 { + SQRT_X 0 + TICK + CZ 0 1 + TICK + } + H 0 + TICK + M 0 + """ + ) + ) + + +def test_to_cz_circuit_from_cnot(): + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + CX 0 1 2 3 + TICK + CX 1 0 2 3 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + H 1 3 + TICK + CZ 0 1 2 3 + TICK + H 0 1 + TICK + CZ 0 1 2 3 + TICK + H 0 3 + TICK + M 0 1 2 3 + """ + ) + ) + + +def test_to_cz_circuit_from_swap_cnot(): + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + CNOT 0 1 + TICK + SWAP 0 1 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + H 1 + TICK + ISWAP 0 1 + TICK + C_XYZ 0 + S 1 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + CNOT 0 1 + TICK + SWAP 1 0 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + H 1 + TICK + ISWAP 0 1 + TICK + C_XYZ 0 + S 1 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + SWAP 1 0 + TICK + CNOT 1 0 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + H 1 + TICK + ISWAP 0 1 + TICK + C_XYZ 0 + S 1 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + SWAP 0 1 + TICK + CNOT 1 0 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + H 1 + TICK + ISWAP 0 1 + TICK + C_XYZ 0 + S 1 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + CNOT 1 0 + TICK + SWAP 0 1 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + H 0 + TICK + ISWAP 0 1 + TICK + C_XYZ 1 + S 0 + TICK + M 0 1 2 3 + """ + ) + ) + + assert ( + transpile_to_z_basis_interaction_circuit( + stim.Circuit( + """ + SWAP 0 1 + TICK + CNOT 0 1 + TICK + M 0 1 2 3 + """ + ) + ) + == stim.Circuit( + """ + H 0 + TICK + ISWAP 0 1 + TICK + C_XYZ 1 + S 0 + TICK + M 0 1 2 3 + """ + ) + ) diff --git a/src/gen/_surf/__init__.py b/src/gen/_surf/__init__.py new file mode 100644 index 0000000..1b5c7c0 --- /dev/null +++ b/src/gen/_surf/__init__.py @@ -0,0 +1,55 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from gen._surf._closed_curve import ( + ClosedCurve, +) +from gen._surf._css_observable_boundary_pair import ( + CssObservableBoundaryPair, +) +from gen._surf._geo import ( + int_points_on_line, + int_points_inside_polygon, +) +from gen._surf._order import ( + checkerboard_basis, + Order_Z, + Order_ᴎ, + Order_N, + Order_S, +) +from gen._surf._patch_outline import ( + PatchOutline, +) +from gen._surf._step_sequence_outline import ( + StepSequenceOutline, + StepOutline, +) +from gen._surf._patch_transition_outline import ( + PatchTransitionOutline, +) +from gen._surf._path_outline import ( + PathOutline, +) +from gen._surf._surface_code import ( + layer_begin, + layer_loop, + layer_transition, + layer_end, + layer_single_shot, + surface_code_patch, +) +from gen._surf._trans import ( + build_patch_to_patch_surface_code_transition_rounds, +) diff --git a/src/gen/_surf/_closed_curve.py b/src/gen/_surf/_closed_curve.py new file mode 100644 index 0000000..b8b23f7 --- /dev/null +++ b/src/gen/_surf/_closed_curve.py @@ -0,0 +1,180 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pathlib +from typing import Iterable, Literal, Callable, TYPE_CHECKING + +from gen._core._patch import Patch +from gen._surf._geo import ( + int_travel_points_on_polygon_boundary, + int_points_on_line, + int_points_inside_polygon_set, + half_int_points_inside_int_polygon_set, +) +from gen._core._util import min_max_complex + +if TYPE_CHECKING: + import gen + + +class ClosedCurve: + """A closed series of line segments between integer coordinates aligned at 45 degree angles. + + Each line segment has an associated basis (X or Z). + """ + + def __init__( + self, *, points: Iterable[complex] = (), bases: Iterable[Literal["X", "Z"]] = () + ): + self.points = tuple(points) + self.bases = tuple(bases) + + def to_patch_outline(self) -> "gen.PatchOutline": + from gen._surf._patch_outline import PatchOutline + + return PatchOutline([self]) + + def to_patch( + self, + *, + rel_order_func: Callable[[complex], Iterable[complex]], + ) -> Patch: + return self.to_patch_outline().to_patch(rel_order_func=rel_order_func) + + def write_svg( + self, + path: str | pathlib.Path, + ) -> None: + return self.to_patch_outline().write_svg(path) + + def with_basis(self, basis: Literal["X", "Z"]) -> "ClosedCurve": + return ClosedCurve(points=self.points, bases=[basis] * len(self.bases)) + + @staticmethod + def from_cycle(point_or_basis: Iterable[Literal["X", "Z"] | complex | int | float]): + point_or_basis = list(point_or_basis) + cur_basis: Literal["X", "Z", "U"] = "U" + cur_basis_used = True + points = [] + bases: list[Literal["X", "Z", "U"]] = [] + for e in point_or_basis: + if e == "X" or e == "Z": + if not cur_basis_used: + assert cur_basis == e, "Basis disagreement" + cur_basis = e + cur_basis_used = False + elif isinstance(e, (int, float, complex)): + cur_basis_used = True + if points and points[-1] == e: + continue + points.append(e) + bases.append(cur_basis) + else: + raise NotImplementedError(f"{e=}") + assert cur_basis != "U" + if not cur_basis_used: + assert bases[0] == "U" or bases[0] == cur_basis + + for k in range(len(bases)): + if bases[k] == "U": + bases[k] = cur_basis + while points[-1] == points[0]: + points.pop() + bases.pop() + + return ClosedCurve(points=points, bases=bases) + + def to_cycle(self) -> list[Literal["X", "Z"] | complex]: + out = [] + for k in range(len(self.points)): + out.append(self.bases[k]) + out.append(self.points[k]) + out.append(self.bases[0]) + return out + + def med(self) -> complex: + """Returns the center of the axis-aligned bounding box of the curve.""" + a, b = min_max_complex(self.points) + return (a.real + b.real) // 2 + (a.imag + b.imag) // 2 * 1j + + def __len__(self): + """Returns the number of line segments making up the curve.""" + return len(self.points) + + def __getitem__(self, item: int) -> tuple[str, complex, complex]: + assert isinstance(item, int) + return self.bases[item], self.points[item - 1], self.points[item] + + def segment_indices_intersecting(self, points: set[complex]) -> list[int]: + """Returns the indices of line segments intersecting the given point set.""" + hits = [] + for k in range(len(self.points)): + a = self.points[k - 1] + b = self.points[k] + if any(e in points for e in int_points_on_line(a, b)): + hits.append(k) + return hits + + def offset_by(self, offset: complex) -> "ClosedCurve": + """Translates the curve's location by translating all of its line segments.""" + return ClosedCurve(points=[p + offset for p in self.points], bases=self.bases) + + def interior_set( + self, *, include_boundary: bool, half_ints: bool = False + ) -> frozenset[complex]: + if half_ints: + return frozenset( + half_int_points_inside_int_polygon_set( + curves=[self.points], include_boundary=include_boundary + ) + ) + return frozenset( + int_points_inside_polygon_set( + [self.points], include_boundary=include_boundary + ) + ) + + def boundary_set(self) -> set[complex]: + """Returns the set of integer coordinates along the line segments of the curve.""" + return set(int_travel_points_on_polygon_boundary(self.points)) + + def boundary_travel(self) -> list[complex]: + """Lists the integer coordinates along the line segments of the curve, in order.""" + return int_travel_points_on_polygon_boundary(self.points) + + def with_transformed_coords( + self, coord_transform: Callable[[complex], complex] + ) -> "ClosedCurve": + return ClosedCurve( + points=[coord_transform(e) for e in self.points], + bases=self.bases, + ) + + @property + def basis(self) -> Literal["X", "Z"] | None: + b = set(self.bases) + if len(b) == 1: + return next(iter(b)) + return None + + def __eq__(self, other): + if not isinstance(other, ClosedCurve): + return NotImplemented + return self.points == other.points and self.bases == other.bases + + def __ne__(self, other): + return not (self == other) + + def __repr__(self): + return f"ClosedCurve.from_cycle({self.to_cycle()!r})" diff --git a/src/gen/_surf/_closed_curve_test.py b/src/gen/_surf/_closed_curve_test.py new file mode 100644 index 0000000..c02a1c8 --- /dev/null +++ b/src/gen/_surf/_closed_curve_test.py @@ -0,0 +1,56 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from gen._surf._closed_curve import ClosedCurve + + +def test_to_from_cycle(): + c1 = ClosedCurve(points=[(5 + 0j), (5 + 3j), 3j, 0j], bases=["Z", "X", "Z", "X"]) + assert c1.to_cycle() == ["Z", (5 + 0j), "X", (5 + 3j), "Z", 3j, "X", 0j, "Z"] + assert ( + ClosedCurve.from_cycle(["Z", (5 + 0j), "X", (5 + 3j), "Z", 3j, "X", 0j, "Z"]) + == c1 + ) + assert ( + ClosedCurve.from_cycle(["Z", (5 + 0j), "X", (5 + 3j), "Z", 3j, "X", 0j]) == c1 + ) + assert ( + ClosedCurve.from_cycle([(5 + 0j), "X", (5 + 3j), "Z", 3j, "X", 0j, "Z"]) == c1 + ) + assert ( + ClosedCurve.from_cycle([(5 + 0j), "X", (5 + 3j), "Z", 3j, "X", 0j, "Z", 5]) + == c1 + ) + + c2 = ClosedCurve(points=[(5 + 0j), (5 + 3j), 3j, 0j], bases=["Z", "Z", "Z", "X"]) + assert ( + ClosedCurve.from_cycle(["Z", (5 + 0j), "Z", (5 + 3j), "Z", 3j, "X", 0j, "Z"]) + == c2 + ) + assert ( + ClosedCurve.from_cycle( + ["Z", (5 + 0j), 5, 5, "X", 5, "Z", 5, "Z", (5 + 3j), "Z", 3j, "X", 0j, "Z"] + ) + == c2 + ) + assert ( + ClosedCurve.from_cycle(["Z", (5 + 0j), (5 + 3j), "Z", 3j, "X", 0j, "Z"]) == c2 + ) + assert ( + ClosedCurve.from_cycle(["Z", (5 + 0j), "Z", (5 + 3j), 3j, "X", 0j, "Z"]) == c2 + ) + assert ( + ClosedCurve.from_cycle(["Z", (5 + 0j), (5 + 3j), "Z", 3j, "X", 0j, "Z"]) == c2 + ) + assert ClosedCurve.from_cycle([(5 + 0j), (5 + 3j), "Z", 3j, "X", 0j, "Z"]) == c2 diff --git a/src/gen/_surf/_css_observable_boundary_pair.py b/src/gen/_surf/_css_observable_boundary_pair.py new file mode 100644 index 0000000..f07f5af --- /dev/null +++ b/src/gen/_surf/_css_observable_boundary_pair.py @@ -0,0 +1,27 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Iterator + +from gen._surf._path_outline import PathOutline + + +class CssObservableBoundaryPair: + def __init__(self, *, x_obs: PathOutline, z_obs: PathOutline): + self.x_obs = x_obs + self.z_obs = z_obs + + def __iter__(self) -> Iterator[tuple[str, PathOutline]]: + yield "X", self.x_obs + yield "Z", self.z_obs diff --git a/src/gen/_surf/_geo.py b/src/gen/_surf/_geo.py new file mode 100644 index 0000000..d7daf4f --- /dev/null +++ b/src/gen/_surf/_geo.py @@ -0,0 +1,219 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import collections +from typing import Iterable, Sequence + +from gen._core._util import min_max_complex + + +def int_points_on_line(a: complex, b: complex) -> list[complex]: + """Lists the integer points along a given line segment. + + The delta `a-b` must be horizontal (imaginary part is 0), vertical + (real part is 0), or diagonal (real and imaginary parts have same + absolute magnitude). + + Args: + a: A complex number with integer real part and integer imaginary part. + b: A complex number with integer real part and integer imaginary part. + + Returns: + The list of integer points. + """ + dr = b.real - a.real + di = b.imag - a.imag + if a == b: + return [a] + if len({0, abs(di), abs(dr)}) != 2: + raise NotImplementedError( + f"{a=} to {b=} isn't horizontal, vertical, or 1:1 diagonal." + ) + steps = int(max(abs(dr), abs(di))) + result = [] + dr /= steps + di /= steps + assert int(dr) == dr + assert int(di) == di + dr = int(dr) + di = int(di) + for k in range(steps + 1): + result.append(a + dr * k + di * k * 1j) + return result + + +def int_travel_points_on_polygon_boundary(corners: Sequence[complex]) -> list[complex]: + boundary = [] + for k in range(len(corners)): + a = corners[k - 1] + b = corners[k] + for p in int_points_on_line(a, b): + if len(boundary) == 0 or boundary[-1] != p: + boundary.append(p) + assert boundary[-1] == boundary[0] + boundary.pop() + return boundary + + +def half_int_points_inside_int_polygon_set( + *, + curves: Sequence[Sequence[complex]], + include_boundary: bool, + match_mask: int | None = None, +) -> set[complex]: + curves2 = [[pt * 2 for pt in curve] for curve in curves] + interior2 = int_points_inside_polygon_set( + curves2, include_boundary=include_boundary, match_mask=match_mask + ) + return {p / 2 for p in interior2 if p.real % 2 == 1 and p.imag % 2 == 1} + + +def half_int_points_inside_int_polygon( + corners: Sequence[complex], *, include_boundary: bool +) -> set[complex]: + return half_int_points_inside_int_polygon_set( + curves=[corners], include_boundary=include_boundary + ) + + +def int_points_inside_polygon( + corners: Sequence[complex], *, include_boundary: bool +) -> set[complex]: + return int_points_inside_polygon_set([corners], include_boundary=include_boundary) + + +def int_points_inside_polygon_set( + curves: Iterable[Sequence[complex]], + *, + include_boundary: bool, + match_mask: int | None = None, +) -> set[complex]: + curves = tuple(curves) + min_c, max_c = min_max_complex((pt for curve in curves for pt in curve), default=0) + + boundary = set() + half_boundary = collections.defaultdict(int) + for k, curve in enumerate(curves): + boundary |= set(int_travel_points_on_polygon_boundary(curve)) + for p in set(int_travel_points_on_polygon_boundary([p * 2 for p in curve])): + half_boundary[p / 2] ^= 1 << k + + result = set() + for r in range(int(min_c.real), int(max_c.real) + 1): + r0 = r - 0.5 + r1 = r + 0.5 + mask0 = 0 + inside0 = 0 + mask1 = 0 + inside1 = 0 + i = int(min_c.imag) + while i <= max_c.imag: + c0 = r0 + i * 1j + c1 = r1 + i * 1j + inside0 ^= half_boundary[c0] != 0 + inside1 ^= half_boundary[c1] != 0 + mask0 ^= half_boundary[c0] + mask1 ^= half_boundary[c1] + m0 = mask0 if inside0 else 0 + m1 = mask1 if inside1 else 0 + if ( + i == int(i) + and m0 == m1 + and (m0 != 0 if match_mask is None else m0 == match_mask) + ): + result.add(r + i * 1j) + i += 0.5 + + if include_boundary: + result |= boundary + else: + result -= boundary + + return result + + +def int_point_disjoint_regions_inside_polygon_set( + curves: Iterable[Sequence[complex]], *, include_boundary: bool +) -> dict[int, set[complex]]: + curves = tuple(curves) + min_real = int(min(pt.real for curve in curves for pt in curve)) + min_imag = int(min(pt.imag for curve in curves for pt in curve)) + max_real = int(max(pt.real for curve in curves for pt in curve)) + max_imag = int(max(pt.imag for curve in curves for pt in curve)) + + half_boundary = collections.defaultdict(int) + for k, curve in enumerate(curves): + for p in set(int_travel_points_on_polygon_boundary([p * 2 for p in curve])): + half_boundary[p / 2] ^= 1 << k + + result = collections.defaultdict(set) + for r in range(min_real, max_real + 1): + r0 = r - 0.5 + r1 = r + 0.5 + + mask0 = 0 + mask1 = 0 + inside0 = 0 + inside1 = 0 + i = min_imag + while i <= max_imag: + c0 = r0 + i * 1j + c1 = r1 + i * 1j + c = r + i * 1j + b0 = half_boundary[c0] + b1 = half_boundary[c1] + new_inside0 = inside0 ^ (b0 != 0) + new_inside1 = inside1 ^ (b1 != 0) + new_mask0 = mask0 ^ b0 + new_mask1 = mask1 ^ b1 + if i == int(i): + if include_boundary: + # On horizontal segment? + if inside0 and not new_inside0: + result[mask0].add(c) + if not inside0 and new_inside0: + result[new_mask0].add(c) + if inside1 and not new_inside1: + result[mask1].add(c) + if not inside1 and new_inside1: + result[new_mask1].add(c) + + # On vertical segment? + if inside0 and not inside1: + result[mask0].add(c) + if new_inside0 and not new_inside1: + result[new_mask0].add(c) + if inside1 and not inside0: + result[mask1].add(c) + if new_inside1 and not new_inside0: + result[new_mask1].add(c) + if ( + inside0 + and inside1 + and new_inside0 + and new_inside1 + and mask0 == mask1 == new_mask0 == new_mask1 + ): + # Interior. + result[mask0].add(c) + mask0 = new_mask0 + mask1 = new_mask1 + inside0 = new_inside0 + inside1 = new_inside1 + i += 0.5 + + if 0 in result: + del result[0] + + return dict(result) diff --git a/src/gen/_surf/_geo_test.py b/src/gen/_surf/_geo_test.py new file mode 100644 index 0000000..93f5363 --- /dev/null +++ b/src/gen/_surf/_geo_test.py @@ -0,0 +1,154 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +from gen._surf._geo import ( + int_points_on_line, + int_points_inside_polygon, + half_int_points_inside_int_polygon, + int_point_disjoint_regions_inside_polygon_set, +) +from gen._core._util import sorted_complex + + +def test_int_points_on_line(): + with pytest.raises(NotImplementedError): + int_points_on_line(0, 1 + 2j) + + assert int_points_on_line(0, 0) == [0] + assert int_points_on_line(0, 5) == [0, 1, 2, 3, 4, 5] + assert int_points_on_line(1, -3) == [1, 0, -1, -2, -3] + assert int_points_on_line(1j, 3j) == [1j, 2j, 3j] + assert int_points_on_line(0, -2j) == [0, -1j, -2j] + assert int_points_on_line(5, 8 + 3j) == [5, 6 + 1j, 7 + 2j, 8 + 3j] + assert int_points_on_line(5, 8 - 3j) == [5, 6 - 1j, 7 - 2j, 8 - 3j] + assert int_points_on_line(5, 2 + 3j) == [5, 4 + 1j, 3 + 2j, 2 + 3j] + assert int_points_on_line(5, 2 - 3j) == [5, 4 - 1j, 3 - 2j, 2 - 3j] + + +def test_int_points_inside_polygon(): + assert sorted_complex( + int_points_inside_polygon([0, 3, 3 + 2j, 5j], include_boundary=True) + ) == [ + 0 + 0j, + 0 + 1j, + 0 + 2j, + 0 + 3j, + 0 + 4j, + 0 + 5j, + 1 + 0j, + 1 + 1j, + 1 + 2j, + 1 + 3j, + 1 + 4j, + 2 + 0j, + 2 + 1j, + 2 + 2j, + 2 + 3j, + 3 + 0j, + 3 + 1j, + 3 + 2j, + ] + assert sorted_complex( + int_points_inside_polygon([0, 3, 3 + 2j, 5j], include_boundary=False) + ) == [ + 1 + 1j, + 1 + 2j, + 1 + 3j, + 2 + 1j, + 2 + 2j, + ] + + +def test_half_int_points_inside_int_polygon(): + assert sorted_complex( + half_int_points_inside_int_polygon([0, 3, 3 + 2j, 5j], include_boundary=True) + ) == [ + 0.5 + 0.5j, + 0.5 + 1.5j, + 0.5 + 2.5j, + 0.5 + 3.5j, + 0.5 + 4.5j, + 1.5 + 0.5j, + 1.5 + 1.5j, + 1.5 + 2.5j, + 1.5 + 3.5j, + 2.5 + 0.5j, + 2.5 + 1.5j, + 2.5 + 2.5j, + ] + assert sorted_complex( + half_int_points_inside_int_polygon([0, 3, 3 + 2j, 5j], include_boundary=False) + ) == [ + 0.5 + 0.5j, + 0.5 + 1.5j, + 0.5 + 2.5j, + 0.5 + 3.5j, + 1.5 + 0.5j, + 1.5 + 1.5j, + 1.5 + 2.5j, + 2.5 + 0.5j, + 2.5 + 1.5j, + ] + + +def test_int_point_disjoint_regions_inside_polygon_set(): + a = int_point_disjoint_regions_inside_polygon_set( + [ + [0, 3, 3 + 2j, 2j], + [3j, 3 + 3j, 3 + 5j, 5j], + ], + include_boundary=False, + ) + assert len(a) == 2 + assert a[1] == {1 + 1j, 2 + 1j} + assert a[2] == {1 + 4j, 2 + 4j} + + a = int_point_disjoint_regions_inside_polygon_set( + [ + [0, 3, 3 + 2j, 2j], + [3j, 3 + 3j, 3 + 5j, 5j], + ], + include_boundary=True, + ) + assert len(a) == 2 + assert a[1] == { + 0, + 1, + 2, + 3, + 0 + 1j, + 1 + 1j, + 2 + 1j, + 3 + 1j, + 0 + 2j, + 1 + 2j, + 2 + 2j, + 3 + 2j, + } + assert a[2] == { + 0 + 3j, + 1 + 3j, + 2 + 3j, + 3 + 3j, + 0 + 4j, + 1 + 4j, + 2 + 4j, + 3 + 4j, + 0 + 5j, + 1 + 5j, + 2 + 5j, + 3 + 5j, + } diff --git a/src/gen/_surf/_open_curve.py b/src/gen/_surf/_open_curve.py new file mode 100644 index 0000000..841d8a9 --- /dev/null +++ b/src/gen/_surf/_open_curve.py @@ -0,0 +1,114 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Iterable, Literal + +from gen._surf._geo import int_points_on_line + + +class OpenCurve: + """A contiguous series of line segments between integer coordinates aligned at 45 degree angles. + + Each line segment has an associated basis (X or Z). + """ + + def __init__( + self, *, points: Iterable[complex], bases: Iterable[Literal["X", "Z"]] + ): + self.points = list(points) + self.bases = list(bases) + if len(self.points) < 2: + raise ValueError(f"len({self.points=}) < 2") + if len(self.points) != len(self.bases) + 1: + raise ValueError(f"len({self.points=}) != len({self.bases=}) + 1") + + @staticmethod + def from_sequence( + points_and_bases: Iterable[Literal["X", "Z"] | complex | int | float] + ): + points_and_bases = list(points_and_bases) + + points = [] + bases: list[Literal["X", "Z"]] = [] + + next_basis = None + for e in points_and_bases: + if e == "X" or e == "Z": + next_basis = e + elif isinstance(e, (int, float, complex)): + if points: + if points[-1] == e: + continue + if next_basis is None: + raise ValueError( + f"Specify basis before second point in {points_and_bases=}" + ) + bases.append(next_basis) + points.append(e) + else: + raise NotImplementedError(f"{e=}") + return OpenCurve(points=points, bases=bases) + + def to_sequence(self) -> list[Literal["X", "Z"] | complex]: + out = [] + for k in range(len(self.bases)): + out.append(self.points[k]) + out.append(self.bases[k]) + out.append(self.points[-1]) + return out + + def __len__(self): + """Returns the number of line segments making up the curve.""" + return len(self.points) + + def __getitem__(self, item: int) -> tuple[str, complex, complex]: + assert isinstance(item, int) + return self.bases[item], self.points[item], self.points[item + 1] + + def offset_by(self, offset: complex) -> "OpenCurve": + """Translates the curve's location by translating all of its line segments.""" + return OpenCurve(points=[p + offset for p in self.points], bases=self.bases) + + @property + def basis(self) -> Literal["X", "Z"] | None: + b = set(self.bases) + if len(b) == 1: + return next(iter(b)) + return None + + def int_points_set(self) -> set[complex]: + """Returns the set of integer coordinates along the line segments of the curve.""" + return set(self.int_points_in_order()) + + def int_points_in_order(self) -> list[complex]: + """Lists the integer coordinates along the line segments of the curve, in order.""" + points = [] + for k in range(len(self.bases)): + a = self.points[k] + b = self.points[k + 1] + for p in int_points_on_line(a, b): + if len(points) == 0 or points[-1] != p: + points.append(p) + return points + + def __eq__(self, other): + if not isinstance(other, OpenCurve): + return NotImplemented + return self.points == other.points and self.bases == other.bases + + def __ne__(self, other): + return not (self == other) + + def __repr__(self): + return f"OpenCurve.from_sequence({self.to_sequence()!r})" diff --git a/src/gen/_surf/_open_curve_test.py b/src/gen/_surf/_open_curve_test.py new file mode 100644 index 0000000..bc70e51 --- /dev/null +++ b/src/gen/_surf/_open_curve_test.py @@ -0,0 +1,72 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +from gen._surf._open_curve import OpenCurve + + +def test_to_from_sequence(): + c1 = OpenCurve(points=[1, 5, 9 + 4j, 9], bases=["Z", "X", "X"]) + assert c1.to_sequence() == [1, "Z", 5, "X", (9 + 4j), "X", 9] + assert OpenCurve.from_sequence([1, "Z", 5, "X", (9 + 4j), "X", 9]) == c1 + assert OpenCurve.from_sequence(["Z", 1, 5, "X", (9 + 4j), "X", 9]) == c1 + assert OpenCurve.from_sequence([1, "Z", 5, "X", (9 + 4j), 9]) == c1 + assert OpenCurve.from_sequence([1, "Z", 5, "X", "Z", "X", (9 + 4j), 9]) == c1 + assert OpenCurve.from_sequence([1, "Z", 5, "X", 5, "Z", "X", (9 + 4j), 9]) == c1 + assert ( + OpenCurve.from_sequence( + ["Z", "Z", "Z", 1, "Z", 5, "X", 5, "Z", "X", (9 + 4j), 9, "X", "Z"] + ) + == c1 + ) + + with pytest.raises(ValueError, match="len.+points.+< 2"): + OpenCurve.from_sequence([]) + with pytest.raises(ValueError, match="len.+points.+< 2"): + OpenCurve.from_sequence([1]) + with pytest.raises(ValueError, match="len.+points.+< 2"): + OpenCurve.from_sequence([1, "X"]) + with pytest.raises(NotImplementedError): + OpenCurve.from_sequence([1, "Y", 2]) + with pytest.raises(ValueError, match="len.+points.+< 2"): + OpenCurve.from_sequence([1, "X", "X"]) + + +def test_iter(): + c1 = OpenCurve(points=[1, 5, 9 + 4j, 9], bases=["Z", "X", "X"]) + assert list(c1) == [ + ("Z", 1, 5), + ("X", 5, (9 + 4j)), + ("X", (9 + 4j), 9), + ] + + +def test_int_points_in_order(): + c1 = OpenCurve(points=[1, 5, 9 + 4j, 9], bases=["Z", "X", "X"]) + assert c1.int_points_in_order() == [ + 1 + 0j, + 2 + 0j, + 3 + 0j, + 4 + 0j, + 5 + 0j, + 6 + 1j, + 7 + 2j, + 8 + 3j, + 9 + 4j, + 9 + 3j, + 9 + 2j, + 9 + 1j, + 9 + 0j, + ] diff --git a/src/gen/_surf/_order.py b/src/gen/_surf/_order.py new file mode 100644 index 0000000..f9133e6 --- /dev/null +++ b/src/gen/_surf/_order.py @@ -0,0 +1,25 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +UL, UR, DL, DR = [e * 0.5 for e in [-1 - 1j, +1 - 1j, -1 + 1j, +1 + 1j]] +Order_Z = [UL, UR, DL, DR] +Order_ᴎ = [UL, DL, UR, DR] +Order_N = [DL, UL, DR, UR] +Order_S = [DL, DR, UL, UR] + + +def checkerboard_basis(q: complex) -> str: + """Classifies a coordinate as X type or Z type according to a checkerboard.""" + is_x = int(q.real + q.imag) & 1 == 0 + return "X" if is_x else "Z" diff --git a/src/gen/_surf/_patch_outline.py b/src/gen/_surf/_patch_outline.py new file mode 100644 index 0000000..8862d09 --- /dev/null +++ b/src/gen/_surf/_patch_outline.py @@ -0,0 +1,353 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import collections +import functools +import pathlib +from typing import Iterable, Callable, Union, Literal, TYPE_CHECKING + +from gen._core import Patch, Tile, sorted_complex +from gen._surf._closed_curve import ClosedCurve +from gen._surf._css_observable_boundary_pair import CssObservableBoundaryPair +from gen._surf._geo import ( + int_points_on_line, + int_points_inside_polygon_set, + half_int_points_inside_int_polygon_set, + int_point_disjoint_regions_inside_polygon_set, +) +from gen._surf._order import Order_Z, checkerboard_basis +from gen._util import write_file + +if TYPE_CHECKING: + from gen._surf._patch_transition_outline import PatchTransitionOutline + + +class PatchOutline: + """Defines a surface code stabilizer configuration in terms of its boundaries.""" + + def __init__( + self, + region_curves: Iterable[ClosedCurve], + *, + observables: Iterable[CssObservableBoundaryPair] = (), + ): + """ + Args: + region_curves: The curves defining the boundaries of the patch. + These curves should not intersect each other, but may be inside + each other, creating interior voids or nested islands. + """ + self.region_curves = tuple(region_curves) + self.observables = tuple(observables) + + def iter_control_points(self) -> Iterable[complex]: + for curve in self.region_curves: + yield from curve.points + + def validate(self): + if not self.observables: + return + boundary_xs = self.x_boundary_set + boundary_zs = self.z_boundary_set + + for i in range(len(self.observables)): + for j in range(len(self.observables)): + pts_x = self.observables[i].x_obs.int_point_set + pts_z = self.observables[j].z_obs.int_point_set + does_commute = len(pts_x & pts_z) % 2 == 0 + should_commute = i != j + if does_commute != should_commute: + raise ValueError( + f"Bad commutation relationship between X{i} and Z{j}: {pts_x=} vs {pts_z=}" + ) + + for obs_pair in self.observables: + for basis, obs in obs_pair: + same_boundary_points = boundary_xs if basis == "X" else boundary_zs + if obs.end_point_set - same_boundary_points: + raise ValueError( + f"Observable doesn't terminate on same-basis boundaries: {basis=} {obs=}." + ) + if not (obs.int_point_set - same_boundary_points): + raise ValueError( + f"Observable is a stabilizer (only runs along same-basis boundaries): {basis=} {obs=}." + ) + + @functools.cached_property + def used_set(self) -> frozenset[complex]: + return frozenset(self.interior_set(include_boundary=True)) + + @functools.cached_property + def x_boundary_set(self) -> frozenset[complex]: + result = set() + for curve in self.region_curves: + for basis, a, b in curve: + if basis == "X": + result |= set(int_points_on_line(a, b)) + return frozenset(result) + + @functools.cached_property + def z_boundary_set(self) -> frozenset[complex]: + result = set() + for curve in self.region_curves: + for basis, a, b in curve: + if basis == "Z": + result |= set(int_points_on_line(a, b)) + return frozenset(result) + + @functools.cached_property + def boundary_set(self) -> frozenset[complex]: + """Returns the set of integer coordinates that are on any of the boundary curves.""" + result = set() + for c in self.region_curves: + result |= c.boundary_set() + return frozenset(result) + + def interior_set(self, *, include_boundary: bool) -> set[complex]: + """Returns the set of integer coordinates inside the bounded area. + + Args: + include_boundary: Whether or not boundary points are considered part + of the interior or not. + """ + return int_points_inside_polygon_set( + [c.points for c in self.region_curves], include_boundary=include_boundary + ) + + def disjoint_interiors(self, *, include_boundary: bool) -> dict[int, set[complex]]: + """Groups the interior by connected component. + + Args: + include_boundary: Whether or not boundary points are considered part + of the interior or not. + + Returns: + A (mask -> interior) dictionary where the mask is the set of curves + the interior is within and the interior is a set of integer + coordinates. + """ + return int_point_disjoint_regions_inside_polygon_set( + [c.points for c in self.region_curves], include_boundary=include_boundary + ) + + def fused(self, a: complex, b: complex) -> "PatchOutline": + """Performs lattice surgery between the two segments intersected by the line from a to b. + + It is assumed that there are exactly two segments along the line from a to b. + It is assumed that these two segments' endpoints are equal when perp-projecting + onto the a-to-b vector. + + Returns: + A boundary list containing the stitched result. + """ + hits = [] + pts = set(int_points_on_line(a, b)) + for k in range(len(self.region_curves)): + for e in self.region_curves[k].segment_indices_intersecting(pts): + hits.append((k, e)) + if len(hits) != 2: + raise NotImplementedError(f"len({hits=}) != 2") + + (c0, s0), (c1, s1) = sorted(hits) + if c0 == c1: + # creating an interior space + c = c0 + v = self.region_curves[c] + new_points = [] + new_bases = [] + fb = v.bases[s0 - 1] + + new_bases.extend(v.bases[:s0]) + new_points.extend(v.points[:s0]) + new_points.extend(v.points[s1:]) + new_bases.append(fb) + new_bases.extend(v.bases[s1 + 1 :]) + + interior_points = v.points[s0:s1] + interior_bases = v.bases[s0:s1] + + return PatchOutline( + [ + *self.region_curves[:c], + ClosedCurve(points=new_points, bases=new_bases), + *self.region_curves[c + 1 :], + ClosedCurve(points=interior_points, bases=interior_bases), + ] + ) + else: + # stitching two regions + v0 = self.region_curves[c0] + v1 = self.region_curves[c1] + new_points = [] + new_bases = [] + fb = v0.bases[s0 - 1] + + new_bases.extend(v0.bases[:s0]) + new_points.extend(v0.points[:s0]) + + new_points.extend(v1.points[s1:]) + new_bases.append(fb) + new_bases.extend(v1.bases[s1 + 1 :]) + + new_points.extend(v1.points[:s1]) + new_bases.extend(v1.bases[:s1]) + + new_points.extend(v0.points[s0:]) + new_bases.append(fb) + new_bases.extend(v0.bases[s0 + 1 :]) + + return PatchOutline( + [ + *self.region_curves[:c0], + ClosedCurve(points=new_points, bases=new_bases), + *self.region_curves[c0 + 1 : c1], + *self.region_curves[c1 + 1 :], + ] + ) + + def __eq__(self, other): + if not isinstance(other, PatchOutline): + return NotImplemented + return self.region_curves == other.region_curves + + def __ne__(self, other): + return not (self == other) + + def __repr__(self): + return f"PatchOutline(curves={self.region_curves!r})" + + def write_svg( + self, + path: str | pathlib.Path, + *, + other_segments: Iterable[tuple[complex, Literal["X", "Y", "Z"], complex]] = (), + other: Union[ + "PatchOutline", + "PatchTransitionOutline", + Iterable[Union["PatchOutline", "PatchTransitionOutline"]], + ] = (), + ) -> None: + from gen._surf._viz_patch_outline_svg import patch_outline_svg_viewer + from gen._surf._patch_transition_outline import PatchTransitionOutline + + if isinstance(other, (PatchOutline, PatchTransitionOutline)): + other = [other] + viewer = patch_outline_svg_viewer( + values=[self, *other], + other_segments=other_segments, + ) + write_file(path, viewer) + + def to_patch( + self, + *, + rel_order_func: Callable[[complex], Iterable[complex]] | None = None, + ) -> Patch: + """Converts the boundary list into an explicit surface code stabilizer configuration.""" + + if rel_order_func is None: + rel_order_func = lambda _: Order_Z + data_qubits = self.interior_set(include_boundary=True) + contiguous_x_data_qubit_sets = [] + contiguous_z_data_qubit_sets = [] + for c in self.region_curves: + cur_set = None + for k in range(len(c.points)): + if k == 0 or c.bases[k] != c.bases[k - 1]: + cur_set = set() + if c.bases[k] == "X": + contiguous_x_data_qubit_sets.append(cur_set) + else: + contiguous_z_data_qubit_sets.append(cur_set) + a = c.points[k - 1] + b = c.points[k] + for p in int_points_on_line(a, b): + cur_set.add(p) + + internal_measure_qubits = half_int_points_inside_int_polygon_set( + curves=[curve.points for curve in self.region_curves], + include_boundary=True, + ) + + plaqs = [] + external_measure_qubits = set() + for c in self.region_curves: + b = c.boundary_travel() + b3 = b * 3 + n = len(b) + for k in range(n): + nearby_measurement_qubits = {b[k] + d for d in Order_Z} + for m in nearby_measurement_qubits: + if m in internal_measure_qubits: + continue + if m in external_measure_qubits: + continue + relevant_contiguous_sets = ( + contiguous_z_data_qubit_sets + if checkerboard_basis(m) == "Z" + else contiguous_x_data_qubit_sets + ) + nearby_boundary_data = b3[n + k - 2 : n + k + 3] + ds = set() + for contiguous_candidate in relevant_contiguous_sets: + kept_ds = { + m + d + for d in Order_Z + if m + d in nearby_boundary_data + and m + d in contiguous_candidate + } + if len(kept_ds) > len(ds): + ds = kept_ds + if len(ds) < 2: + continue + plaqs.append( + Tile( + bases=checkerboard_basis(m), + measurement_qubit=m, + ordered_data_qubits=[ + m + d if d is not None and m + d in ds else None + for d in rel_order_func(m) + ], + ) + ) + external_measure_qubits.add(m) + + d_count = collections.Counter() + for m in internal_measure_qubits: + for d in Order_Z: + d_count[m + d] += 1 + for p in plaqs: + # Don't trim data qubits used by boundary measurements. + for d in p.data_set: + d_count[d] += 100 + + used_data_qubits = set() + for d in sorted_complex(data_qubits): + if d_count[d] > 1: + used_data_qubits.add(d) + + for m in internal_measure_qubits: + b = checkerboard_basis(m) + plaqs.append( + Tile( + bases=b, + measurement_qubit=m, + ordered_data_qubits=[ + m + d if d is not None and m + d in used_data_qubits else None + for d in rel_order_func(m) + ], + ) + ) + + return Patch(plaqs) diff --git a/src/gen/_surf/_patch_outline_test.py b/src/gen/_surf/_patch_outline_test.py new file mode 100644 index 0000000..bd96de7 --- /dev/null +++ b/src/gen/_surf/_patch_outline_test.py @@ -0,0 +1,536 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + +from gen._surf._geo import int_points_inside_polygon +from gen._surf._order import Order_Z, Order_ᴎ, checkerboard_basis +from gen._surf._patch_outline import PatchOutline +from gen._surf._closed_curve import ClosedCurve +from gen._surf._css_observable_boundary_pair import CssObservableBoundaryPair +from gen._surf._path_outline import PathOutline +from gen._surf._viz_patch_outline_svg import patch_outline_svg_viewer + + +def test_tight_boundary(): + c1 = ClosedCurve.from_cycle(["Z", (5 + 0j), "X", (5 + 3j), "Z", 3j, "X", 0j, "Z"]) + + c2 = ClosedCurve.from_cycle( + [ + "X", + 5 + 4j, + "X", + 5 + 6j, + "X", + 0 + 6j, + "X", + 0 + 4j, + ] + ) + + b = PatchOutline([c1, c2]) + fused = b.fused(c1.med(), c2.med()) + + c3 = ClosedCurve.from_cycle( + [ + "Z", + 5 + 0j, + "X", + 5 + 3j, + "X", + 5 + 4j, + "X", + 5 + 6j, + "X", + 0 + 6j, + "X", + 0 + 4j, + "X", + 0 + 3j, + "X", + 0 + 0j, + ] + ) + assert fused == PatchOutline([c3]) + + p = b.to_patch( + rel_order_func=lambda m: Order_Z if checkerboard_basis(m) == "Z" else Order_ᴎ + ) + assert sum(e.basis == "X" and len(e.data_set) == 2 for e in p.tiles) == 11 + assert sum(e.basis == "Z" and len(e.data_set) == 2 for e in p.tiles) == 4 + + +def test_pitchfork_boundary(): + b = PatchOutline( + [ + ClosedCurve( + points=[0, 3, 3 + 10j, 2 + 10j, 2 + 6j, 1 + 6j, 1 + 10j, 10j], + bases="XXXXZXXX", + ), + ] + ) + p = b.to_patch( + rel_order_func=lambda m: Order_Z if checkerboard_basis(m) == "Z" else Order_ᴎ + ) + + assert sum(e.basis == "X" and len(e.data_set) == 2 for e in p.tiles) == 15 + assert sum(e.basis == "X" and len(e.data_set) == 3 for e in p.tiles) == 1 + assert sum(e.basis == "Z" and len(e.data_set) == 2 for e in p.tiles) == 2 + assert sum(e.basis == "Z" and len(e.data_set) == 3 for e in p.tiles) == 0 + + +def test_line(): + c = ClosedCurve.from_cycle( + [ + "Z", + 6, + "X", + 6, + "Z", + 0, + "X", + 0, + ] + ) + b = PatchOutline([c]) + p = b.to_patch( + rel_order_func=lambda m: Order_Z if checkerboard_basis(m) == "Z" else Order_ᴎ + ) + assert p.data_set == {0, 1, 2, 3, 4, 5, 6} + assert p.measure_set == { + 0.5 + 0.5j, + 1.5 - 0.5j, + 2.5 + 0.5j, + 3.5 - 0.5j, + 4.5 + 0.5j, + 5.5 - 0.5j, + } + assert all(len(e.data_set) == 2 for e in p.tiles) + assert len(p.tiles) == 6 + + +def test_hole(): + c = ClosedCurve.from_cycle( + [ + "Z", + 0, + "X", + 10, + "Z", + 10 + 10j, + "X", + 10j, + ] + ) + + c2 = ClosedCurve.from_cycle( + [ + "X", + 2 + 2j, + "X", + 8 + 2j, + "X", + 8 + 8j, + "X", + 2 + 8j, + ] + ) + + b = PatchOutline([c, c2]) + p = b.to_patch( + rel_order_func=lambda m: Order_Z if checkerboard_basis(m) == "Z" else Order_ᴎ + ) + assert sum(e.basis == "X" and len(e.data_set) == 2 for e in p.tiles) == 18 + assert sum(e.basis == "Z" and len(e.data_set) == 2 for e in p.tiles) == 10 + assert sum(e.basis == "X" and len(e.data_set) == 3 for e in p.tiles) == 2 + assert sum(e.basis == "Z" and len(e.data_set) == 3 for e in p.tiles) == 0 + + +def test_fused_simple(): + a = ClosedCurve.from_cycle( + [ + "X", + 4 + 0j, + "Z", + 4 + 4j, + "X", + 0 + 4j, + "Z", + 0 + 0j, + ] + ) + + b = PatchOutline([a, a.offset_by(6)]) + b = b.fused(2 + 2j, 8 + 2j) + assert b == PatchOutline( + [ + ClosedCurve( + points=[ + 4 + 0j, + 6 + 0j, + 10 + 0j, + 10 + 4j, + 6 + 4j, + 4 + 4j, + 0 + 4j, + 0 + 0j, + ], + bases=["X", "X", "X", "Z", "X", "X", "X", "Z"], + ), + ] + ) + + +def test_fused_stability(): + a = ClosedCurve.from_cycle( + [ + "Z", + 4 + 0j, + "Z", + 4 + 4j, + "Z", + 0 + 4j, + "Z", + 0 + 0j, + ] + ) + + b = PatchOutline([a, a.offset_by(6j), a.offset_by(12j)]) + b = b.fused(2 + 2j, 2 + 8j) + assert b == PatchOutline( + [ + ClosedCurve( + points=[ + 4 + 0j, + 4 + 4j, + 4 + 6j, + 4 + 10j, + 0 + 10j, + 0 + 6j, + 0 + 4j, + 0 + 0j, + ], + bases=["Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z"], + ), + a.offset_by(12j), + ] + ) + + b = b.fused(2 + 8j, 2 + 14j) + assert b == PatchOutline( + [ + ClosedCurve( + points=[ + 4 + 0j, + 4 + 4j, + 4 + 6j, + 4 + 10j, + 4 + 12j, + 4 + 16j, + 0 + 16j, + 0 + 12j, + 0 + 10j, + 0 + 6j, + 0 + 4j, + 0 + 0j, + ], + bases=["Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z"], + ), + ] + ) + + +def test_fused_t(): + a = ClosedCurve.from_cycle( + [ + "Z", + 4 + 0j, + "Z", + 4 + 4j, + "Z", + 0 + 4j, + "Z", + 0 + 0j, + ] + ) + + b = PatchOutline([a, a.offset_by(6j), a.offset_by(6j - 6)]) + b = b.fused(2 + 2j, 2 + 8j) + assert b == PatchOutline( + [ + ClosedCurve( + points=[ + 4 + 0j, + 4 + 4j, + 4 + 6j, + 4 + 10j, + 0 + 10j, + 0 + 6j, + 0 + 4j, + 0 + 0j, + ], + bases=["Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z"], + ), + a.offset_by(6j - 6), + ] + ) + + b = b.fused(-4 + 8j, 2 + 8j) + assert b == PatchOutline( + [ + ClosedCurve( + points=[ + 4 + 0j, + 4 + 4j, + 4 + 6j, + 4 + 10j, + 0 + 10j, + -2 + 10j, + -6 + 10j, + -6 + 6j, + -2 + 6j, + 0 + 6j, + 0 + 4j, + 0 + 0j, + ], + bases=["Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z", "Z"], + ), + ] + ) + assert ( + len( + [ + p + for p in int_points_inside_polygon( + b.region_curves[0].points, include_boundary=False + ) + if p.real == 0 + ] + ) + == 3 + ) + + +def test_fused_interior(): + a = ClosedCurve.from_cycle( + [ + "Z", + 12 + 0j, + "Z", + 12 + 4j, + "Z", + 8 + 4j, + "Z", + 4 + 4j, + "Z", + 4 + 8j, + "Z", + 8 + 8j, + "Z", + 12 + 8j, + "Z", + 12 + 12j, + "Z", + 0 + 12j, + "Z", + 0, + ] + ) + + actual = PatchOutline([a]).fused(10 + 2j, 10 + 10j) + assert actual == PatchOutline( + [ + ClosedCurve( + points=[(12 + 0j), (12 + 4j), (12 + 8j), (12 + 12j), 12j, 0], + bases=["Z", "Z", "Z", "Z", "Z", "Z"], + ), + ClosedCurve( + points=[(8 + 4j), (4 + 4j), (4 + 8j), (8 + 8j)], + bases=["Z", "Z", "Z", "Z"], + ), + ] + ) + + +def test_fused_inner(): + b1 = ClosedCurve.from_cycle( + [ + "X", + 0 + 16j, + 6 + 16j, + 8 + 16j, + 14 + 16j, + 16 + 16j, + 22 + 16j, + 22 + 18j, + 22 + 20j, + 22 + 22j, + 22 + 24j, + 22 + 26j, + 22 + 28j, + 22 + 30j, + 16 + 30j, + 16 + 28j, + 16 + 26j, + 14 + 26j, + 8 + 26j, + "Z", + 8 + 24j, + "X", + 14 + 24j, + 16 + 24j, + 16 + 22j, + 16 + 20j, + 16 + 18j, + 14 + 18j, + 8 + 18j, + 6 + 18j, + 6 + 20j, + 8 + 20j, + 14 + 20j, + "Z", + 14 + 22j, + "X", + 8 + 22j, + 6 + 22j, + 6 + 24j, + 6 + 26j, + 6 + 28j, + 8 + 28j, + 14 + 28j, + "Z", + 14 + 30j, + "X", + 8 + 30j, + 6 + 30j, + 30j, + 28j, + 26j, + 24j, + 22j, + 20j, + 18j, + ] + ).to_patch_outline() + b2 = b1.fused(19 + 29j, 11 + 29j) + + assert len(b2.region_curves) == 2 + assert all(e == "X" for e in b2.region_curves[0].bases) + assert b2.region_curves[1] == ClosedCurve.from_cycle( + [ + "X", + (16 + 28j), + (16 + 26j), + (14 + 26j), + (8 + 26j), + "Z", + (8 + 24j), + "X", + (14 + 24j), + (16 + 24j), + (16 + 22j), + (16 + 20j), + (16 + 18j), + (14 + 18j), + (8 + 18j), + (6 + 18j), + (6 + 20j), + (8 + 20j), + (14 + 20j), + "Z", + (14 + 22j), + "X", + (8 + 22j), + (6 + 22j), + (6 + 24j), + (6 + 26j), + (6 + 28j), + (8 + 28j), + (14 + 28j), + ] + ) + + +def test_validate(): + patch = ClosedCurve.from_cycle([0, "X", 5, "Z", 5 + 5j, "X", 5j, "Z", 0]) + obs = CssObservableBoundaryPair( + x_obs=PathOutline([(0, 5j, "X")]), + z_obs=PathOutline([(0, 5, "Z")]), + ) + PatchOutline( + [patch], + observables=[obs], + ).validate() + with pytest.raises(ValueError, match="X0 and Z1"): + PatchOutline( + [patch], + observables=[obs, obs], + ).validate() + with pytest.raises(ValueError, match="terminate on same-basis boundaries"): + PatchOutline( + [patch], + observables=[ + CssObservableBoundaryPair( + x_obs=PathOutline([(0, 5j, "X")]), + z_obs=PathOutline([(0, 4, "Z")]), + ) + ], + ).validate() + with pytest.raises(ValueError, match="only runs along same-basis boundaries"): + PatchOutline( + [patch], + observables=[ + CssObservableBoundaryPair( + x_obs=PathOutline([(0, 5, "X")]), + z_obs=PathOutline([(0, 5j, "Z")]), + ) + ], + ).validate() + + +def test_diagram(): + boundary = PatchOutline( + [ClosedCurve.from_cycle([0, "X", 5, "Z", 5 + 5j, "X", 5j, "Z", 0])], + observables=[ + CssObservableBoundaryPair( + x_obs=PathOutline([(0, 5j, "X")]), + z_obs=PathOutline([(1j, 1j + 5, "Z")]), + ), + ], + ) + assert ( + patch_outline_svg_viewer([boundary]).strip() + == """ + + +X + +Y + +Z + + + + + + + + + + + + + +""".strip() + ) diff --git a/src/gen/_surf/_patch_transition_outline.py b/src/gen/_surf/_patch_transition_outline.py new file mode 100644 index 0000000..fc928d1 --- /dev/null +++ b/src/gen/_surf/_patch_transition_outline.py @@ -0,0 +1,112 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import functools +from typing import Iterable + +import gen +from gen._surf._closed_curve import ClosedCurve +from gen._surf._geo import int_points_inside_polygon_set +from gen._surf._path_outline import PathOutline + + +class PatchTransitionOutline: + """An outline of what's happening during a transition between two patches. + + This class stores data encoding a floor or ceiling in a 3d topological + spacetime diagram. It encodes the details of time boundaries. + """ + + def __init__( + self, + *, + observable_deltas: dict[str, PathOutline], + data_boundary_planes: Iterable[ClosedCurve], + ): + self.observable_deltas = observable_deltas + self.data_boundary_planes = tuple(data_boundary_planes) + for data_boundary_plane in self.data_boundary_planes: + if data_boundary_plane.basis is None: + raise ValueError(f"Not a uniform basis: {data_boundary_plane=}") + + @staticmethod + def empty() -> "PatchTransitionOutline": + return PatchTransitionOutline(observable_deltas={}, data_boundary_planes=[]) + + def __bool__(self) -> bool: + return bool(self.observable_deltas) or bool(self.data_boundary_planes) + + @functools.cached_property + def patch(self) -> gen.Patch: + tiles = [] + for b, qs in [ + ("X", self.data_x_set), + ("Y", self.data_y_set), + ("Z", self.data_z_set), + ]: + for q in qs: + tiles.append( + gen.Tile(bases=b, measurement_qubit=q, ordered_data_qubits=[q]) + ) + return gen.Patch(tiles) + + def iter_control_points(self) -> Iterable[complex]: + for curve in self.data_boundary_planes: + yield from curve.points + for segment_sets in self.observable_deltas.values(): + for a, b, _ in segment_sets.segments: + yield a + yield b + + @functools.cached_property + def data_basis_map(self) -> dict[complex, str]: + result = {} + for q in self.data_x_set: + result[q] = "X" + for q in self.data_y_set: + result[q] = "Y" + for q in self.data_z_set: + result[q] = "Z" + return result + + @functools.cached_property + def data_set(self) -> frozenset[complex]: + curves = [] + for plane in self.data_boundary_planes: + curves.append(plane.points) + return frozenset(int_points_inside_polygon_set(curves, include_boundary=True)) + + @functools.cached_property + def data_x_set(self) -> frozenset[complex]: + curves = [] + for plane in self.data_boundary_planes: + if plane.basis == "X": + curves.append(plane.points) + return frozenset(int_points_inside_polygon_set(curves, include_boundary=True)) + + @functools.cached_property + def data_y_set(self) -> frozenset[complex]: + curves = [] + for plane in self.data_boundary_planes: + if plane.basis == "Y": + curves.append(plane.points) + return frozenset(int_points_inside_polygon_set(curves, include_boundary=True)) + + @functools.cached_property + def data_z_set(self) -> frozenset[complex]: + curves = [] + for plane in self.data_boundary_planes: + if plane.basis == "Z": + curves.append(plane.points) + return frozenset(int_points_inside_polygon_set(curves, include_boundary=True)) diff --git a/src/gen/_surf/_patch_transition_outline_test.py b/src/gen/_surf/_patch_transition_outline_test.py new file mode 100644 index 0000000..4c15084 --- /dev/null +++ b/src/gen/_surf/_patch_transition_outline_test.py @@ -0,0 +1,25 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from gen._surf._closed_curve import ClosedCurve +from gen._surf._patch_transition_outline import PatchTransitionOutline +from gen._surf._path_outline import PathOutline + + +def test_data_set(): + trans = PatchTransitionOutline( + observable_deltas={1: PathOutline([(0 + 1j, 2 + 1j, "X")])}, + data_boundary_planes=[ClosedCurve.from_cycle(["X", 0, 2, 2 + 2j, 2j])], + ) + assert trans.data_set == {0, 1, 2, 1j, 1j + 1, 1j + 2, 2j, 2j + 1, 2j + 2} diff --git a/src/gen/_surf/_path_outline.py b/src/gen/_surf/_path_outline.py new file mode 100644 index 0000000..b152b39 --- /dev/null +++ b/src/gen/_surf/_path_outline.py @@ -0,0 +1,90 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import functools +from typing import Iterable, Sequence, Literal + +import gen +from gen._surf._geo import int_points_on_line +from gen._core._util import complex_key + + +class PathOutline: + """A series of line segments between integer coordinates.""" + + def __init__(self, segments: Iterable[tuple[complex, complex, Literal["X", "Z"]]]): + canon_segments = [] + for a, c, b in segments: + a, c = sorted([a, c], key=complex_key) + canon_segments.append((a, c, b)) + self.segments = frozenset(canon_segments) + + @staticmethod + def from_stops( + basis: Literal["X", "Z"], + stops: Sequence[complex], + *, + extra: Iterable[complex] = (), + ) -> "PathOutline": + assert len(stops) > 1 + segments = [] + for k in range(len(stops) - 1): + segments.append((stops[k], stops[k + 1], basis)) + for e in extra: + segments.append((e, e, basis)) + return PathOutline(segments) + + def offset_by(self, offset: complex) -> "PathOutline": + return PathOutline((a + offset, b + offset, c) for a, b, c in self.segments) + + def basis(self) -> str | None: + bases = {c for _, _, c in self.segments} + if len(bases) != 1: + return None + return next(iter(bases)) + + def to_pauli_string(self) -> gen.PauliString: + b = self.basis() + assert b is not None + return gen.PauliString({q: b for q in self.int_point_set}) + + @functools.cached_property + def int_point_set(self) -> set[complex]: + return {p for a, b, _ in self.segments for p in int_points_on_line(a, b)} + + @property + def end_point_set(self) -> frozenset[complex]: + end_points = set() + for a, b, _ in self.segments: + end_points ^= {a, b} + return frozenset(end_points) + + @property + def end_point_set_including_elbows(self) -> frozenset[complex]: + end_points = set() + for a, b, _ in self.segments: + end_points.add(a) + end_points.add(b) + return frozenset(end_points) + + def __eq__(self, other): + if not isinstance(other, PathOutline): + return NotImplemented + return self.segments == other.segments + + def __ne__(self, other): + return not (self == other) + + def __repr__(self): + return f"SegmentSet({self.segments!r})" diff --git a/src/gen/_surf/_step_outline.py b/src/gen/_surf/_step_outline.py new file mode 100644 index 0000000..cce7eb2 --- /dev/null +++ b/src/gen/_surf/_step_outline.py @@ -0,0 +1,447 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import functools +from typing import Callable, Any, Iterable + +from gen._core import Builder, AtLayer +from gen._surf._closed_curve import ClosedCurve +from gen._surf._patch_outline import PatchOutline +from gen._surf._patch_transition_outline import PatchTransitionOutline + + +class StepOutline: + def __init__( + self, + *, + start: PatchTransitionOutline | None = None, + body: PatchOutline, + end: PatchTransitionOutline | None = None, + obs_delta_body_start: dict[str, ClosedCurve] | None = None, + obs_delta_body_end: dict[str, ClosedCurve] | None = None, + rounds: int, + ): + self.start: PatchTransitionOutline = ( + start if start is not None else PatchTransitionOutline.empty() + ) + self.body: PatchOutline = body + self.obs_delta_body_start = ( + {} if obs_delta_body_start is None else obs_delta_body_start + ) + self.obs_delta_body_end = ( + {} if obs_delta_body_end is None else obs_delta_body_end + ) + self.end: PatchTransitionOutline = ( + end if end is not None else PatchTransitionOutline.empty() + ) + self.rounds = rounds + assert self.rounds > 0 + + def without_start_transition(self): + return StepOutline( + start=None, + body=self.body, + end=self.end, + obs_delta_body_start=self.obs_delta_body_end, + obs_delta_body_end=self.obs_delta_body_start, + rounds=self.rounds, + ) + + def without_end_transition(self): + return StepOutline( + start=self.start, + body=self.body, + end=None, + obs_delta_body_start=self.obs_delta_body_end, + obs_delta_body_end=self.obs_delta_body_start, + rounds=self.rounds, + ) + + @functools.cached_property + def used_set(self) -> frozenset[complex]: + return self.start.data_set | self.end.data_set | self.body.to_patch().used_set + + def to_magic_init_step(self) -> "MagicInitStep": + return MagicInitStep(self) + + def to_magic_end_step(self) -> "MagicEndStep": + return MagicEndStep(self) + + def build_rounds( + self, + *, + builder: Builder, + rel_order_func: Callable[[complex], Iterable[complex]], + alternate_ordering_with_round_parity: bool, + start_round_index: int, + cmp_layer: Any | None, + save_layer: Any | None, + edit_cur_obs: dict[str, set[complex]], + o2i: dict[str, int | None], + ) -> None: + assert self.rounds > 0 + empty = PatchTransitionOutline.empty() + patch = self.body.to_patch(rel_order_func=rel_order_func) + + def loop_round_key(r: int) -> Any: + return (save_layer, "round", r) + + def fast_forward_record( + *, rec_offset: int, old_round_key: Any, new_round_key: Any + ): + builder.tracker.next_measurement_index += rec_offset + for m in patch.measure_set: + builder.tracker.recorded[AtLayer(m, new_round_key)] = [ + e + rec_offset + for e in builder.tracker.recorded[AtLayer(m, old_round_key)] + ] + + round_builders = [] + round_index = start_round_index + end_round_index = start_round_index + self.rounds + while round_index < end_round_index: + round_save_layer = loop_round_key(round_index) + round_builders.append(builder.fork()) + bd: list[tuple[str, ClosedCurve]] = [] + if round_index == start_round_index: + bd.extend(self.obs_delta_body_start.items()) + if round_index == end_round_index - 1: + bd.extend(self.obs_delta_body_end.items()) + _css_surface_code_round( + builder=round_builders[-1], + edit_cur_obs=edit_cur_obs, + start_outline=self.start if round_index == start_round_index else empty, + end_outline=self.end if round_index == end_round_index - 1 else empty, + observable_stabilizer_deltas=bd, + patch_outline=self.body, + save_layer=round_save_layer, + cmp_layer=cmp_layer + if round_index == start_round_index + else loop_round_key(round_index - 1), + rel_order_func=rel_order_func, + reverse_order=alternate_ordering_with_round_parity + and round_index % 2 == 1, + o2i=o2i, + ) + + round_index += 1 + + # Use repeat blocks when the circuit starts repeating. + bulk_rounds_left = ( + end_round_index + - round_index + - bool(self.end or self.obs_delta_body_end) + ) + if bulk_rounds_left > 0: + if ( + alternate_ordering_with_round_parity + and bulk_rounds_left % 2 == 0 + and len(round_builders) >= 4 + and round_builders[-3].circuit == round_builders[-1].circuit + and round_builders[-4].circuit == round_builders[-2].circuit + ): + round_builders.pop() + round_builders.pop() + reversed_half = round_builders.pop() + round_builders[-1].circuit += reversed_half.circuit + m = round_builders[-1].circuit.num_measurements + double_rounds_to_run = bulk_rounds_left // 2 + round_builders[-1].circuit *= double_rounds_to_run + 2 + round_index += double_rounds_to_run * 2 + fast_forward_record( + rec_offset=m * (double_rounds_to_run - 1), + new_round_key=loop_round_key(round_index - 1), + old_round_key=round_save_layer, + ) + elif ( + not alternate_ordering_with_round_parity + and len(round_builders) >= 2 + and round_builders[-1].circuit == round_builders[-2].circuit + ): + round_builders.pop() + rounds_to_run = bulk_rounds_left + m = round_builders[-1].circuit.num_measurements + round_builders[-1].circuit *= rounds_to_run + 2 + round_index += rounds_to_run + fast_forward_record( + rec_offset=m * rounds_to_run, + new_round_key=loop_round_key(round_index - 1), + old_round_key=round_save_layer, + ) + + for sub_builder in round_builders: + builder.circuit += sub_builder.circuit + + # Expose last round tracker info as overall saved tracker info + round_save_layer = loop_round_key(end_round_index - 1) + for q in self.end.data_set | patch.measure_set: + builder.tracker.recorded[AtLayer(q, save_layer)] = builder.tracker.recorded[ + AtLayer(q, round_save_layer) + ] + + +def _css_surface_code_round( + *, + builder: Builder, + o2i: dict[str, int | None], + edit_cur_obs: dict[str, set[complex]], + start_outline: PatchTransitionOutline, + end_outline: PatchTransitionOutline, + observable_stabilizer_deltas: Iterable[tuple[str, ClosedCurve]], + patch_outline: PatchOutline, + rel_order_func: Callable[[complex], Iterable[complex]], + reverse_order: bool, + save_layer: Any, + cmp_layer: Any | None, +) -> None: + patch = patch_outline.to_patch(rel_order_func=rel_order_func) + x_tiles = [tile for tile in patch.tiles if tile.basis == "X"] + z_tiles = [tile for tile in patch.tiles if tile.basis == "Z"] + if len(x_tiles) + len(z_tiles) != len(patch.tiles): + raise NotImplementedError(f"Non-CSS {patch.tiles=}") + + # Reset moment. + reset_bases = { + "X": {tile.measurement_qubit for tile in x_tiles} | start_outline.data_x_set, + "Z": {tile.measurement_qubit for tile in z_tiles} | start_outline.data_z_set, + } + for basis, qs in reset_bases.items(): + if qs: + builder.gate(f"R{basis}", qs) + builder.tick() + + # CX moments. + (num_layers,) = {len(e.ordered_data_qubits) for e in patch.tiles} + for k in range(num_layers)[:: -1 if reverse_order else +1]: + pairs = [] + for tile in patch.tiles: + q = tile.ordered_data_qubits[k] + if q is not None: + pair = (tile.measurement_qubit, q) + if tile.basis == "Z": + pair = pair[::-1] + pairs.append(pair) + builder.gate2("CX", pairs) + builder.tick() + + # Measure moment. + measure_bases = { + "X": {tile.measurement_qubit for tile in x_tiles} | end_outline.data_x_set, + "Z": {tile.measurement_qubit for tile in z_tiles} | end_outline.data_z_set, + } + tmp_save_layer = ("raw", save_layer) + for basis, qs in measure_bases.items(): + if qs: + builder.measure( + qs, + basis=basis, + save_layer=tmp_save_layer, + ) + + # Compare to resets and/or previous round. + for tile in patch.tiles: + comm = start_outline.data_x_set + anti = start_outline.data_z_set + if tile.basis == "Z": + comm, anti = anti, comm + if not tile.data_set.isdisjoint(anti): + continue + keys = [AtLayer(tile.measurement_qubit, tmp_save_layer)] + if not (tile.data_set <= comm): + if cmp_layer is None: + # No comparison available. + continue + prev_key = AtLayer(tile.measurement_qubit, cmp_layer) + keys.append(prev_key) + if prev_key not in builder.tracker.recorded: + continue + builder.detector(keys, pos=tile.measurement_qubit) + + # Handle data measurements. + for tile in patch.tiles: + comm = end_outline.data_x_set + anti = end_outline.data_z_set + if tile.basis == "Z": + comm, anti = anti, comm + save_key = AtLayer(tile.measurement_qubit, save_layer) + + if not tile.data_set.isdisjoint(anti): + # Stabilizer lost due to measurements. + builder.tracker.record_obstacle(save_key) + elif tile.data_set <= comm: + # Stabilizer finalized by measurements. + builder.detector( + [AtLayer(q, tmp_save_layer) for q in tile.used_set], + pos=tile.measurement_qubit, + t=0.5, + ) + builder.tracker.record_obstacle(save_key) + else: + # All or part of stabilizer survived measurements. + builder.tracker.make_measurement_group( + [AtLayer(tile.measurement_qubit, tmp_save_layer)] + + [AtLayer(q, tmp_save_layer) for q in tile.data_set if q in comm], + key=save_key, + ) + for q in end_outline.data_set: + builder.tracker.recorded[AtLayer(q, save_layer)] = builder.tracker.recorded[ + AtLayer(q, tmp_save_layer) + ] + + # Apply observable deltas. + for obs_name, delta in start_outline.observable_deltas.items(): + obs_index = o2i[obs_name] + if obs_index is None: + continue + pts = delta.int_point_set + assert pts <= start_outline.data_set, (obs_name, pts, start_outline.data_set) + assert pts.isdisjoint(edit_cur_obs[obs_name]) + edit_cur_obs[obs_name] ^= pts + for obs_name, delta in observable_stabilizer_deltas: + obs_index = o2i[obs_name] + if obs_index is None: + continue + pts = delta.interior_set(include_boundary=True) + b = delta.basis + assert b is not None + ms = { + tile.measurement_qubit + for tile in patch.tiles + if tile.basis == b and tile.data_set <= pts + } + for pt in ms: + edit_cur_obs[obs_name] ^= patch.m2tile[pt].data_set + builder.obs_include( + [AtLayer(m, tmp_save_layer) for m in ms], obs_index=obs_index + ) + for obs_name, delta in end_outline.observable_deltas.items(): + obs_index = o2i[obs_name] + if obs_index is None: + continue + pts = delta.int_point_set + assert pts <= end_outline.data_x_set | end_outline.data_z_set + assert pts <= edit_cur_obs[obs_name] + edit_cur_obs[obs_name] ^= pts + builder.obs_include( + [AtLayer(q, tmp_save_layer) for q in pts], obs_index=obs_index + ) + + builder.shift_coords(dt=1) + builder.tick() + + +class MagicInitStep: + def __init__(self, step: StepOutline): + self.step = step + + @property + def rounds(self) -> int: + return self.step.rounds + + def build_rounds( + self, + *, + builder: Builder, + rel_order_func: Callable[[complex], Iterable[complex]], + alternate_ordering_with_round_parity: bool, + start_round_index: int, + cmp_layer: Any | None, + save_layer: Any | None, + edit_cur_obs: dict[str, set[complex]], + o2i: dict[str, int | None], + ) -> None: + builder.gate("DEPOLARIZE1", builder.q2i.keys(), 0.75) + builder.tick() + patch = self.step.body.to_patch() + for tile in patch.tiles: + builder.measure_pauli_product( + tile.to_data_pauli_string(), + key=AtLayer(tile.measurement_qubit, save_layer), + ) + for obs_name, delta in self.step.start.observable_deltas.items(): + obs_index = o2i[obs_name] + if obs_index is None: + continue + builder.measure_pauli_product( + delta.to_pauli_string(), + key=AtLayer(obs_name, save_layer), + ) + assert not edit_cur_obs[obs_name] + edit_cur_obs[obs_name] ^= delta.int_point_set + for obs_name, delta in self.step.start.observable_deltas.items(): + obs_index = o2i[obs_name] + if obs_index is None: + continue + builder.obs_include([AtLayer(obs_name, save_layer)], obs_index=obs_index) + builder.shift_coords(dt=1) + builder.tick() + + +class MagicEndStep: + def __init__(self, step: StepOutline): + self.step = step + + @property + def rounds(self) -> int: + return self.step.rounds + + def build_rounds( + self, + *, + builder: Builder, + rel_order_func: Callable[[complex], Iterable[complex]], + alternate_ordering_with_round_parity: bool, + start_round_index: int, + cmp_layer: Any | None, + save_layer: Any | None, + edit_cur_obs: dict[str, set[complex]], + o2i: dict[str, int | None], + ) -> None: + patch = self.step.body.to_patch() + for tile in patch.tiles: + builder.measure_pauli_product( + tile.to_data_pauli_string(), + key=AtLayer(tile.measurement_qubit, save_layer), + ) + for obs_name, delta in self.step.end.observable_deltas.items(): + obs_index = o2i[obs_name] + if obs_index is None: + continue + builder.measure_pauli_product( + delta.to_pauli_string(), + key=AtLayer(obs_name, save_layer), + ) + assert edit_cur_obs[obs_name] == delta.int_point_set, ( + obs_name, + edit_cur_obs[obs_name], + delta.int_point_set, + ) + edit_cur_obs[obs_name].clear() + + for tile in patch.tiles: + builder.detector( + [ + AtLayer(tile.measurement_qubit, cmp_layer), + AtLayer(tile.measurement_qubit, save_layer), + ], + pos=tile.measurement_qubit, + ) + for obs_name, delta in self.step.end.observable_deltas.items(): + obs_index = o2i[obs_name] + if obs_index is None: + continue + builder.obs_include([AtLayer(obs_name, save_layer)], obs_index=obs_index) + builder.shift_coords(dt=1) + builder.tick() + builder.gate("DEPOLARIZE1", builder.q2i.keys(), 0.75) diff --git a/src/gen/_surf/_step_outline_test.py b/src/gen/_surf/_step_outline_test.py new file mode 100644 index 0000000..5a9a016 --- /dev/null +++ b/src/gen/_surf/_step_outline_test.py @@ -0,0 +1,379 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +import gen + + +def test_step_outline_simple(): + rel_order_func = ( + lambda m: gen.Order_Z if gen.checkerboard_basis(m) == "Z" else gen.Order_ᴎ + ) + step = gen.StepOutline( + start=gen.PatchTransitionOutline( + observable_deltas={}, + data_boundary_planes=[ + gen.ClosedCurve.from_cycle( + [ + "Z", + 0, + 2, + 2 + 2j, + 2j, + ] + ) + ], + ), + body=gen.PatchOutline( + [ + gen.ClosedCurve.from_cycle( + [ + 0, + "X", + 2, + "Z", + 2 + 2j, + "X", + 2j, + "Z", + ] + ) + ] + ), + end=gen.PatchTransitionOutline( + observable_deltas={}, + data_boundary_planes=[ + gen.ClosedCurve.from_cycle( + [ + "X", + 0, + 2, + 2 + 2j, + 2j, + ] + ) + ], + ), + rounds=25, + ) + builder = gen.Builder.for_qubits( + step.body.to_patch(rel_order_func=rel_order_func).used_set + ) + step.build_rounds( + builder=builder, + rel_order_func=rel_order_func, + alternate_ordering_with_round_parity=False, + start_round_index=5, + cmp_layer=None, + save_layer="test", + edit_cur_obs={}, + o2i={}, + ) + assert builder.circuit == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + QUBIT_COORDS(0, 1) 1 + QUBIT_COORDS(0, 2) 2 + QUBIT_COORDS(1, 0) 3 + QUBIT_COORDS(1, 1) 4 + QUBIT_COORDS(1, 2) 5 + QUBIT_COORDS(2, 0) 6 + QUBIT_COORDS(2, 1) 7 + QUBIT_COORDS(2, 2) 8 + QUBIT_COORDS(-0.5, 1.5) 9 + QUBIT_COORDS(0.5, -0.5) 10 + QUBIT_COORDS(0.5, 0.5) 11 + QUBIT_COORDS(0.5, 1.5) 12 + QUBIT_COORDS(1.5, 0.5) 13 + QUBIT_COORDS(1.5, 1.5) 14 + QUBIT_COORDS(1.5, 2.5) 15 + QUBIT_COORDS(2.5, 0.5) 16 + RX 10 12 13 15 + R 0 1 2 3 4 5 6 7 8 9 11 14 16 + TICK + CX 0 11 4 14 6 16 12 1 13 3 15 5 + TICK + CX 1 9 3 11 7 14 10 0 12 2 13 4 + TICK + CX 1 11 5 14 7 16 12 4 13 6 15 8 + TICK + CX 2 9 4 11 8 14 10 3 12 5 13 7 + TICK + MX 10 12 13 15 + M 9 11 14 16 + DETECTOR(-0.5, 1.5, 0) rec[-4] + DETECTOR(0.5, 0.5, 0) rec[-3] + DETECTOR(1.5, 1.5, 0) rec[-2] + DETECTOR(2.5, 0.5, 0) rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + REPEAT 23 { + RX 10 12 13 15 + R 9 11 14 16 + TICK + CX 0 11 4 14 6 16 12 1 13 3 15 5 + TICK + CX 1 9 3 11 7 14 10 0 12 2 13 4 + TICK + CX 1 11 5 14 7 16 12 4 13 6 15 8 + TICK + CX 2 9 4 11 8 14 10 3 12 5 13 7 + TICK + MX 10 12 13 15 + M 9 11 14 16 + DETECTOR(-0.5, 1.5, 0) rec[-12] rec[-4] + DETECTOR(0.5, -0.5, 0) rec[-16] rec[-8] + DETECTOR(0.5, 0.5, 0) rec[-11] rec[-3] + DETECTOR(0.5, 1.5, 0) rec[-15] rec[-7] + DETECTOR(1.5, 0.5, 0) rec[-14] rec[-6] + DETECTOR(1.5, 1.5, 0) rec[-10] rec[-2] + DETECTOR(1.5, 2.5, 0) rec[-13] rec[-5] + DETECTOR(2.5, 0.5, 0) rec[-9] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + } + RX 10 12 13 15 + R 9 11 14 16 + TICK + CX 0 11 4 14 6 16 12 1 13 3 15 5 + TICK + CX 1 9 3 11 7 14 10 0 12 2 13 4 + TICK + CX 1 11 5 14 7 16 12 4 13 6 15 8 + TICK + CX 2 9 4 11 8 14 10 3 12 5 13 7 + TICK + MX 0 1 2 3 4 5 6 7 8 10 12 13 15 + M 9 11 14 16 + DETECTOR(-0.5, 1.5, 0) rec[-21] rec[-4] + DETECTOR(0.5, -0.5, 0) rec[-25] rec[-8] + DETECTOR(0.5, 0.5, 0) rec[-20] rec[-3] + DETECTOR(0.5, 1.5, 0) rec[-24] rec[-7] + DETECTOR(1.5, 0.5, 0) rec[-23] rec[-6] + DETECTOR(1.5, 1.5, 0) rec[-19] rec[-2] + DETECTOR(1.5, 2.5, 0) rec[-22] rec[-5] + DETECTOR(2.5, 0.5, 0) rec[-18] rec[-1] + DETECTOR(0.5, -0.5, 0.5) rec[-17] rec[-14] rec[-8] + DETECTOR(0.5, 1.5, 0.5) rec[-16] rec[-15] rec[-13] rec[-12] rec[-7] + DETECTOR(1.5, 0.5, 0.5) rec[-14] rec[-13] rec[-11] rec[-10] rec[-6] + DETECTOR(1.5, 2.5, 0.5) rec[-12] rec[-9] rec[-5] + SHIFT_COORDS(0, 0, 1) + TICK + """ + ) + + +def test_step_outline_alternating(): + rel_order_func = ( + lambda m: gen.Order_Z if gen.checkerboard_basis(m) == "Z" else gen.Order_ᴎ + ) + step = gen.StepOutline( + start=gen.PatchTransitionOutline( + observable_deltas={}, + data_boundary_planes=[ + gen.ClosedCurve.from_cycle( + [ + "Z", + 0, + 2, + 2 + 2j, + 2j, + ] + ) + ], + ), + body=gen.PatchOutline( + [ + gen.ClosedCurve.from_cycle( + [ + 0, + "X", + 2, + "Z", + 2 + 2j, + "X", + 2j, + "Z", + ] + ) + ] + ), + end=gen.PatchTransitionOutline( + observable_deltas={}, + data_boundary_planes=[ + gen.ClosedCurve.from_cycle( + [ + "X", + 0, + 2, + 2 + 2j, + 2j, + ] + ) + ], + ), + rounds=25, + ) + builder = gen.Builder.for_qubits( + step.body.to_patch(rel_order_func=rel_order_func).used_set + ) + step.build_rounds( + builder=builder, + rel_order_func=rel_order_func, + alternate_ordering_with_round_parity=True, + start_round_index=5, + cmp_layer=None, + save_layer="test", + edit_cur_obs={}, + o2i={}, + ) + assert builder.circuit == stim.Circuit( + """ + QUBIT_COORDS(0, 0) 0 + QUBIT_COORDS(0, 1) 1 + QUBIT_COORDS(0, 2) 2 + QUBIT_COORDS(1, 0) 3 + QUBIT_COORDS(1, 1) 4 + QUBIT_COORDS(1, 2) 5 + QUBIT_COORDS(2, 0) 6 + QUBIT_COORDS(2, 1) 7 + QUBIT_COORDS(2, 2) 8 + QUBIT_COORDS(-0.5, 1.5) 9 + QUBIT_COORDS(0.5, -0.5) 10 + QUBIT_COORDS(0.5, 0.5) 11 + QUBIT_COORDS(0.5, 1.5) 12 + QUBIT_COORDS(1.5, 0.5) 13 + QUBIT_COORDS(1.5, 1.5) 14 + QUBIT_COORDS(1.5, 2.5) 15 + QUBIT_COORDS(2.5, 0.5) 16 + RX 10 12 13 15 + R 0 1 2 3 4 5 6 7 8 9 11 14 16 + TICK + CX 2 9 4 11 8 14 10 3 12 5 13 7 + TICK + CX 1 11 5 14 7 16 12 4 13 6 15 8 + TICK + CX 1 9 3 11 7 14 10 0 12 2 13 4 + TICK + CX 0 11 4 14 6 16 12 1 13 3 15 5 + TICK + MX 10 12 13 15 + M 9 11 14 16 + DETECTOR(-0.5, 1.5, 0) rec[-4] + DETECTOR(0.5, 0.5, 0) rec[-3] + DETECTOR(1.5, 1.5, 0) rec[-2] + DETECTOR(2.5, 0.5, 0) rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + RX 10 12 13 15 + R 9 11 14 16 + TICK + CX 0 11 4 14 6 16 12 1 13 3 15 5 + TICK + CX 1 9 3 11 7 14 10 0 12 2 13 4 + TICK + CX 1 11 5 14 7 16 12 4 13 6 15 8 + TICK + CX 2 9 4 11 8 14 10 3 12 5 13 7 + TICK + MX 10 12 13 15 + M 9 11 14 16 + DETECTOR(-0.5, 1.5, 0) rec[-12] rec[-4] + DETECTOR(0.5, -0.5, 0) rec[-16] rec[-8] + DETECTOR(0.5, 0.5, 0) rec[-11] rec[-3] + DETECTOR(0.5, 1.5, 0) rec[-15] rec[-7] + DETECTOR(1.5, 0.5, 0) rec[-14] rec[-6] + DETECTOR(1.5, 1.5, 0) rec[-10] rec[-2] + DETECTOR(1.5, 2.5, 0) rec[-13] rec[-5] + DETECTOR(2.5, 0.5, 0) rec[-9] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + REPEAT 11 { + RX 10 12 13 15 + R 9 11 14 16 + TICK + CX 2 9 4 11 8 14 10 3 12 5 13 7 + TICK + CX 1 11 5 14 7 16 12 4 13 6 15 8 + TICK + CX 1 9 3 11 7 14 10 0 12 2 13 4 + TICK + CX 0 11 4 14 6 16 12 1 13 3 15 5 + TICK + MX 10 12 13 15 + M 9 11 14 16 + DETECTOR(-0.5, 1.5, 0) rec[-12] rec[-4] + DETECTOR(0.5, -0.5, 0) rec[-16] rec[-8] + DETECTOR(0.5, 0.5, 0) rec[-11] rec[-3] + DETECTOR(0.5, 1.5, 0) rec[-15] rec[-7] + DETECTOR(1.5, 0.5, 0) rec[-14] rec[-6] + DETECTOR(1.5, 1.5, 0) rec[-10] rec[-2] + DETECTOR(1.5, 2.5, 0) rec[-13] rec[-5] + DETECTOR(2.5, 0.5, 0) rec[-9] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + RX 10 12 13 15 + R 9 11 14 16 + TICK + CX 0 11 4 14 6 16 12 1 13 3 15 5 + TICK + CX 1 9 3 11 7 14 10 0 12 2 13 4 + TICK + CX 1 11 5 14 7 16 12 4 13 6 15 8 + TICK + CX 2 9 4 11 8 14 10 3 12 5 13 7 + TICK + MX 10 12 13 15 + M 9 11 14 16 + DETECTOR(-0.5, 1.5, 0) rec[-12] rec[-4] + DETECTOR(0.5, -0.5, 0) rec[-16] rec[-8] + DETECTOR(0.5, 0.5, 0) rec[-11] rec[-3] + DETECTOR(0.5, 1.5, 0) rec[-15] rec[-7] + DETECTOR(1.5, 0.5, 0) rec[-14] rec[-6] + DETECTOR(1.5, 1.5, 0) rec[-10] rec[-2] + DETECTOR(1.5, 2.5, 0) rec[-13] rec[-5] + DETECTOR(2.5, 0.5, 0) rec[-9] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK + } + RX 10 12 13 15 + R 9 11 14 16 + TICK + CX 2 9 4 11 8 14 10 3 12 5 13 7 + TICK + CX 1 11 5 14 7 16 12 4 13 6 15 8 + TICK + CX 1 9 3 11 7 14 10 0 12 2 13 4 + TICK + CX 0 11 4 14 6 16 12 1 13 3 15 5 + TICK + MX 0 1 2 3 4 5 6 7 8 10 12 13 15 + M 9 11 14 16 + DETECTOR(-0.5, 1.5, 0) rec[-21] rec[-4] + DETECTOR(0.5, -0.5, 0) rec[-25] rec[-8] + DETECTOR(0.5, 0.5, 0) rec[-20] rec[-3] + DETECTOR(0.5, 1.5, 0) rec[-24] rec[-7] + DETECTOR(1.5, 0.5, 0) rec[-23] rec[-6] + DETECTOR(1.5, 1.5, 0) rec[-19] rec[-2] + DETECTOR(1.5, 2.5, 0) rec[-22] rec[-5] + DETECTOR(2.5, 0.5, 0) rec[-18] rec[-1] + DETECTOR(0.5, -0.5, 0.5) rec[-17] rec[-14] rec[-8] + DETECTOR(0.5, 1.5, 0.5) rec[-16] rec[-15] rec[-13] rec[-12] rec[-7] + DETECTOR(1.5, 0.5, 0.5) rec[-14] rec[-13] rec[-11] rec[-10] rec[-6] + DETECTOR(1.5, 2.5, 0.5) rec[-12] rec[-9] rec[-5] + SHIFT_COORDS(0, 0, 1) + TICK + """ + ) diff --git a/src/gen/_surf/_step_sequence_outline.py b/src/gen/_surf/_step_sequence_outline.py new file mode 100644 index 0000000..7276a83 --- /dev/null +++ b/src/gen/_surf/_step_sequence_outline.py @@ -0,0 +1,123 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pathlib +from typing import Union, Optional, Callable, Any, Iterable, Tuple + +import stim + +import gen +from gen._core import Builder, AtLayer +from gen._surf._closed_curve import ClosedCurve +from gen._surf._order import Order_Z +from gen._surf._patch_outline import PatchOutline +from gen._surf._patch_transition_outline import PatchTransitionOutline +from gen._surf._step_outline import StepOutline +from gen._util import write_file + + +class StepSequenceOutline: + def __init__(self, steps: Iterable[StepOutline]): + self.steps = list(steps) + + def to_circuit( + self, *, rel_order_func: Callable[[complex], Iterable[complex]] + ) -> stim.Circuit: + builder = Builder.for_qubits(...) + + round_index = 0 + cmp_layer = None + save_layer = 0 + for step in self.steps: + step.build_rounds( + builder=builder, + rel_order_func=rel_order_func, + alternate_ordering_with_round_parity=True, + start_round_index=round_index, + edit_cur_obs=None, + o2i=None, + cmp_layer=cmp_layer, + save_layer=("step_to_circuit", save_layer), + ) + cmp_layer = save_layer + round_index += step.rounds + + return builder.circuit + + def write_outlines_svg(self, path: str | pathlib.Path) -> None: + from gen._surf._viz_patch_outline_svg import patch_outline_svg_viewer + + viewer = patch_outline_svg_viewer( + [ + piece + for segment in self.steps + for piece in [segment.start, segment.body, segment.end] + if any(piece.iter_control_points()) + ] + ) + write_file(path, viewer) + + def write_patches_svg( + self, + path: str | pathlib.Path, + *, + rel_order_func: Callable[[complex], Iterable[complex]] = None, + ) -> None: + from gen._viz_patch_svg import patch_svg_viewer + + show_order = True + if rel_order_func is None: + rel_order_func = lambda _: Order_Z + show_order = False + patches = [] + for k in range(len(self.steps)): + segment = self.steps[k] + patch = segment.body.to_patch(rel_order_func=rel_order_func) + if segment.start.data_set: + b2 = segment.start.data_basis_map + tiles = list(segment.start.patch.tiles) + for t in patch.tiles: + if all( + b2.get(q, b) == b + for q, b in t.to_data_pauli_string().qubits.items() + ): + tiles.append(t) + patches.append(gen.Patch(tiles)) + patches.append(patch) + if segment.end.data_set: + b2 = segment.end.data_basis_map + tiles = list(segment.end.patch.tiles) + for t in patch.tiles: + if all( + b2.get(q, b) == b + for q, b in t.to_data_pauli_string().qubits.items() + ): + tiles.append(t) + patches.append(gen.Patch(tiles)) + viewer = patch_svg_viewer( + patches, show_order=show_order, show_measure_qubits=False + ) + write_file(path, viewer) + + def write_gltf(self, path: str | pathlib.Path) -> None: + from gen._surf._viz_sequence_3d import patch_sequence_to_model + + print(f"wrote file://{pathlib.Path(path).absolute()}") + patch_sequence_to_model(self).save_json(str(path)) + + def write_3d_viewer_html(self, path: str | pathlib.Path) -> None: + from gen._surf._viz_gltf_3d import viz_3d_gltf_model_html + from gen._surf._viz_sequence_3d import patch_sequence_to_model + + write_file(path, viz_3d_gltf_model_html(patch_sequence_to_model(self))) diff --git a/src/gen/_surf/_surface_code.py b/src/gen/_surf/_surface_code.py new file mode 100644 index 0000000..11b62bd --- /dev/null +++ b/src/gen/_surf/_surface_code.py @@ -0,0 +1,350 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import AbstractSet, Callable, Any, Literal + +from gen._core._builder import Builder, AtLayer +from gen._core._patch import Patch +from gen._core._tile import Tile +from gen._core._util import sorted_complex +from gen._surf._closed_curve import ClosedCurve +from gen._surf._patch_outline import PatchOutline +from gen._surf._surface_code_legacy import measure_patch_legacy + + +def surface_code_patch( + *, + width: int, + height: int, + top_basis: Literal["X", "Z"], + bot_basis: Literal["X", "Z"], + left_basis: Literal["X", "Z"], + right_basis: Literal["X", "Z"], + rel_order_func: Callable[[complex], tuple[complex, ...]], +) -> Patch: + """Generates the stabilizer configuration for a surface code patch.""" + + c = ClosedCurve.from_cycle( + [ + top_basis, + width - 1, + right_basis, + width + height * 1j - 1 - 1j, + bot_basis, + height * 1j - 1j, + left_basis, + 0, + ] + ) + return PatchOutline([c]).to_patch(rel_order_func=rel_order_func) + + +def layer_loop( + *, + builder: Builder, + patch: Patch, + style: Literal["css", "mpp", "cz"], + compare_layer: Any, + save_layer: Any, + repetitions: int, + mark_as_post_selected: Callable[[AtLayer], bool] = lambda _: False, +) -> None: + if repetitions == 0: + for tile in patch.tiles: + m = tile.measurement_qubit + builder.tracker.make_measurement_group( + [AtLayer(m, compare_layer)], key=AtLayer(m, save_layer) + ) + return + + measure_index_before_first_iteration = builder.tracker.next_measurement_index + loop_start_layer = ("loop_start", save_layer) + + # Perform first iteration of loop. + child = builder.fork() + measure_patch_legacy( + builder=child, + patch=patch, + save_layer=loop_start_layer, + style=style, + ) + for tile in patch.tiles: + m = tile.measurement_qubit + child.detector( + [AtLayer(m, compare_layer), AtLayer(m, loop_start_layer)], + pos=m, + mark_as_post_selected=mark_as_post_selected(AtLayer(m, save_layer)), + ) + child.circuit.append("SHIFT_COORDS", [], [0, 0, 1]) + child.tick() + + # Update tracker to contain last iteration information at desired save index. + num_measurements_in_loop = ( + builder.tracker.next_measurement_index - measure_index_before_first_iteration + ) + first_to_last_offset = num_measurements_in_loop * (repetitions - 1) + for tile in patch.tiles: + m = tile.measurement_qubit + (start,) = builder.tracker.recorded[AtLayer(m, loop_start_layer)] + builder.tracker.recorded[AtLayer(m, save_layer)] = [ + start + first_to_last_offset + ] + builder.tracker.next_measurement_index += first_to_last_offset + + # Append loop body to circuit. + builder.circuit += child.circuit * repetitions + + +def layer_single_shot( + *, + builder: Builder, + patch: Patch, + style: Literal["cz", "css", "mpp"], + data_basis: str | Callable[[complex], str], + data_obs_qubit_sets: dict[int, AbstractSet[complex]] | None = None, +) -> None: + if isinstance(data_basis, str): + fixed_data_basis = data_basis + data_basis = lambda _: fixed_data_basis + dq = {q: data_basis(q) for q in patch.data_set} + measure_patch_legacy( + patch=patch, + style=style, + builder=builder, + data_resets=dq, + data_measures=dq, + save_layer="single", + ) + + def matches_basis(t: Tile) -> bool: + for b, d in zip(t.bases, t.ordered_data_qubits): + if d is not None and b != data_basis(d): + return False + return True + + for tile in patch.tiles: + if matches_basis(tile): + builder.detector( + [ + AtLayer(tile.measurement_qubit, "single"), + ], + pos=tile.measurement_qubit, + ) + for tile in patch.tiles: + if matches_basis(tile): + builder.detector( + [AtLayer(q, "single") for q in tile.used_set], + pos=tile.measurement_qubit, + t=0.5, + ) + for index, obs_qubits in data_obs_qubit_sets.items(): + builder.obs_include([AtLayer(q, "single") for q in obs_qubits], obs_index=index) + + +def layer_begin( + *, + builder: Builder, + style: Literal["cz", "css", "mpp"], + patch: Patch, + save_layer: Any, + obs_key_sets: dict[int, AbstractSet[complex]] | None = None, + reset_basis: str | Callable[[complex], str], + mark_as_post_selected: Callable[[AtLayer], bool] = lambda _: False, +) -> None: + layer_transition( + builder=builder, + style=style, + kept_data_qubits=set(), + past_patch=None, + past_save_layer=None, + past_compare_layer=None, + past_layer_lost_data_measure_basis=None, + past_layer_lost_data_obs_qubit_sets=None, + future_patch=patch, + future_save_layer=save_layer, + future_layer_obs_key_sets=obs_key_sets, + future_layer_gain_data_reset_basis=reset_basis, + mark_as_post_selected=mark_as_post_selected, + ) + + +def layer_end( + *, + builder: Builder, + style: Literal["cz", "css", "mpp"], + patch: Patch, + save_layer: Any, + compare_layer: Any, + data_measure_basis: str | Callable[[complex], str], + data_obs_qubit_sets: dict[int, AbstractSet[complex]] | None = None, + mark_as_post_selected: Callable[[AtLayer], bool] = lambda _: False, +) -> None: + layer_transition( + builder=builder, + style=style, + kept_data_qubits=set(), + past_patch=patch, + past_save_layer=save_layer, + past_compare_layer=compare_layer, + past_layer_lost_data_measure_basis=data_measure_basis, + past_layer_lost_data_obs_qubit_sets=data_obs_qubit_sets, + future_patch=None, + future_save_layer=None, + future_layer_obs_key_sets=None, + future_layer_gain_data_reset_basis=None, + mark_as_post_selected=mark_as_post_selected, + ) + + +def layer_transition( + *, + builder: Builder, + style: Literal["css", "mpp"], + kept_data_qubits: set[complex] | frozenset[complex], + past_patch: Patch | None, + past_save_layer: Any | None, + past_compare_layer: Any | None, + past_layer_lost_data_measure_basis: None | str | Callable[[complex], str], + past_layer_lost_data_obs_qubit_sets: dict[int, AbstractSet[complex]] | None = None, + future_patch: Patch | None, + future_save_layer: Any | None, + future_layer_obs_key_sets: dict[int, AbstractSet[complex]] | None = None, + future_layer_gain_data_reset_basis: None | str | Callable[[complex], str], + mark_as_post_selected: Callable[[AtLayer], bool] = lambda _: False, +) -> None: + assert future_patch is not None or past_patch is not None + assert ( + (future_save_layer is None) + == (future_patch is None) + == (future_layer_gain_data_reset_basis is None) + ) + assert ( + (past_save_layer is None) + == (past_patch is None) + == (past_compare_layer is None) + == (past_layer_lost_data_measure_basis is None) + ) + if future_patch is None: + future_patch = Patch([]) + if past_patch is None: + past_patch = Patch([]) + if isinstance(past_layer_lost_data_measure_basis, str): + fixed_future_time_basis = past_layer_lost_data_measure_basis + past_layer_lost_data_measure_basis = lambda _: fixed_future_time_basis + if isinstance(future_layer_gain_data_reset_basis, str): + fixed_past_time_basis = future_layer_gain_data_reset_basis + future_layer_gain_data_reset_basis = lambda _: fixed_past_time_basis + + assert kept_data_qubits <= past_patch.data_set + assert kept_data_qubits <= future_patch.data_set, repr( + sorted_complex(kept_data_qubits - future_patch.data_set) + ) + lost_data = past_patch.data_set - kept_data_qubits + gained_data = future_patch.data_set - kept_data_qubits + + def matches_past_basis(tile: Tile) -> bool: + for b, d in zip(tile.bases, tile.ordered_data_qubits): + if ( + d is not None + and d in gained_data + and b != future_layer_gain_data_reset_basis(d) + ): + return False + return True + + def matches_future_basis(tile: Tile) -> bool: + for b, d in zip(tile.bases, tile.ordered_data_qubits): + if ( + d is not None + and d in lost_data + and b != past_layer_lost_data_measure_basis(d) + ): + return False + return True + + if past_patch.tiles: + measure_patch_legacy( + style=style, + patch=past_patch, + builder=builder, + data_measures={q: past_layer_lost_data_measure_basis(q) for q in lost_data}, + save_layer=past_save_layer, + ) + for prev_tile in past_patch.tiles: + m = prev_tile.measurement_qubit + builder.detector( + [AtLayer(m, past_compare_layer), AtLayer(m, past_save_layer)], + pos=m, + mark_as_post_selected=mark_as_post_selected( + AtLayer(m, past_save_layer) + ), + ) + for prev_tile in past_patch.tiles: + m = prev_tile.measurement_qubit + if matches_future_basis(prev_tile) and prev_tile.data_set.isdisjoint( + kept_data_qubits + ): + builder.detector( + [AtLayer(q, past_save_layer) for q in prev_tile.used_set], + pos=m, + t=0.5, + ) + if past_layer_lost_data_obs_qubit_sets: + for obs_index, obs_qubits in past_layer_lost_data_obs_qubit_sets.items(): + builder.obs_include( + [AtLayer(q, past_save_layer) for q in lost_data & obs_qubits], + obs_index=obs_index, + ) + builder.shift_coords(dt=1) + builder.tick() + + if future_patch.tiles: + measure_patch_legacy( + patch=future_patch, + style=style, + builder=builder, + data_resets={q: future_layer_gain_data_reset_basis(q) for q in gained_data}, + save_layer=future_save_layer, + ) + for next_tile in future_patch.tiles: + if not matches_past_basis(next_tile): + # Anticommutes with time boundary. + continue + + m = next_tile.measurement_qubit + comparison = [AtLayer(m, future_save_layer)] + prev_tile = past_patch.m2tile.get(m) + if prev_tile is not None and not prev_tile.data_set.isdisjoint( + kept_data_qubits + ): + comparison.append(AtLayer(m, past_save_layer)) + for q in prev_tile.data_set: + if q not in kept_data_qubits: + comparison.append(AtLayer(q, past_save_layer)) + builder.detector( + comparison, + pos=m, + mark_as_post_selected=mark_as_post_selected( + AtLayer(m, future_save_layer) + ), + ) + + builder.shift_coords(dt=1) + if future_layer_obs_key_sets: + for obs_index, obs_qubits in future_layer_obs_key_sets.items(): + builder.obs_include( + [AtLayer(q, future_save_layer) for q in obs_qubits], + obs_index=obs_index, + ) + builder.tick() diff --git a/src/gen/_surf/_surface_code_legacy.py b/src/gen/_surf/_surface_code_legacy.py new file mode 100644 index 0000000..918f81b --- /dev/null +++ b/src/gen/_surf/_surface_code_legacy.py @@ -0,0 +1,285 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Callable, Any, Literal, AbstractSet, Iterable + +from gen._layers import transpile_to_z_basis_interaction_circuit +from gen._core import Patch, Builder, AtLayer, PauliString, complex_key, sorted_complex + + +def _measure_css( + *, + patch: Patch, + data_resets: dict[complex, str], + data_measures: dict[complex, str], + builder: Builder, + tracker_key: Callable[[complex], Any], + tracker_layer: float, +) -> None: + assert patch.measure_set.isdisjoint(data_resets) + if not patch.tiles: + return + + x_tiles = [tile for tile in patch.tiles if tile.basis == "X"] + z_tiles = [tile for tile in patch.tiles if tile.basis == "Z"] + other_tiles = [ + tile for tile in patch.tiles if tile.basis != "X" and tile.basis != "Z" + ] + reset_bases = { + "X": [tile.measurement_qubit for tile in x_tiles], + "Y": [], + "Z": [tile.measurement_qubit for tile in z_tiles + other_tiles], + } + for q, b in data_resets.items(): + reset_bases[b].append(q) + for b, qs in reset_bases.items(): + if qs: + builder.gate(f"R{b}", qs) + builder.tick() + + (num_layers,) = {len(e.ordered_data_qubits) for e in patch.tiles} + for k in range(num_layers): + pairs = [] + for tile in x_tiles: + q = tile.ordered_data_qubits[k] + if q is not None: + pairs.append((tile.measurement_qubit, q)) + for tile in z_tiles: + q = tile.ordered_data_qubits[k] + if q is not None: + pairs.append((q, tile.measurement_qubit)) + builder.gate2("CX", pairs) + for tile in sorted( + other_tiles, key=lambda tile: complex_key(tile.measurement_qubit) + ): + q = tile.ordered_data_qubits[k] + b = tile.bases[k] + if q is not None: + builder.gate2(f"{b}CX", [(q, tile.measurement_qubit)]) + builder.tick() + + measure_bases = { + "X": [tile.measurement_qubit for tile in x_tiles], + "Y": [], + "Z": [tile.measurement_qubit for tile in z_tiles + other_tiles], + } + for q, b in data_measures.items(): + measure_bases[b].append(q) + for b, qs in measure_bases.items(): + if qs: + builder.measure( + qs, + basis=b, + tracker_key=tracker_key, + save_layer=tracker_layer, + ) + + +def _measure_cz( + *, + patch: Patch, + data_resets: dict[complex, str], + data_measures: dict[complex, str], + builder: Builder, + tracker_key: Callable[[complex], Any], + tracker_layer: float, +) -> None: + out = builder.fork() + _measure_css( + patch=patch, + data_resets=data_resets, + data_measures=data_measures, + builder=out, + tracker_key=tracker_key, + tracker_layer=tracker_layer, + ) + builder.circuit += transpile_to_z_basis_interaction_circuit( + out.circuit, is_entire_circuit=False + ) + + +def _measure_mpp( + patch, + *, + data_resets: dict[complex, str], + data_measures: dict[complex, str], + builder: Builder, + tracker_key: Callable[[complex], Any], + tracker_layer: float, +) -> None: + assert patch.measure_set.isdisjoint(data_resets) + + if data_resets: + for b in "XYZ": + builder.gate(f"R{b}", {q for q, db in data_resets.items() if b == db}) + + for v in patch.tiles: + builder.measure_pauli_string( + PauliString( + {q: b for q, b in zip(v.ordered_data_qubits, v.bases) if q is not None} + ), + key=AtLayer(tracker_key(v.measurement_qubit), tracker_layer), + ) + + if data_measures: + for b in "XYZ": + builder.measure( + {q for q, db in data_measures.items() if b == db}, + basis=b, + tracker_key=tracker_key, + save_layer=tracker_layer, + ) + + +def measure_patch_legacy( + patch, + *, + data_resets: dict[complex, str] | None = None, + data_measures: dict[complex, str] | None = None, + builder: Builder, + tracker_key: Callable[[complex], Any] = lambda e: e, + save_layer: Any, + style: Literal["css", "cz", "mpp"] = "cz", +) -> None: + if data_resets is None: + data_resets = {} + if data_measures is None: + data_measures = {} + if style == "css": + _measure_css( + patch=patch, + data_resets=data_resets, + data_measures=data_measures, + builder=builder, + tracker_key=tracker_key, + tracker_layer=save_layer, + ) + elif style == "cz": + _measure_cz( + patch=patch, + data_resets=data_resets, + data_measures=data_measures, + builder=builder, + tracker_key=tracker_key, + tracker_layer=save_layer, + ) + elif style == "mpp": + _measure_mpp( + patch=patch, + data_resets=data_resets, + data_measures=data_measures, + builder=builder, + tracker_key=tracker_key, + tracker_layer=save_layer, + ) + else: + raise NotImplementedError(f"{style=}") + + +def measure_patch_legacy_detect( + patch, + *, + comparison_overrides: dict[Any, list[Any] | None] | None = None, + skipped_comparisons: Iterable[Any] = (), + singleton_detectors: Iterable[Any] = (), + data_resets: dict[complex, str] | None = None, + data_measures: dict[complex, str] | None = None, + builder: Builder, + repetitions: int | None = None, + tracker_key: Callable[[complex], Any] = lambda e: e, + cmp_layer: Any | None, + save_layer: Any, + tracker_layer_last_rep: Any | None = None, + post_selected_positions: AbstractSet[complex] = frozenset(), + style: Literal["css", "cz", "mpp"] = "cz", +) -> None: + if data_resets is None: + data_resets = {} + if data_measures is None: + data_measures = {} + assert (repetitions is not None) == (tracker_layer_last_rep is not None) + if repetitions is not None: + assert not data_resets + assert not data_measures + if repetitions == 0: + for plaq in patch.tiles: + m = plaq.measurement_qubit + builder.tracker.make_measurement_group( + [AtLayer(m, cmp_layer)], key=AtLayer(m, tracker_layer_last_rep) + ) + return + + child = builder.fork() + pm = builder.tracker.next_measurement_index + measure_patch_legacy( + patch=patch, + data_resets=data_resets, + data_measures=data_measures, + builder=child, + tracker_key=tracker_key, + save_layer=save_layer, + style=style, + ) + num_measurements = builder.tracker.next_measurement_index - pm + + if comparison_overrides is None: + comparison_overrides = {} + assert patch.measure_set.isdisjoint(data_resets) + skipped_comparisons_set = frozenset(skipped_comparisons) + singleton_detectors_set = frozenset(singleton_detectors) + for e in sorted_complex(patch.tiles, key=lambda e2: e2.measurement_qubit): + if all(e is None for e in e.ordered_data_qubits): + continue + failed = False + for q, b in zip(e.ordered_data_qubits, e.bases): + if q is not None and data_resets.get(q, b) != b: + failed = True + if failed: + continue + m = e.measurement_qubit + if m in skipped_comparisons_set: + continue + if m in singleton_detectors_set: + comparisons = [] + elif cmp_layer is not None: + comparisons = comparison_overrides.get(m, [AtLayer(m, cmp_layer)]) + else: + comparisons = [] + if comparisons is None: + continue + assert isinstance( + comparisons, list + ), f"Vs exception must be a list but got {comparisons!r} for {m!r}" + child.detector( + [AtLayer(m, save_layer), *comparisons], + pos=m, + mark_as_post_selected=m in post_selected_positions, + ) + child.circuit.append("SHIFT_COORDS", [], [0, 0, 1]) + specified_reps = repetitions is not None + if repetitions is None: + repetitions = 1 + if specified_reps: + child.tick() + + if repetitions > 1 or tracker_layer_last_rep is not None: + if tracker_layer_last_rep is None: + raise ValueError("repetitions > 1 and tracker_layer_last_rep is None") + offset = num_measurements * (repetitions - 1) + builder.tracker.next_measurement_index += offset + for m in data_measures.keys() | patch.measure_set: + builder.tracker.recorded[AtLayer(m, tracker_layer_last_rep)] = [ + e + offset for e in builder.tracker.recorded[AtLayer(m, save_layer)] + ] + builder.circuit += child.circuit * repetitions diff --git a/src/gen/_surf/_surface_code_test.py b/src/gen/_surf/_surface_code_test.py new file mode 100644 index 0000000..390585e --- /dev/null +++ b/src/gen/_surf/_surface_code_test.py @@ -0,0 +1,338 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gen +from gen._surf._patch_outline import PatchOutline +from gen._surf._closed_curve import ClosedCurve +from gen._surf._order import Order_Z, Order_ᴎ, checkerboard_basis +from gen._surf._surface_code import layer_transition, surface_code_patch +from gen._core._builder import Builder +from gen._core._pauli_string import PauliString + + +def test_surface_code_patch(): + patch = surface_code_patch( + width=5, + height=5, + top_basis="Z", + bot_basis="Z", + left_basis="X", + right_basis="X", + rel_order_func=lambda _: Order_Z, + ) + assert len(patch.data_set) == 25 + assert len(patch.tiles) == 24 + + +def test_layer_transition_notched_shift(): + c0 = ClosedCurve.from_cycle( + [ + "Z", + 6 + 0j, + "X", + 6 + 6j, + "Z", + 0 + 6j, + "X", + 0 + 0j, + ] + ) + p0 = PatchOutline([c0]).to_patch( + rel_order_func=lambda m: Order_Z if checkerboard_basis(m) == "Z" else Order_ᴎ + ) + p2 = PatchOutline([c0.offset_by(2)]).to_patch( + rel_order_func=lambda m: Order_Z if checkerboard_basis(m) == "Z" else Order_ᴎ + ) + p3 = PatchOutline([c0.offset_by(3)]).to_patch( + rel_order_func=lambda m: Order_Z if checkerboard_basis(m) == "Z" else Order_ᴎ + ) + + builder = Builder.for_qubits(p0.used_set | p3.used_set | {-1}) + + builder.measure_pauli_string( + PauliString.from_xyzs(zs=[q for q in p0.data_set if q.real == 4] + [-1]), + key="H_INIT", + ) + builder.obs_include(["H_INIT"], obs_index=2) + builder.tick() + builder.measure_pauli_string( + PauliString.from_xyzs(xs=[q for q in p0.data_set if q.imag == 0] + [-1]), + key="V_INIT", + ) + builder.obs_include(["V_INIT"], obs_index=5) + builder.tick() + + builder.measure_patch(patch=p0, save_layer=4) + + builder.tick() + layer_transition( + builder=builder, + past_patch=p0, + future_patch=p2, + kept_data_qubits=p0.data_set & p2.data_set & p3.data_set, + style="mpp", + past_compare_layer=4, + past_save_layer=5, + future_save_layer=6, + past_layer_lost_data_obs_qubit_sets={ + 2: {q for q in p0.data_set | p3.data_set if q.real == 4}, + 5: {q for q in p0.data_set | p3.data_set if q.imag == 0}, + }, + future_layer_gain_data_reset_basis="X", + past_layer_lost_data_measure_basis="X", + ) + + builder.measure_pauli_string( + PauliString.from_xyzs(zs=[q for q in p2.data_set if q.real == 4] + [-1]), + key="H_OUT", + ) + builder.obs_include(["H_OUT"], obs_index=2) + builder.tick() + builder.measure_pauli_string( + PauliString.from_xyzs(xs=[q for q in p2.data_set if q.imag == 0] + [-1]), + key="V_OUT", + ) + builder.obs_include(["V_OUT"], obs_index=5) + builder.tick() + + # Verify that all detectors and observables are deterministic. + builder.circuit.detector_error_model(decompose_errors=True) + + +def test_layer_transition_shrink(): + c_shrunk = ClosedCurve.from_cycle( + [ + "X", + 3 + 0j, + "Z", + 3 + 6j, + "X", + 0 + 6j, + "Z", + 0 + 0j, + ] + ) + + c_full = ClosedCurve.from_cycle( + [ + "X", + 6 + 0j, + "Z", + 6 + 6j, + "X", + 0 + 6j, + "Z", + 0 + 0j, + ] + ) + + p_shrunk = PatchOutline([c_shrunk]).to_patch( + rel_order_func=lambda m: Order_Z if checkerboard_basis(m) == "Z" else Order_ᴎ + ) + p_full = PatchOutline([c_full]).to_patch( + rel_order_func=lambda m: Order_Z if checkerboard_basis(m) == "Z" else Order_ᴎ + ) + + builder = Builder.for_qubits(p_full.used_set | {-1}) + + builder.measure_pauli_string( + gen.PauliString.from_xyzs( + xs=[q for q in p_full.data_set if q.real == 0] + [-1] + ), + key="H_INIT", + ) + builder.obs_include(["H_INIT"], obs_index=2) + builder.tick() + builder.measure_pauli_string( + gen.PauliString.from_xyzs( + zs=[q for q in p_full.data_set if q.imag == 0] + [-1] + ), + key="V_INIT", + ) + builder.obs_include(["V_INIT"], obs_index=5) + builder.tick() + + builder.measure_patch(patch=p_full, save_layer=4) + + builder.tick() + layer_transition( + builder=builder, + past_patch=p_full, + future_patch=p_shrunk, + kept_data_qubits=p_shrunk.data_set, + style="mpp", + past_compare_layer=4, + past_save_layer=5, + future_save_layer=6, + past_layer_lost_data_obs_qubit_sets={ + 2: {q for q in p_full.data_set if q.real == 0}, + 5: {q for q in p_full.data_set if q.imag == 0}, + }, + past_layer_lost_data_measure_basis="Z", + future_layer_gain_data_reset_basis="Z", + ) + + builder.measure_pauli_string( + PauliString.from_xyzs(xs=[q for q in p_shrunk.data_set if q.real == 0] + [-1]), + key="H_OUT", + ) + builder.obs_include(["H_OUT"], obs_index=2) + builder.tick() + builder.measure_pauli_string( + PauliString.from_xyzs(zs=[q for q in p_shrunk.data_set if q.imag == 0] + [-1]), + key="V_OUT", + ) + builder.obs_include(["V_OUT"], obs_index=5) + builder.tick() + + # Verify that all detectors and observables are deterministic. + builder.circuit.detector_error_model(decompose_errors=True) + + +def test_layer_transition_full_notch(): + c = ClosedCurve.from_cycle( + [ + "X", + 3 + 0j, + "Z", + 3 + 3j, + "X", + 0 + 3j, + "Z", + 0 + 0j, + ] + ) + + p = PatchOutline([c]).to_patch( + rel_order_func=lambda m: Order_Z if checkerboard_basis(m) == "Z" else Order_ᴎ + ) + builder = Builder.for_qubits(p.used_set) + builder.measure_patch(patch=p, save_layer=4) + builder.tick() + layer_transition( + builder=builder, + past_patch=p, + future_patch=p, + kept_data_qubits=set(), + style="mpp", + past_compare_layer=4, + past_save_layer=5, + future_save_layer=6, + past_layer_lost_data_obs_qubit_sets={}, + past_layer_lost_data_measure_basis="Z", + future_layer_gain_data_reset_basis="Z", + ) + + # Verify that all detectors and observables are deterministic. + builder.circuit.detector_error_model(decompose_errors=True) + assert builder.circuit.num_detectors == 7 * 3 + 8 + + +def test_fused_inner(): + b1 = PatchOutline( + [ + ClosedCurve( + points=[ + 0 + 16j, + 6 + 16j, + 8 + 16j, + 14 + 16j, + 16 + 16j, + 22 + 16j, + 22 + 18j, + 22 + 20j, + 22 + 22j, + 22 + 24j, + 22 + 26j, + 22 + 28j, + 22 + 30j, + 16 + 30j, + 16 + 28j, + 16 + 26j, + 14 + 26j, + 8 + 26j, + 8 + 24j, + 14 + 24j, + 16 + 24j, + 16 + 22j, + 16 + 20j, + 16 + 18j, + 14 + 18j, + 8 + 18j, + 6 + 18j, + 6 + 20j, + 8 + 20j, + 14 + 20j, + 14 + 22j, + 8 + 22j, + 6 + 22j, + 6 + 24j, + 6 + 26j, + 6 + 28j, + 8 + 28j, + 14 + 28j, + 14 + 30j, + 8 + 30j, + 6 + 30j, + 30j, + 28j, + 26j, + 24j, + 22j, + 20j, + 18j, + ], + bases="XXXXXXXXXXXXXXXXXXZXXXXXXXXXXXZXXXXXXXZXXXXXXXXX", + ) + ] + ) + b2 = b1.fused(19 + 29j, 11 + 29j) + + assert len(b2.region_curves) == 2 + assert all(e == "X" for e in b2.region_curves[0].bases) + assert b2.region_curves[1] == ClosedCurve( + points=[ + (16 + 28j), + (16 + 26j), + (14 + 26j), + (8 + 26j), + (8 + 24j), + (14 + 24j), + (16 + 24j), + (16 + 22j), + (16 + 20j), + (16 + 18j), + (14 + 18j), + (8 + 18j), + (6 + 18j), + (6 + 20j), + (8 + 20j), + (14 + 20j), + (14 + 22j), + (8 + 22j), + (6 + 22j), + (6 + 24j), + (6 + 26j), + (6 + 28j), + (8 + 28j), + (14 + 28j), + ], + bases="XXXXZXXXXXXXXXXXZXXXXXXX", + ) + + +def test_distance_2(): + curve = ClosedCurve(points=[1, (1 + 1j), 1j, 0], bases="ZXZX") + plan = PatchOutline([curve]).to_patch(rel_order_func=lambda _: Order_Z) + assert len(plan.tiles) == 3 diff --git a/src/gen/_surf/_trans.py b/src/gen/_surf/_trans.py new file mode 100644 index 0000000..d1b2035 --- /dev/null +++ b/src/gen/_surf/_trans.py @@ -0,0 +1,136 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import AbstractSet, Callable, Any, Literal + +from gen._core._util import sorted_complex +from gen._core._builder import Builder, AtLayer +from gen._core._patch import Patch, Tile +from gen._surf._surface_code_legacy import measure_patch_legacy + + +def build_patch_to_patch_surface_code_transition_rounds( + *, + builder: Builder, + first_layer: Patch, + second_layer: Patch, + style: Literal["css", "mpp"], + cmp_key_prev_layer: Any, + save_key_first_layer: Any, + save_key_second_layer: Any, + kept_data_qubits: AbstractSet[complex], + obs_qubit_sets: dict[int, AbstractSet[complex]], + first_layer_data_measure_basis: None | str | Callable[[complex], str], + second_layer_data_init_basis: None | str | Callable[[complex], str], +): + if isinstance(first_layer_data_measure_basis, str): + fixed_future_time_basis = first_layer_data_measure_basis + first_layer_data_measure_basis = lambda _: fixed_future_time_basis + if isinstance(second_layer_data_init_basis, str): + fixed_past_time_basis = second_layer_data_init_basis + second_layer_data_init_basis = lambda _: fixed_past_time_basis + + assert kept_data_qubits <= first_layer.data_set + assert kept_data_qubits <= second_layer.data_set, repr( + sorted_complex(kept_data_qubits - second_layer.data_set) + ) + lost_data = first_layer.data_set - kept_data_qubits + gained_data = second_layer.data_set - kept_data_qubits + + def matches_1st_layer_measure_basis(tile: Tile) -> bool: + for b, d in zip(tile.bases, tile.ordered_data_qubits): + if ( + d is not None + and d in lost_data + and b != first_layer_data_measure_basis(d) + ): + return False + return True + + if first_layer.tiles: + measure_patch_legacy( + patch=first_layer, + style=style, + builder=builder, + data_measures={q: first_layer_data_measure_basis(q) for q in lost_data}, + save_layer=save_key_first_layer, + ) + + # Detectors from comparing to previous round. + for prev_tile in first_layer.tiles: + m = prev_tile.measurement_qubit + builder.detector( + [AtLayer(m, cmp_key_prev_layer), AtLayer(m, save_key_first_layer)], + pos=m, + ) + + # Detectors from comparing data measurements to stabilizer measurements. + for prev_tile in first_layer.tiles: + m = prev_tile.measurement_qubit + if matches_1st_layer_measure_basis( + prev_tile + ) and prev_tile.data_set.isdisjoint(kept_data_qubits): + builder.detector( + [AtLayer(q, save_key_first_layer) for q in prev_tile.used_set], + pos=m, + t=0.5, + ) + + for obs_index, obs_qubits in obs_qubit_sets.items(): + builder.obs_include( + [AtLayer(q, save_key_first_layer) for q in lost_data & obs_qubits], + obs_index=obs_index, + ) + builder.shift_coords(dt=1) + builder.tick() + + def matches_2nd_layer_init_basis(tile: Tile) -> bool: + for b, d in zip(tile.bases, tile.ordered_data_qubits): + if ( + d is not None + and d in gained_data + and b != second_layer_data_init_basis(d) + ): + return False + return True + + if second_layer.tiles: + measure_patch_legacy( + patch=second_layer, + style=style, + builder=builder, + data_resets={q: second_layer_data_init_basis(q) for q in gained_data}, + save_layer=save_key_second_layer, + ) + + # Detectors from comparing to first layer and/or data resets. + for next_tile in second_layer.tiles: + if not matches_2nd_layer_init_basis(next_tile): + # Anticommutes with time boundary. + continue + + m = next_tile.measurement_qubit + comparison = [AtLayer(m, save_key_second_layer)] + prev_tile = first_layer.m2tile.get(m) + if prev_tile is not None and not prev_tile.data_set.isdisjoint( + kept_data_qubits + ): + comparison.append(AtLayer(m, save_key_first_layer)) + for q in prev_tile.data_set: + if q not in kept_data_qubits: + comparison.append(AtLayer(q, save_key_first_layer)) + builder.detector(comparison, pos=m) + + builder.shift_coords(dt=1) + builder.tick() diff --git a/src/gen/_surf/_viz_gltf_3d.py b/src/gen/_surf/_viz_gltf_3d.py new file mode 100644 index 0000000..a19e8f5 --- /dev/null +++ b/src/gen/_surf/_viz_gltf_3d.py @@ -0,0 +1,425 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import base64 +import collections +from typing import Iterable, Sequence + +import numpy as np +import pygltflib + + +class ColoredTriangleData: + def __init__( + self, *, rgba: tuple[float, float, float, float], triangle_list: np.ndarray + ): + assert ( + len(triangle_list.shape) == 2 + and triangle_list.shape[1] == 3 + and triangle_list.dtype == np.float32 + ) + assert len(rgba) == 4 + assert triangle_list.shape[0] > 0 + self.rgba = tuple(rgba) + self.triangle_list = triangle_list + + @staticmethod + def square( + *, + rgba: tuple[float, float, float, float], + origin: Iterable[float], + d1: Iterable[float], + d2: Iterable[float], + ) -> "ColoredTriangleData": + origin = np.array(origin, dtype=np.float32) + d1 = np.array(d1, dtype=np.float32) + d2 = np.array(d2, dtype=np.float32) + p1 = origin + d1 + p2 = origin + d2 + return ColoredTriangleData( + rgba=rgba, + triangle_list=np.array( + [ + origin, + p1, + p2, + p2, + p1, + p1 + d2, + ], + dtype=np.float32, + ), + ) + + @staticmethod + def fused(data: Iterable["ColoredTriangleData"]) -> list["ColoredTriangleData"]: + groups = collections.defaultdict(list) + for e in data: + groups[e.rgba].append(e) + result = [] + for rgba, group in groups.items(): + if len(group) == 1: + result.append(group[0]) + else: + result.append( + ColoredTriangleData( + rgba=rgba, + triangle_list=np.concatenate( + [e.triangle_list for e in group], axis=0 + ), + ) + ) + return result + + +class ColoredLineData: + def __init__( + self, *, rgba: tuple[float, float, float, float], edge_list: np.ndarray + ): + assert ( + len(edge_list.shape) == 2 + and edge_list.shape[1] == 3 + and edge_list.dtype == np.float32 + ) + assert len(rgba) == 4 + assert edge_list.shape[0] > 0 + self.rgba = tuple(rgba) + self.edge_list = edge_list + + @staticmethod + def fused(data: Iterable["ColoredLineData"]) -> list["ColoredLineData"]: + groups = collections.defaultdict(list) + for e in data: + groups[e.rgba].append(e) + result = [] + for rgba, group in groups.items(): + if len(group) == 1: + result.append(group[0]) + else: + result.append( + ColoredLineData( + rgba=rgba, + edge_list=np.concatenate([e.edge_list for e in group], axis=0), + ) + ) + return result + + +def gltf_model_from_colored_triangle_data( + colored_triangle_data: list[ColoredTriangleData], + *, + colored_line_data: Sequence[ColoredLineData] = (), +) -> pygltflib.GLTF2: + colored_triangle_data = ColoredTriangleData.fused(colored_triangle_data) + colored_line_data = ColoredLineData.fused(colored_line_data) + + gltf = pygltflib.GLTF2() + gltf.asset = None + + material_INDICES = {} + for data in colored_triangle_data: + material = pygltflib.Material() + material.pbrMetallicRoughness = pygltflib.PbrMetallicRoughness() + material.pbrMetallicRoughness.baseColorFactor = data.rgba + material.pbrMetallicRoughness.roughnessFactor = 0.8 + material.pbrMetallicRoughness.metallicFactor = 0.3 + material.emissiveFactor = None + material.alphaMode = None + material.alphaCutoff = None + material.doubleSided = True + material_INDICES[data.rgba] = len(gltf.materials) + gltf.materials.append(material) + for data in colored_line_data: + material = pygltflib.Material() + material.pbrMetallicRoughness = pygltflib.PbrMetallicRoughness() + material.pbrMetallicRoughness.baseColorFactor = data.rgba + material.pbrMetallicRoughness.roughnessFactor = 0.8 + material.pbrMetallicRoughness.metallicFactor = 0.3 + material.emissiveFactor = None + material.alphaMode = None + material.alphaCutoff = None + material_INDICES[data.rgba] = len(gltf.materials) + gltf.materials.append(material) + + shared_buffer = pygltflib.Buffer() + coords_tri = ( + np.array([]) + if not colored_triangle_data + else np.concatenate( + [data.triangle_list for data in colored_triangle_data], axis=0 + ) + ) + coords_edg = ( + np.array([]) + if not colored_line_data + else np.concatenate([data.edge_list for data in colored_line_data], axis=0) + ) + coord_data = coords_tri.tobytes() + coords_edg.tobytes() + buffer_bytes = base64.b64encode(coord_data).decode() + shared_buffer.uri = f"data:application/octet-stream;base64,{buffer_bytes}" + shared_buffer.byteLength = len(buffer_bytes) + shared_buffer_INDEX = len(gltf.buffers) + gltf.buffers.append(shared_buffer) + + buffer_view_INDICES = {} + byte_offset = 0 + for data in colored_triangle_data: + bufferView = pygltflib.BufferView() + bufferView.buffer = shared_buffer_INDEX + byte_length = data.triangle_list.shape[0] * 3 * 4 + bufferView.byteOffset = byte_offset + bufferView.byteLength = byte_length + byte_offset += byte_length + bufferView.target = pygltflib.ARRAY_BUFFER + buffer_view_INDICES[data.rgba] = len(gltf.bufferViews) + gltf.bufferViews.append(bufferView) + for data in colored_line_data: + bufferView = pygltflib.BufferView() + bufferView.buffer = shared_buffer_INDEX + byte_length = data.edge_list.shape[0] * 3 * 4 + bufferView.byteOffset = byte_offset + bufferView.byteLength = byte_length + byte_offset += byte_length + bufferView.target = pygltflib.ARRAY_BUFFER + buffer_view_INDICES[data.rgba] = len(gltf.bufferViews) + gltf.bufferViews.append(bufferView) + + accessor_INDICES = {} + for data in colored_triangle_data: + accessor = pygltflib.Accessor() + accessor.bufferView = buffer_view_INDICES[data.rgba] + accessor.byteOffset = 0 + accessor.componentType = pygltflib.FLOAT + accessor.count = data.triangle_list.shape[0] + accessor.type = pygltflib.VEC3 + accessor.max = [float(e) for e in np.max(data.triangle_list, axis=0)] + accessor.min = [float(e) for e in np.min(data.triangle_list, axis=0)] + accessor_INDICES[data.rgba] = len(gltf.accessors) + gltf.accessors.append(accessor) + for data in colored_line_data: + accessor = pygltflib.Accessor() + accessor.bufferView = buffer_view_INDICES[data.rgba] + accessor.byteOffset = 0 + accessor.componentType = pygltflib.FLOAT + accessor.count = data.edge_list.shape[0] + accessor.type = pygltflib.VEC3 + accessor.max = [float(e) for e in np.max(data.edge_list, axis=0)] + accessor.min = [float(e) for e in np.min(data.edge_list, axis=0)] + accessor_INDICES[data.rgba] = len(gltf.accessors) + gltf.accessors.append(accessor) + + mesh0 = pygltflib.Mesh() + for data in colored_triangle_data: + primitive = pygltflib.Primitive() + primitive.material = material_INDICES[data.rgba] + primitive.attributes.POSITION = accessor_INDICES[data.rgba] + primitive.mode = pygltflib.TRIANGLES + mesh0.primitives.append(primitive) + for data in colored_line_data: + primitive = pygltflib.Primitive() + primitive.material = material_INDICES[data.rgba] + primitive.attributes.POSITION = accessor_INDICES[data.rgba] + primitive.mode = pygltflib.LINES + mesh0.primitives.append(primitive) + mesh0_INDEX = len(gltf.meshes) + gltf.meshes.append(mesh0) + + node0 = pygltflib.Node() + node0.mesh = mesh0_INDEX + node0_INDEX = len(gltf.nodes) + gltf.nodes.append(node0) + + scene = pygltflib.Scene() + scene.nodes = [node0_INDEX] + gltf.scenes.append(scene) + + return gltf + + +def viz_3d_gltf_model_html(model: pygltflib.GLTF2) -> str: + model_bytes = b"".join(model.save_to_bytes()) + + model_data_uri = ( + f"""data:text/plain;base64,{base64.b64encode(model_bytes).decode()}""" + ) + + return ( + r''' + + + + + + + Download 3D Model as .GLTF File +
Mouse Wheel = Zoom. Left Drag = Orbit. Right Drag = Strafe. +
+
JavaScript Blocked?
+
+ + + + """ + ) diff --git a/src/gen/_surf/_viz_gltf_3d_test.py b/src/gen/_surf/_viz_gltf_3d_test.py new file mode 100644 index 0000000..1bd7092 --- /dev/null +++ b/src/gen/_surf/_viz_gltf_3d_test.py @@ -0,0 +1,146 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json + +import numpy as np + +from gen._surf._viz_gltf_3d import ( + ColoredTriangleData, + gltf_model_from_colored_triangle_data, + viz_3d_gltf_model_html, +) + + +def test_gltf_model_from_colored_triangle_data(): + model = gltf_model_from_colored_triangle_data( + [ + ColoredTriangleData( + rgba=(1, 0, 0, 1), + triangle_list=np.array( + [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1], + ], + dtype=np.float32, + ), + ), + ColoredTriangleData( + rgba=(1, 0, 1, 1), + triangle_list=np.array( + [ + [1, 1, 0], + [0, 1, 0], + [0, 0, 1], + ], + dtype=np.float32, + ), + ), + ] + ) + assert json.loads(model.to_json()) == { + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5126, + "normalized": False, + "count": 3, + "type": "VEC3", + "max": [1.0, 1.0, 1.0], + "min": [0.0, 0.0, 0.0], + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "normalized": False, + "count": 3, + "type": "VEC3", + "max": [1.0, 1.0, 1.0], + "min": [0.0, 0.0, 0.0], + }, + ], + "bufferViews": [ + {"buffer": 0, "byteOffset": 0, "byteLength": 36, "target": 34962}, + {"buffer": 0, "byteOffset": 36, "byteLength": 36, "target": 34962}, + ], + "buffers": [ + { + "uri": "data:application/octet-stream;base64,AACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/", + "byteLength": 96, + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [1, 0, 0, 1], + "metallicFactor": 0.3, + "roughnessFactor": 0.8, + }, + "doubleSided": True, + }, + { + "pbrMetallicRoughness": { + "baseColorFactor": [1, 0, 1, 1], + "metallicFactor": 0.3, + "roughnessFactor": 0.8, + }, + "doubleSided": True, + }, + ], + "meshes": [ + { + "primitives": [ + {"attributes": {"POSITION": 0}, "mode": 4, "material": 0}, + {"attributes": {"POSITION": 1}, "mode": 4, "material": 1}, + ] + } + ], + "nodes": [{"mesh": 0}], + "scenes": [{"nodes": [0]}], + } + + +def test_viz_3d_gltf_model_html(): + model = gltf_model_from_colored_triangle_data( + [ + ColoredTriangleData( + rgba=(1, 0, 0, 1), + triangle_list=np.array( + [ + [1, 0, 0], + [0, 1, 0], + [0, 0, 1], + ], + dtype=np.float32, + ), + ), + ColoredTriangleData( + rgba=(1, 0, 1, 1), + triangle_list=np.array( + [ + [1, 1, 0], + [0, 1, 0], + [0, 0, 1], + ], + dtype=np.float32, + ), + ), + ] + ) + + html = viz_3d_gltf_model_html(model) + assert "" in html diff --git a/src/gen/_surf/_viz_patch_outline_svg.py b/src/gen/_surf/_viz_patch_outline_svg.py new file mode 100644 index 0000000..c71ee39 --- /dev/null +++ b/src/gen/_surf/_viz_patch_outline_svg.py @@ -0,0 +1,209 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import math +from typing import Iterable, TYPE_CHECKING, Literal, Union + +from gen._core._util import min_max_complex + +if TYPE_CHECKING: + from gen._surf._patch_outline import PatchOutline + from gen._surf._patch_transition_outline import PatchTransitionOutline + + +def patch_outline_svg_viewer( + values: Iterable[Union["PatchOutline", "PatchTransitionOutline"]], + *, + other_segments: Iterable[tuple[complex, Literal["X", "Y", "Z"], complex]] = (), + canvas_height: int = 500, +) -> str: + """Returns a picture of the stabilizers measured by various plan.""" + from gen._surf._patch_outline import PatchOutline + from gen._surf._patch_transition_outline import PatchTransitionOutline + + outlines = tuple(values) + control_points = [ + pt for outline in outlines for pt in outline.iter_control_points() + ] + min_c, max_c = min_max_complex(control_points, default=0) + min_c -= 1 + 1j + max_c += 1 + 1j + box_width = max_c.real - min_c.real + box_height = max_c.imag - min_c.imag + pad = max(box_width, box_height) * 0.1 + 1 + box_width += pad + box_height += pad + columns = math.ceil(math.sqrt(len(outlines))) + rows = math.ceil(len(outlines) / max(1, columns)) + total_height = max(1.0, box_height * rows - pad) + total_width = max(1.0, box_width * columns - pad) + scale_factor = canvas_height / max(total_height, 1) + canvas_width = int(math.ceil(canvas_height * (total_width / total_height))) + stroke_width = scale_factor / 25 + + def transform_pt(plan_i2: int, pt2: complex) -> complex: + pt2 += box_width * (plan_i2 % columns) + pt2 += box_height * (plan_i2 // columns) * 1j + pt2 += pad * (0.5 + 0.5j) + pt2 *= scale_factor + return pt2 + + lines = [ + f"""""" + ] + + BASE_COLORS = {"X": "#FF0000", "Z": "#0000FF", "Y": "#00FF00", None: "gray"} + OBS_COLORS = {"X": "#800000", "Z": "#000080", "Y": "#008000", None: "black"} + + lines.append( + f'' + ) + lines.append( + "X" + ) + + lines.append( + f'' + ) + lines.append( + "Y" + ) + + lines.append( + f'' + ) + lines.append( + "Z" + ) + + # Draw interior. + for outline_index, outline in enumerate(outlines): + pieces = [] + if isinstance(outline, PatchOutline): + for curve in outline.region_curves: + pieces.append("M") + for k in range(len(curve)): + a = transform_pt(outline_index, curve.points[k]) + pieces.append(f"{a.real},{a.imag}") + pieces.append("Z") + path = " ".join(pieces) + lines.append(f'') + elif isinstance(outline, PatchTransitionOutline): + fill_color = "#000" + for curve in outline.data_boundary_planes: + fill_color = BASE_COLORS[curve.basis] + pieces.append("M") + for k in range(len(curve)): + a = transform_pt(outline_index, curve.points[k]) + pieces.append(f"{a.real},{a.imag}") + pieces.append("Z") + path = " ".join(pieces) + lines.append(f'') + else: + raise NotImplementedError(f"{outline=}") + + # Trace boundaries. + for outline_index, outline in enumerate(outlines): + if isinstance(outline, PatchOutline): + for curve in outline.region_curves: + for k in range(len(curve)): + a = transform_pt(outline_index, curve.points[k - 1]) + b = transform_pt(outline_index, curve.points[k]) + stroke_color = BASE_COLORS[curve.bases[k]] + lines.append( + f"' + ) + for k, obs_pair in enumerate(outline.observables): + k -= len(outline.observables) / 2 + for basis, obs in obs_pair: + for a, b, _basis in obs.segments: + a = transform_pt(outline_index, a) + b = transform_pt(outline_index, b) + stroke_color = OBS_COLORS[basis] + lines.append( + f"' + ) + for a, basis, b in other_segments: + a = transform_pt(outline_index, a) + b = transform_pt(outline_index, b) + stroke_color = OBS_COLORS[basis] + lines.append( + f"' + ) + + # Trace control points. + for outline_index, outline in enumerate(outlines): + for pt in outline.iter_control_points(): + a = transform_pt(outline_index, pt) + lines.append( + f"' + ) + + # Frames + for outline_index, outline in enumerate(outlines): + a = transform_pt(outline_index, min_c) + b = transform_pt(outline_index, max_c) + lines.append( + f'' + ) + + lines.append("") + return "\n".join(lines) diff --git a/src/gen/_surf/_viz_sequence_3d.py b/src/gen/_surf/_viz_sequence_3d.py new file mode 100644 index 0000000..c7bb60e --- /dev/null +++ b/src/gen/_surf/_viz_sequence_3d.py @@ -0,0 +1,143 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Tuple + +import numpy as np +import pygltflib + +from gen import PatchOutline +from gen._surf._step_sequence_outline import StepSequenceOutline +from gen._surf._patch_transition_outline import PatchTransitionOutline +from gen._surf._viz_gltf_3d import ( + ColoredTriangleData, + gltf_model_from_colored_triangle_data, + ColoredLineData, +) + +_X_COLOR = (1, 0, 0, 1) +_Z_COLOR = (0, 0, 1, 1) + + +def _coords(c: complex, t: float) -> tuple[float, float, float]: + return c.real, t, c.imag + + +def _patch_transition_to_floor( + *, + trans: PatchTransitionOutline, + t: float, + out_triangles: list[ColoredTriangleData], + out_lines: list[ColoredLineData], + order: int +): + for q in trans.data_set: + for d in range(4): + a = q + 1j**d + b = q + 1j**d * 1j + if a in trans.data_set and b in trans.data_set: + out_triangles.append( + ColoredTriangleData( + rgba=_X_COLOR if q in trans.data_x_set else _Z_COLOR, + triangle_list=np.array( + [ + _coords(q, t), + _coords(a, t), + _coords(b, t), + ][::order], + dtype=np.float32, + ), + ) + ) + for plane in trans.data_boundary_planes: + for _, a, c in plane: + out_lines.append( + ColoredLineData( + rgba=(0, 0, 0, 1), + edge_list=np.array( + [_coords(a, t), _coords(c, t)], dtype=np.float32 + ), + ) + ) + + +def _patch_boundary_to_walls( + *, + boundary: PatchOutline, + t: float, + dt: float, + out_triangles: list[ColoredTriangleData], + out_lines: list[ColoredLineData] +): + for curve in boundary.region_curves: + for basis, p1, p2 in curve: + out_triangles.append( + ColoredTriangleData.square( + rgba=_X_COLOR if basis == "X" else _Z_COLOR, + origin=_coords(p1, t), + d1=_coords(p2 - p1, 0), + d2=_coords(0, dt), + ) + ) + out_triangles.append( + ColoredTriangleData.square( + rgba=_X_COLOR if basis == "X" else _Z_COLOR, + origin=_coords(p1, t), + d1=_coords(p2 - p1, 0), + d2=_coords(0, dt), + ) + ) + for pt in boundary.iter_control_points(): + out_lines.append( + ColoredLineData( + rgba=(0, 0, 0, 1), + edge_list=np.array( + [_coords(pt, t), _coords(pt, t + dt)], dtype=np.float32 + ), + ) + ) + for curve in boundary.region_curves: + for _, a, c in curve: + for t2 in [t, t + dt]: + out_lines.append( + ColoredLineData( + rgba=(0, 0, 0, 1), + edge_list=np.array( + [_coords(a, t2), _coords(c, t2)], dtype=np.float32 + ), + ) + ) + + +def patch_sequence_to_model(sequence: StepSequenceOutline) -> pygltflib.GLTF2: + t = 0 + triangles = [] + lines = [] + for segment in sequence.steps: + _patch_transition_to_floor( + trans=segment.start, + t=t + 0.01, + out_triangles=triangles, + order=-1, + out_lines=lines, + ) + dt = max(1, segment.rounds) + _patch_boundary_to_walls( + boundary=segment.body, t=t, dt=dt, out_triangles=triangles, out_lines=lines + ) + t += dt + _patch_transition_to_floor( + trans=segment.end, t=t, out_triangles=triangles, order=+1, out_lines=lines + ) + return gltf_model_from_colored_triangle_data(triangles, colored_line_data=lines) diff --git a/src/gen/_util.py b/src/gen/_util.py new file mode 100644 index 0000000..d218330 --- /dev/null +++ b/src/gen/_util.py @@ -0,0 +1,183 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pathlib +import sys +from typing import Callable, Any + +import stim + + +def stim_circuit_with_transformed_coords( + circuit: stim.Circuit, transform: Callable[[complex], complex] +) -> stim.Circuit: + """Returns an equivalent circuit, but with the qubit and detector position metadata modified. + The "position" is assumed to be the first two coordinates. These are mapped to the real and + imaginary values of a complex number which is then transformed. + + Note that `SHIFT_COORDS` instructions that modify the first two coordinates are not supported. + This is because supporting them requires flattening loops, or promising that the given + transformation is affine. + + Args: + circuit: The circuit with qubits to reposition. + transform: The transformation to apply to the positions. The positions are given one by one + to this method, as complex numbers. The method returns the new complex number for the + position. + + Returns: + The transformed circuit. + """ + result = stim.Circuit() + for instruction in circuit: + if isinstance(instruction, stim.CircuitInstruction): + if instruction.name == "QUBIT_COORDS" or instruction.name == "DETECTOR": + args = list(instruction.gate_args_copy()) + while len(args) < 2: + args.append(0) + c = transform(args[0] + args[1] * 1j) + args[0] = c.real + args[1] = c.imag + result.append(instruction.name, instruction.targets_copy(), args) + continue + if instruction.name == "SHIFT_COORDS": + args = instruction.gate_args_copy() + if any(args[:2]): + raise NotImplementedError( + f"Shifting first two coords: {instruction=}" + ) + + if isinstance(instruction, stim.CircuitRepeatBlock): + result.append( + stim.CircuitRepeatBlock( + repeat_count=instruction.repeat_count, + body=stim_circuit_with_transformed_coords( + instruction.body_copy(), transform + ), + ) + ) + continue + + result.append(instruction) + return result + + +def stim_circuit_with_transformed_moments( + circuit: stim.Circuit, *, moment_func: Callable[[stim.Circuit], stim.Circuit] +) -> stim.Circuit: + """Applies a transformation to regions of a circuit separated by TICKs and blocks. + + For example, in this circuit: + + H 0 + X 0 + TICK + + H 1 + X 1 + REPEAT 100 { + H 2 + X 2 + } + H 3 + X 3 + + TICK + H 4 + X 4 + + `moment_func` would be called five times, each time with one of the H and X instruction pairs. + The result from the method would then be substituted into the circuit, replacing each of the H + and X instruction pairs. + + Args: + circuit: The circuit to return a transformed result of. + moment_func: The transformation to apply to regions of the circuit. Returns a new circuit + for the result. + + Returns: + A transformed circuit. + """ + + result = stim.Circuit() + current_moment = stim.Circuit() + + for instruction in circuit: + if isinstance(instruction, stim.CircuitRepeatBlock): + # Implicit tick at transition into REPEAT? + if current_moment: + result += moment_func(current_moment) + current_moment.clear() + + transformed_body = stim_circuit_with_transformed_moments( + instruction.body_copy(), moment_func=moment_func + ) + result.append( + stim.CircuitRepeatBlock( + repeat_count=instruction.repeat_count, body=transformed_body + ) + ) + elif ( + isinstance(instruction, stim.CircuitInstruction) + and instruction.name == "TICK" + ): + # Explicit tick. Process even if empty. + result += moment_func(current_moment) + result.append("TICK") + current_moment.clear() + else: + current_moment.append(instruction) + + # Implicit tick at end of circuit? + if current_moment: + result += moment_func(current_moment) + + return result + + +def estimate_qubit_count_during_postselection(circuit: stim.Circuit) -> int: + circuit = circuit.without_noise() + start = 0 + end = 0 + for k, instruction in enumerate(circuit): + if isinstance(instruction, stim.CircuitInstruction): + if instruction.name == "QUBIT_COORDS": + start = k + 1 + elif instruction.name == "DETECTOR": + args = instruction.gate_args_copy() + if len(args) >= 4 and args[3] == 999: + end = k + 1 + used_qubits = set() + + def process(sub_circuit: stim.Circuit): + for inst in sub_circuit: + if isinstance(inst, stim.CircuitRepeatBlock): + process(inst.body_copy()) + else: + for t in inst.targets_copy(): + if t.is_qubit_target: + used_qubits.add(t.value) + + process(circuit[start:end]) + return len(used_qubits) + + +def write_file(path: str | pathlib.Path, content: Any): + if isinstance(content, bytes): + with open(path, "wb") as f: + print(content, file=f) + else: + with open(path, "w") as f: + print(content, file=f) + print(f"wrote file://{pathlib.Path(path).absolute()}", file=sys.stderr) diff --git a/src/gen/_util_test.py b/src/gen/_util_test.py new file mode 100644 index 0000000..2aa69d5 --- /dev/null +++ b/src/gen/_util_test.py @@ -0,0 +1,93 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import stim + +from gen._util import estimate_qubit_count_during_postselection + + +def test_estimate_qubit_count_during_postselection(): + assert ( + estimate_qubit_count_during_postselection( + stim.Circuit( + """ + QUBIT_COORDS(0, 0) 100 + H 55 + M 55 + """ + ) + ) + == 0 + ) + + assert ( + estimate_qubit_count_during_postselection( + stim.Circuit( + """ + QUBIT_COORDS(0, 0) 100 + H 55 + M 55 + DETECTOR(0, 0, 0, 999) rec[-1] + """ + ) + ) + == 1 + ) + + assert ( + estimate_qubit_count_during_postselection( + stim.Circuit( + """ + QUBIT_COORDS(0, 0) 100 + H 55 56 + M 55 + DETECTOR(0, 0, 0, 999) rec[-1] + """ + ) + ) + == 2 + ) + + assert ( + estimate_qubit_count_during_postselection( + stim.Circuit( + """ + QUBIT_COORDS(0, 0) 100 + H 55 56 + M 55 + DETECTOR(0, 0, 0, 999) rec[-1] + H 57 + """ + ) + ) + == 2 + ) + + assert ( + estimate_qubit_count_during_postselection( + stim.Circuit( + """ + QUBIT_COORDS(0, 0) 100 + H 55 56 + M 55 + REPEAT 10 { + H 58 + } + DETECTOR(0, 0, 0, 999) rec[-1] + H 57 + """ + ) + ) + == 3 + ) diff --git a/src/gen/_viz_circuit_html.py b/src/gen/_viz_circuit_html.py new file mode 100644 index 0000000..076ce6f --- /dev/null +++ b/src/gen/_viz_circuit_html.py @@ -0,0 +1,832 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import base64 +import collections +import dataclasses +import math +import random +import sys +from typing import Iterable + +import stim + +from gen._core._patch import Patch + +PITCH = 48 * 2 +DIAM = 32 +RAD = DIAM / 2 +NOISY_GATES = { + "X_ERROR", + "Y_ERROR", + "Z_ERROR", + "E", + "ELSE_CORRELATED_ERROR", + "DEPOLARIZE1", + "DEPOLARIZE2", +} + + +def rand_color() -> str: + color = "#" + for _ in range(6): + color += "0123456789abcdef"[random.randint(0, 15)] + return color + + +MEASUREMENT_NAMES = {"M", "MX", "MY", "MR", "MRX", "MRY"} + + +@dataclasses.dataclass +class GateStyle: + label: str + fill_color: str + text_color: str + + +def _init_gate_box_labels() -> dict[str, GateStyle]: + result = {"I": GateStyle(label="I", fill_color="white", text_color="gray")} + for name in ["X", "Y", "Z"]: + result[name] = GateStyle(label=name, fill_color="white", text_color="black") + for name in ["R", "M", "RX", "RY", "MX", "MY", "MR", "MRX", "MRY"]: + result[name] = GateStyle(label=name, fill_color="black", text_color="white") + for key in [ + "H", + "H_YZ", + "H_XY", + "S", + "SQRT_X", + "SQRT_Y", + "S_DAG", + "SQRT_X_DAG", + "SQRT_Y_DAG", + ]: + name = key.replace("SQRT_", "√") + name = name.replace("_DAG", "⁻¹") + a, b = name.split("_") if "_" in name else (name, "") + result[key] = GateStyle( + label=a + b.lower(), fill_color="yellow", text_color="black" + ) + for name in ["C_XYZ", "C_ZYX"]: + result[name] = GateStyle( + label=name[0] + name[2:].lower(), fill_color="teal", text_color="black" + ) + return result + + +GATE_BOX_LABELS = _init_gate_box_labels() +TWO_QUBIT_GATE_STYLES = { + "CX": ("Z", "X"), + "CY": ("Z", "Y"), + "CZ": ("Z", "Z"), + "XCX": ("X", "X"), + "XCY": ("X", "Y"), + "XCZ": ("X", "Z"), + "YCX": ("Y", "X"), + "YCY": ("Y", "Y"), + "YCZ": ("Y", "Z"), + "SQRT_XX": ("SQRT_XX", "SQRT_XX"), + "SQRT_XX_DAG": ("SQRT_XX", "SQRT_XX"), + "SQRT_YY": ("SQRT_YY", "SQRT_YY"), + "SQRT_YY_DAG": ("SQRT_YY", "SQRT_YY"), + "SQRT_ZZ": ("SQRT_ZZ", "SQRT_ZZ"), + "SQRT_ZZ_DAG": ("SQRT_ZZ", "SQRT_ZZ"), + "ISWAP": ("ISWAP", "ISWAP"), + "ISWAP_DAG": ("ISWAP", "ISWAP"), + "SWAP": ("SWAP", "SWAP"), + "CXSWAP": ("ZSWAP", "XSWAP"), + "SWAPCX": ("XSWAP", "ZSWAP"), +} + + +def tag_str(tag, *, content: bool | str = False, **kwargs) -> str: + parts = [f"<{tag}"] + for k, v in kwargs.items(): + parts.append(f"{k.replace('_', '-')}={str(v)!r}") + instr = " ".join(parts) + if not content: + instr += " />" + elif isinstance(content, str): + instr += f">{content}" + elif content is True: + instr += ">" + else: + raise NotImplementedError(repr(content)) + + return instr + + +class _SvgLayer: + def __init__(self): + self.svg_instructions: list[str] = [] + self.q2i_dict: dict[int, tuple[float, float]] = {} + self.used_indices: set[int] = set() + self.used_positions: set[tuple[float, float]] = set() + self.measurement_positions: dict[int, tuple[float, float]] = {} + + def add(self, tag, *, content: bool | str = False, **kwargs) -> None: + self.svg_instructions.append(" " + tag_str(tag, content=content, **kwargs)) + + def bounds(self) -> tuple[float, float, float, float]: + min_y = min(e for _, e in self.used_positions) + max_y = max(e for _, e in self.used_positions) + min_x = min(e for e, _ in self.used_positions) + max_x = max(e for e, _ in self.used_positions) + min_x -= PITCH + min_y -= PITCH + max_x += PITCH + max_y += PITCH + return min_x, min_y, max_x, max_y + + def add_idles(self, all_used_positions: set[tuple[float, float]]): + for x, y in all_used_positions - self.used_positions: + self.add("circle", cx=x, cy=y, r=5, fill="gray", stroke="black") + self.used_positions |= all_used_positions + min_x, min_y, max_x, max_y = self.bounds() + xs = {e for e, _ in self.used_positions} + ys = {e for _, e in self.used_positions} + for x in xs: + x2 = x + x2 /= PITCH + if x2 == int(x2): + x2 = int(x2) + self.add( + "text", + x=x, + y=max_y - 5, + fill="black", + content=str(x2), + text_anchor="middle", + dominant_baseline="auto", + font_size=24, + ) + for y in ys: + y2 = y + y2 /= PITCH + if y2 == int(y2): + y2 = int(y2) + self.add( + "text", + x=min_x + 5, + y=y, + fill="black", + content=str(y2), + text_anchor="left", + alignment_baseline="middle", + font_size=24, + ) + + def svg( + self, + *, + html_id: str | None = None, + as_img_with_data_uri: bool = False, + width: int, + height: int, + ) -> str: + min_x, min_y, max_x, max_y = self.bounds() + kwargs = {} if html_id is None or as_img_with_data_uri else {"id": html_id} + svg = "\n".join( + [ + tag_str( + "svg", + xmlns="http://www.w3.org/2000/svg", + viewBox=f"{min_x} {min_y} {max_x - min_x} {max_y - min_y}", + content=True, + **kwargs, + ), + *self.svg_instructions, + "", + ] + ) + if as_img_with_data_uri: + kwargs = {} if html_id is None else {"id": html_id} + svg = tag_str( + "img", + width=width, + height=height, + **kwargs, + src="data:image/svg+xml;base64," + + base64.standard_b64encode(svg.encode("utf-8")).decode("utf-8"), + ) + svg = svg.replace("/>", ">") + return svg + + +class _SvgState: + def __init__(self): + self.layers: list[_SvgLayer] = [_SvgLayer()] + self.coord_shift: list[int] = [0, 0] + self.measurement_layer_indices: list[int] = [] + self.detector_index = 0 + self.detector_coords = {} + self.measurement_marks = collections.Counter() + self.highlighted_detectors = set() + self.highlighted_errors: list[tuple[int, int, str]] = [] + self.flipped_measurements: set[int] = set() + self.noted_errors: list[tuple[int, int, str]] = [] + self.control_count = 0 + + def tick(self) -> None: + self.layers.append(_SvgLayer()) + self.layers[-1].q2i_dict = dict(self.layers[-2].q2i_dict) + + def q2i(self, i: int) -> tuple[float, float]: + x, y = self.layers[-1].q2i_dict.setdefault(i, (i, 0)) + pt = x * PITCH, y * PITCH + self.layers[-1].used_indices.add(i) + self.layers[-1].used_positions.add(pt) + return pt + + def are_adjacent(self, q1: stim.GateTarget, q2: stim.GateTarget) -> bool: + if q1.is_qubit_target and q2.is_qubit_target: + x1, y1 = self.layers[-1].q2i_dict.setdefault(q1.value, (q1.value, 0)) + x2, y2 = self.layers[-1].q2i_dict.setdefault(q2.value, (q2.value, 0)) + if abs(x2 - x1) + abs(y2 - y1) < 1.5: + return True + return False + + def add(self, tag, *, content="", **kwargs) -> None: + self.layers[-1].add(tag, content=content, **kwargs) + + def add_box( + self, x: float, y: float, text: str, *, fill="white", text_color="black" + ): + self.add( + "rect", + x=x - RAD, + y=y - RAD, + width=DIAM, + height=DIAM, + fill=fill, + stroke="black", + ) + self.add( + "text", + x=x, + y=y, + fill=text_color, + content=text, + font_size=32 if len(text) == 1 else 24 if len(text) == 2 else 18, + text_anchor="middle", + alignment_baseline="central", + ) + + def add_measurement(self, target: stim.GateTarget) -> None: + assert ( + target.is_qubit_target + or target.is_x_target + or target.is_y_target + or target.is_z_target + ) + m_index = len(self.measurement_layer_indices) + self.measurement_layer_indices.append(len(self.layers) - 1) + self.layers[-1].measurement_positions[m_index] = self.q2i(target.value) + + def mark_measurements( + self, targets: list[stim.GateTarget], prefix: str, index: int | None + ) -> None: + if index is None: + assert prefix == "D" + index = self.detector_index + self.detector_index += 1 + if prefix == "D": + color = "black" + if index in self.highlighted_detectors: + color = "red" + elif prefix == "L": + color = "blue" + elif prefix == "C": + color = "green" + else: + color = "black" + name = f"{prefix}{index}" + for t in targets: + m_index = len(self.measurement_layer_indices) + t.value + if m_index < 0: + print( + "Attempted to mark a measurement before the beginning of time.\n" + "Skipping this mark.", + file=sys.stderr, + ) + continue + assert m_index >= 0, m_index + assert t.is_measurement_record_target + layer = self.layers[self.measurement_layer_indices[m_index]] + x, y = layer.measurement_positions[m_index] + x += RAD + 1 + y -= RAD + y += self.measurement_marks[m_index] * 15 + self.measurement_marks[m_index] += 1 + layer.add( + "text", + x=x, + y=y, + fill=color, + content=name, + text_anchor="left", + alignment_baseline="hanging", + font_size=16, + ) + + +def _draw_endpoint(x: float, y: float, style: str, *, out: _SvgState) -> None: + add = out.add + if style == "X": + add("circle", cx=x, cy=y, r=RAD, stroke="black", fill="white") + add("line", x1=x - RAD, x2=x + RAD, y1=y, y2=y, stroke="black") + add("line", x1=x, x2=x, y1=y - RAD, y2=y + RAD, stroke="black") + elif style == "Y": + s = 0.5**0.5 + add("circle", cx=x, cy=y, r=RAD, stroke="black", fill="white") + add("line", x1=x, x2=x, y1=y, y2=y + RAD, stroke="black") + add("line", x1=x, x2=x - RAD * s, y1=y, y2=y - RAD * s, stroke="black") + add("line", x1=x, x2=x + RAD * s, y1=y, y2=y - RAD * s, stroke="black") + elif style == "Z": + add("circle", cx=x, cy=y, r=RAD, fill="black") + elif style == "SWAP": + r = RAD / 3 + add("line", x1=x - r, x2=x + r, y1=y - r, y2=y + r, stroke="black") + add("line", x1=x - r, x2=x + r, y1=y + r, y2=y - r, stroke="black") + elif style == "ISWAP": + r = RAD + add("circle", cx=x, cy=y, r=RAD / 2, fill="gray") + add("line", x1=x - r, x2=x + r, y1=y - r, y2=y + r, stroke="black") + add("line", x1=x - r, x2=x + r, y1=y + r, y2=y - r, stroke="black") + elif style == "SQRT_ZZ": + out.add_box(x=x, y=y, text="√ZZ") + elif style == "SQRT_YY": + out.add_box(x=x, y=y, text="√YY") + elif style == "SQRT_XX": + out.add_box(x=x, y=y, text="√XX") + elif style == "XSWAP": + r = RAD * 0.4 + add("circle", cx=x, cy=y, r=RAD, fill="white", stroke="black") + add( + "line", + x1=x - r, + x2=x + r, + y1=y - r, + y2=y + r, + stroke="black", + stroke_width=5, + ) + add( + "line", + x1=x - r, + x2=x + r, + y1=y + r, + y2=y - r, + stroke="black", + stroke_width=5, + ) + elif style == "ZSWAP": + r = RAD * 0.4 + add("circle", cx=x, cy=y, r=RAD, fill="black", stroke="black") + add( + "line", + x1=x - r, + x2=x + r, + y1=y - r, + y2=y + r, + stroke="white", + stroke_width=5, + ) + add( + "line", + x1=x - r, + x2=x + r, + y1=y + r, + y2=y - r, + stroke="white", + stroke_width=5, + ) + else: + raise NotImplementedError(style) + + +def _draw_2q(instruction: stim.CircuitInstruction, *, out: _SvgState) -> None: + style1, style2 = TWO_QUBIT_GATE_STYLES[instruction.name] + targets = instruction.targets_copy() + q2i = out.q2i + + assert len(targets) % 2 == 0 + for k in range(0, len(targets), 2): + t1 = targets[k] + t2 = targets[k + 1] + if t1.is_measurement_record_target or t2.is_measurement_record_target: + if t1.is_qubit_target: + t = t1.value + m = t2 + elif t2.is_qubit_target: + t = t2.value + m = t1 + else: + continue + b = ( + "X" + if instruction.name in ["XCZ", "CX"] + else "Y" + if instruction.name in ["YCZ", "CY"] + else "Z" + if instruction.name == "CZ" + else "?" + ) + x, y = q2i(t) + out.add( + "text", + x=x - RAD + 1, + y=y, + fill="green", + content=b, + font_size=18, + text_anchor="left", + alignment_baseline="central", + ) + out.add( + "text", + x=x - 1, + y=y - RAD / 2, + fill="green", + content=f"C{out.control_count}", + font_size=8, + text_anchor="left", + alignment_baseline="central", + ) + out.mark_measurements([m], prefix="C", index=out.control_count) + out.control_count += 1 + continue + assert t1.is_qubit_target + assert t2.is_qubit_target + x1, y1 = q2i(t1.value) + x2, y2 = q2i(t2.value) + dx = x2 - x1 + dy = y2 - y1 + r = (dx * dx + dy * dy) ** 0.5 + px = dy + py = -dx + px *= 25 / r + py *= 25 / r + cx1 = dx / 10 + px + cy1 = dy / 10 + py + cx2 = dx - dx / 10 + px + cy2 = dy - dy / 10 + py + + if out.are_adjacent(t1, t2): + out.add("line", x1=x1, x2=x2, y1=y1, y2=y2, stroke="black") + else: + out.add( + "path", + d=f"M {x1},{y1} c {cx1},{cy1} {cx2},{cy2} {dx},{dy}", + stroke="black", + fill="none", + ) + + _draw_endpoint(x1, y1, style1, out=out) + _draw_endpoint(x2, y2, style2, out=out) + + +def _draw_mpp(instruction: stim.CircuitInstruction, *, out: _SvgState) -> None: + targets = instruction.targets_copy() + add = out.add + add_box = out.add_box + q2i = out.q2i + + chunks = [] + start = 0 + end = 1 + while start < len(targets): + while end < len(targets) and targets[end].is_combiner: + end += 2 + chunks.append(targets[start:end:2]) + start = end + end = start + 1 + for chunk in chunks: + out.add_measurement(chunk[0]) + tx, ty = 0, 0 + for t in chunk: + x, y = q2i(t.value) + tx += x + ty += y + tx /= len(chunk) + ty /= len(chunk) + color = rand_color() + no_text = False + if all(t.is_x_target for t in chunk): + color = "red" + no_text = True + if all(t.is_y_target for t in chunk): + color = "green" + no_text = True + if all(t.is_z_target for t in chunk): + color = "blue" + no_text = True + for t in chunk: + x, y = q2i(t.value) + add("line", x1=x, x2=tx, y1=y, y2=ty, stroke=color, stroke_width=8) + for k, c in enumerate(chunk): + if c.is_x_target: + text = "PX" + elif c.is_y_target: + text = "PY" + elif c.is_z_target: + text = "PZ" + else: + raise NotImplementedError(repr(c)) + x, y = q2i(c.value) + add_box(x, y, text * (1 - int(no_text)), fill=color) + + +def _draw_1q(instruction: stim.CircuitInstruction, *, out: _SvgState): + targets = instruction.targets_copy() + if instruction.name in MEASUREMENT_NAMES: + for t in targets: + out.add_measurement(t) + for t in targets: + assert t.is_qubit_target + x, y = out.q2i(t.value) + style = GATE_BOX_LABELS[instruction.name] + out.add_box( + x, y, style.label, fill=style.fill_color, text_color=style.text_color + ) + + +def _stim_circuit_to_svg_helper(circuit: stim.Circuit, state: _SvgState) -> None: + for instruction in circuit: + if isinstance(instruction, stim.CircuitRepeatBlock): + body = instruction.body_copy() + for _ in range(instruction.repeat_count): + _stim_circuit_to_svg_helper(body, state) + elif isinstance(instruction, stim.CircuitInstruction): + targets: list[stim.GateTarget] = instruction.targets_copy() + if instruction.name == "QUBIT_COORDS": + pos = instruction.gate_args_copy() + for t in instruction.targets_copy(): + assert t.is_qubit_target + if len(pos) == 1: + pos = (pos[0], 0) + state.layers[-1].q2i_dict[t.value] = ( + pos[0] + state.coord_shift[0], + pos[1] + state.coord_shift[1], + ) + elif instruction.name == "SHIFT_COORDS": + pos = instruction.gate_args_copy() + if len(pos) >= 1: + state.coord_shift[0] += pos[0] + if len(pos) >= 2: + state.coord_shift[1] += pos[1] + elif instruction.name in GATE_BOX_LABELS: + _draw_1q(instruction, out=state) + elif instruction.name in TWO_QUBIT_GATE_STYLES: + _draw_2q(instruction, out=state) + elif instruction.name == "TICK": + state.tick() + elif instruction.name == "MPP": + _draw_mpp(instruction, out=state) + elif instruction.name == "DETECTOR": + state.mark_measurements(targets, prefix="D", index=None) + elif instruction.name == "OBSERVABLE_INCLUDE": + state.mark_measurements( + targets, prefix="L", index=int(instruction.gate_args_copy()[0]) + ) + elif instruction.name in NOISY_GATES: + for t in instruction.targets_copy(): + state.noted_errors.append((t.value, len(state.layers) - 1, "E")) + else: + raise NotImplementedError(repr(instruction)) + else: + raise NotImplementedError(repr(instruction)) + + +def append_patch_polygons(*, out: list[str], patch: Patch, q2i: dict[complex, int]): + for e in patch.tiles: + if e.basis == "X": + r, g, b = (1, 0, 0) + elif e.basis == "Y": + r, g, b = (0, 1, 0) + elif e.basis == "Z": + r, g, b = (0, 0, 1) + else: + r, g, b = (1, 1, 0) + qs = [q for q in e.ordered_data_qubits if q is not None] + c = e.measurement_qubit + if any(abs(q - c) < 1e-4 for q in e.data_set): + c = sum(e.data_set) / len(e.data_set) + qs = sorted(qs, key=lambda q: math.atan2(q.imag - c.imag, q.real - c.real)) + alpha = 0.75 if len(qs) == 2 else 0.5 + line = f"POLYGON({r},{g},{b},{alpha})" + for q in qs: + line += f"_{q2i.get(q, 0)}" + out.append(line) + + +def stim_circuit_html_viewer( + circuit: stim.Circuit, + *, + patch: None | Patch | dict[int, Patch] = None, + width: int = 500, + height: int = 500, + known_error: Iterable[stim.ExplainedError] | None = None, +) -> str: + q2i = { + v[0] + 1j * v[1]: k for k, v in circuit.get_final_qubit_coordinates().items() + } + + state = _SvgState() + state.detector_coords = circuit.get_detector_coordinates() + if known_error is None: + # noinspection PyBroadException + try: + known_error = circuit.shortest_graphlike_error( + ignore_ungraphlike_errors=True, + canonicalize_circuit_errors=True, + ) + except Exception: + pass + if known_error is not None: + for product in known_error: + loc = next(iter(product.circuit_error_locations)) + for flipped in loc.flipped_pauli_product: + if flipped.gate_target.is_x_target: + b = "X" + elif flipped.gate_target.is_y_target: + b = "Y" + elif flipped.gate_target.is_z_target: + b = "Z" + else: + raise NotImplementedError(repr(loc)) + state.highlighted_errors.append( + (flipped.gate_target.value, loc.tick_offset, b) + ) + if loc.flipped_measurement is not None: + state.flipped_measurements.add(loc.flipped_measurement.record_index) + for term in product.dem_error_terms: + target = term.dem_target + if target.is_relative_detector_id(): + state.highlighted_detectors.add(target.val) + + _stim_circuit_to_svg_helper(circuit, state) + all_pos = {pt for layer in state.layers for pt in layer.used_positions} + for layer in state.layers: + layer.add_idles(all_pos) + + for m in state.flipped_measurements: + layer = state.layers[state.measurement_layer_indices[m]] + x, y = layer.measurement_positions[m] + layer.add( + "rect", + x=x - RAD, + y=y - RAD, + width=DIAM, + height=DIAM, + fill="#FF000080", + stroke="#FF0000", + ) + for qubit, time, basis in state.highlighted_errors: + layer = state.layers[time] + x, y = state.q2i(qubit) + layer.add( + "text", + x=x, + y=y, + fill="red", + content=basis, + text_anchor="middle", + dominant_baseline="middle", + font_size=64, + ) + for qubit, time, basis in set(state.noted_errors): + if time >= len(state.layers): + print(f"Error time is past end of circuit: {time}", file=sys.stderr) + continue + layer = state.layers[time] + x, y = state.q2i(qubit) + layer.add( + "text", + x=x - RAD, + y=y, + fill="red", + content=basis, + text_anchor="end", + dominant_baseline="middle", + font_size=12, + ) + + svg_image_tags = [] + for k, layer in enumerate(state.layers): + svg = layer.svg(html_id=f"layer{k}", width=width, height=height) + data = base64.standard_b64encode(svg.encode("utf-8")).decode("utf-8") + svg_image_tags.append( + f'' + ) + all_svg_image_tags = "\n".join(svg_image_tags) + + flattened = circuit.flattened() + circuit_coords = [str(inst) for inst in flattened if inst.name == "QUBIT_COORDS"] + if isinstance(patch, Patch): + patch = {0: patch} + if patch is None: + patch = {} + tick = 0 + circuit_rest = [] + for inst in flattened: + if tick in patch: + append_patch_polygons(out=circuit_rest, patch=patch[tick], q2i=q2i) + circuit_rest.append("TICK") + tick += 1 + if inst.name == "TICK": + tick += 1 + if inst.name != "QUBIT_COORDS": + circuit_rest.append(str(inst)) + max_patch_tick = max(patch.keys(), default=0) + while tick <= max_patch_tick: + if tick in patch: + circuit_rest.append("TICK") + append_patch_polygons(out=circuit_rest, patch=patch[tick], q2i=q2i) + tick += 1 + + escaped = ";".join(circuit_coords + circuit_rest) + escaped = escaped.replace(", ", ",").replace(" ", "_") + escaped = escaped.replace("QUBIT_COORDS", "Q") + escaped = escaped.replace("DETECTOR", "DT") + escaped = escaped.replace("(", "%28").replace(")", "%29") + escaped = escaped.replace("[", "%5B").replace("]", "%5D") + local_server_crumble_url = f"""https://algassert.com/crumble#circuit={escaped}""" + + return ( + f"""
Loading...
+ + + Open in Crumble +
+ """ + + all_svg_image_tags + + """ +
+""" + ) diff --git a/src/gen/_viz_patch_svg.py b/src/gen/_viz_patch_svg.py new file mode 100644 index 0000000..7cb23bd --- /dev/null +++ b/src/gen/_viz_patch_svg.py @@ -0,0 +1,676 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import math +from typing import Iterable, Union, Literal, TYPE_CHECKING, Sequence, Callable + +from gen._core._patch import Patch, Tile +from gen._core._util import min_max_complex + +if TYPE_CHECKING: + import gen + + +def is_colinear(a: complex, b: complex, c: complex) -> bool: + d1 = b - a + d2 = c - a + return abs(d1.real * d2.imag - d2.real * d1.imag) < 1e-4 + + +def _path_commands_for_points_with_one_point( + *, + a: complex, + draw_coord: Callable[[complex], complex], + draw_radius: float | None = None, +): + draw_a = draw_coord(a) + if draw_radius is None: + draw_radius = abs(draw_coord(0.2) - draw_coord(0)) + r = draw_radius + left = draw_a - draw_radius + return [ + f"""M {left.real},{left.imag}""", + f"""a {r},{r} 0 0,0 {2*r},{0}""", + f"""a {r},{r} 0 0,0 {-2*r},{0}""", + ] + + +def _path_commands_for_points_with_two_points( + *, + a: complex, + b: complex, + hint_point: complex, + draw_coord: Callable[[complex], complex], +) -> list[str]: + def transform_dif(d: complex) -> complex: + return draw_coord(d) - draw_coord(0) + + da = a - hint_point + db = b - hint_point + angle = math.atan2(da.imag, da.real) - math.atan2(db.imag, db.real) + angle %= math.pi * 2 + if angle < math.pi: + a, b = b, a + + if abs(abs(da) - abs(db)) < 1e-4 < abs(da + db): + # Semi-circle oriented towards measure qubit. + draw_a = draw_coord(a) + draw_ba = transform_dif(b - a) + return [ + f"""M {draw_a.real},{draw_a.imag}""", + f"""a 1,1 0 0,0 {draw_ba.real},{draw_ba.imag}""", + f"""L {draw_a.real},{draw_a.imag}""", + ] + else: + # A wedge between the two data qubits. + dif = b - a + average = (a + b) * 0.5 + perp = dif * 1j + if abs(perp) > 1: + perp /= abs(perp) + ac1 = average + perp * 0.2 - dif * 0.2 + ac2 = average + perp * 0.2 + dif * 0.2 + bc1 = average + perp * -0.2 + dif * 0.2 + bc2 = average + perp * -0.2 - dif * 0.2 + + tac1 = draw_coord(ac1) + tac2 = draw_coord(ac2) + tbc1 = draw_coord(bc1) + tbc2 = draw_coord(bc2) + draw_a = draw_coord(a) + draw_b = draw_coord(b) + return [ + f"M {draw_a.real},{draw_a.imag}", + f"C {tac1.real} {tac1.imag}, {tac2.real} {tac2.imag}, {draw_b.real} {draw_b.imag}", + f"C {tbc1.real} {tbc1.imag}, {tbc2.real} {tbc2.imag}, {draw_a.real} {draw_a.imag}", + ] + + +def _path_commands_for_points_with_many_points( + *, + pts: Sequence[complex], + draw_coord: Callable[[complex], complex], +) -> list[str]: + assert len(pts) >= 3 + ori = draw_coord(pts[-1]) + path_commands = [f"""M{ori.real},{ori.imag}"""] + for k in range(len(pts)): + prev_prev_q = pts[k - 2] + prev_q = pts[k - 1] + q = pts[k] + next_q = pts[(k + 1) % len(pts)] + if (is_colinear(prev_q, q, next_q) or is_colinear(prev_prev_q, prev_q, q)): + prev_pt = draw_coord(prev_q) + cur_pt = draw_coord(q) + d = cur_pt - prev_pt + p1 = prev_pt + d * (-0.25 + 0.05j) + p2 = cur_pt + d * (0.25 + 0.05j) + path_commands.append( + f"""C {p1.real} {p1.imag}, {p2.real} {p2.imag}, {cur_pt.real} {cur_pt.imag}""" + ) + else: + q2 = draw_coord(q) + path_commands.append(f"""L {q2.real},{q2.imag}""") + return path_commands + + +def svg_path_directions_for_tile( + *, tile: "gen.Tile", draw_coord: Callable[[complex], complex] +) -> str | None: + hint_point = tile.measurement_qubit + if any(abs(q - hint_point) < 1e-4 for q in tile.data_set): + hint_point = sum(tile.data_set) / len(tile.data_set) + + points = sorted( + tile.data_set, + key=lambda p2: math.atan2(p2.imag - hint_point.imag, p2.real - hint_point.real), + ) + + if len(points) == 0: + return None + + if len(points) == 1: + return " ".join( + _path_commands_for_points_with_one_point( + a=points[0], + draw_coord=draw_coord, + ) + ) + + if len(points) == 2: + return " ".join( + _path_commands_for_points_with_two_points( + a=points[0], + b=points[1], + hint_point=hint_point, + draw_coord=draw_coord, + ) + ) + + return " ".join( + _path_commands_for_points_with_many_points( + pts=points, + draw_coord=draw_coord, + ) + ) + + +BASE_COLORS = {"X": "#FF8080", "Z": "#8080FF", "Y": "#80FF80", None: "gray"} + + +def _data_span_sort(tile: "gen.Tile") -> float: + min_c, max_c = min_max_complex(tile.data_set, default=0) + return max_c.real - min_c.real + max_c.imag - min_c.imag + + +def _patch_svg_viewer_helper_single_patch_wraparound_clip( + *, + patch: Patch, + transform_pt: Callable[[complex], complex], + out_lines: list[str], + show_order: str, + opacity: float, + show_data_qubits: bool, + show_measure_qubits: bool, + available_qubits: frozenset[complex], + extra_used_coords: frozenset[complex], + clip_path_id_ptr: list[int], +): + if len(patch.without_wraparound_tiles().tiles) == len(patch.tiles): + _patch_svg_viewer_helper_single_patch( + patch=patch, + transform_pt=transform_pt, + out_lines=out_lines, + show_order=show_order, + opacity=opacity, + show_data_qubits=show_data_qubits, + show_measure_qubits=show_measure_qubits, + clip_path_id_ptr=clip_path_id_ptr, + available_qubits=available_qubits, + extra_used_coords=extra_used_coords, + ) + return + + p_min, p_max = min_max_complex(patch.data_set, default=0) + w = p_max.real - p_min.real + h = p_max.imag - p_min.imag + left = p_min.real + w * 0.1 + right = p_min.real + w * 0.9 + top = p_min.imag + h * 0.1 + bot = p_min.imag + h * 0.9 + pad_w = 1 + pad_h = 1 + pad_shift = -pad_w - 1j*pad_h + pad_shift /= 2 + w += pad_w + h += pad_h + def new_transform(q: complex) -> complex: + q -= p_min + q /= (p_max - p_min).real + q *= w + q += p_min + return transform_pt(q) + + def is_normal_tile(tile: Tile) -> bool: + t_min, t_max = min_max_complex(tile.data_set, default=0) + if t_min.real < left and t_max.real > right: + return False + if t_min.imag < top and t_max.imag > bot: + return False + return True + + def unwraparound(tile: Tile): + t_min, t_max = min_max_complex(tile.data_set, default=0) + dw = w + dh = h + if not (t_min.real < left and t_max.real > right): + dw = 0 + if not (t_min.imag < top and t_max.imag > bot): + dh = 0 + def trans(q: complex) -> complex: + if q.real < w / 2: + q += dw + if q.imag < h / 2: + q += dh*1j + return q + return trans + + new_tiles = [] + for tile in patch.tiles: + if is_normal_tile(tile): + new_tiles.append(tile) + continue + new_tile_1 = tile.with_transformed_coords(unwraparound(tile)) + new_tile_2 = new_tile_1.with_transformed_coords(lambda q: q - w) + new_tile_3 = new_tile_1.with_transformed_coords(lambda q: q - h*1j) + new_tile_4 = new_tile_1.with_transformed_coords(lambda q: q - w - h*1j) + new_tiles.append(new_tile_1) + new_tiles.append(new_tile_2) + new_tiles.append(new_tile_3) + new_tiles.append(new_tile_4) + + clip_ip = clip_path_id_ptr[0] + clip_path_id_ptr[0] += 1 + out_lines.append(f'''''') + tl = transform_pt(p_min) + br = transform_pt(p_max) + out_lines.append(f''' ''') + out_lines.append(f'''''') + _patch_svg_viewer_helper_single_patch( + patch=Patch(new_tiles).with_transformed_coords(lambda q: q + pad_shift), + transform_pt=new_transform, + out_lines=out_lines, + show_order=show_order, + opacity=opacity, + show_data_qubits=show_data_qubits, + show_measure_qubits=show_measure_qubits, + clip_path_id_ptr=clip_path_id_ptr, + available_qubits=frozenset([q + pad_shift for q in available_qubits]), + extra_used_coords=frozenset([q + pad_shift for q in extra_used_coords]), + extra_clip_path_arg=f'clip-path="url(#clipPath{clip_ip})" ', + ) + + +def _patch_svg_viewer_helper_single_patch( + *, + patch: Patch, + transform_pt: Callable[[complex], complex], + out_lines: list[str], + show_order: str, + opacity: float, + show_data_qubits: bool, + show_measure_qubits: bool, + clip_path_id_ptr: list[int], + available_qubits: frozenset[complex], + extra_used_coords: frozenset[complex], + extra_clip_path_arg: str = '', +): + layer_1q2 = [] + layer_1q = [] + fill_layer2q = [] + stroke_layer2q = [] + fill_layer_mq = [] + stroke_layer_mq = [] + stroke_width = abs(transform_pt(0.02) - transform_pt(0)) + + sorted_tiles = sorted(patch.tiles, key=_data_span_sort, reverse=True) + for tile in sorted_tiles: + c = tile.measurement_qubit + if any(abs(q - c) < 1e-4 for q in tile.data_set): + c = sum(tile.data_set) / len(tile.data_set) + dq = sorted( + tile.data_set, + key=lambda p2: math.atan2(p2.imag - c.imag, p2.real - c.real), + ) + if not dq: + continue + common_basis = tile.basis + fill_color = BASE_COLORS[common_basis] + + path_directions = svg_path_directions_for_tile( + tile=tile, + draw_coord=transform_pt, + ) + path_cmd_start = None + if path_directions is not None: + if len(tile.data_set) == 1: + fl = layer_1q + sl = layer_1q2 + elif len(tile.data_set) == 2: + fl = fill_layer2q + sl = stroke_layer2q + else: + fl = fill_layer_mq + sl = stroke_layer_mq + fl.append( + f'''""" + + ) + + # # Draw lines from data qubits to measurement qubit. + # for d in tile.data_set: + # pd = transform_pt(d) + # pc = transform_pt(c) + # sl.append( + # f'''""" + # ) + + if show_order != "undirected": + sl.append( + f'''""" + ) + else: + cur_pt = transform_pt(dq[-1]) + path_cmd_start = f'' + ) + if show_order != "undirected": + stroke_layer_mq.append( + f"{path_cmd_start} " + f'stroke-width="{stroke_width}" ' + f'stroke="black" ' + f""" {extra_clip_path_arg} """ + f'fill="none" />' + ) + + if show_measure_qubits: + m = tile.measurement_qubit + if show_order == "undirected": + m = m * 0.8 + c * 0.2 + p = transform_pt(m) + layer_1q2.append( + f"""" + ) + if show_data_qubits: + for d in tile.data_set: + p = transform_pt(d) + layer_1q2.append( + f"""" + ) + + if common_basis is None and path_cmd_start is not None: + clip_path_id_ptr[0] += 1 + fill_layer_mq.append(f'') + fill_layer_mq.append(f" {path_cmd_start} />") + fill_layer_mq.append(f"") + for k, q in enumerate(tile.ordered_data_qubits): + if q is None: + continue + v = transform_pt(q) + fill_layer_mq.append( + f"' + ) + out_lines.extend(fill_layer_mq) + out_lines.extend(stroke_layer_mq) + out_lines.extend(fill_layer2q) + out_lines.extend(stroke_layer2q) + out_lines.extend(layer_1q) + out_lines.extend(layer_1q2) + + if available_qubits | extra_used_coords: + for q in available_qubits | (patch.used_set | extra_used_coords): + fill_color = "black" if q in available_qubits else "orange" + if ( + not show_measure_qubits + and not q in available_qubits + and q in patch.measure_set + ): + continue + q2 = transform_pt(q) + out_lines.append( + f"" + ) + + +def patch_svg_viewer( + patches: Iterable[Patch], + *, + canvas_height: int = 500, + show_order: Union[bool, Literal["undirected", "3couplerspecial"]] = True, + opacity: float = 1, + show_measure_qubits: bool = True, + show_data_qubits: bool = False, + available_qubits: Iterable[complex] = (), + extra_used_coords: Iterable[complex] = (), + wraparound_clip: bool = False, +) -> str: + """Returns a picture of the stabilizers measured by various plan.""" + + available_qubits = frozenset(available_qubits) + extra_used_coords = frozenset(extra_used_coords) + patches = tuple(patches) + min_c, max_c = min_max_complex( + [ + q + for plan in patches + for q in plan.used_set | available_qubits | extra_used_coords + ], + default=0, + ) + min_c -= 1 + 1j + max_c += 1 + 1j + box_width = max_c.real - min_c.real + box_height = max_c.imag - min_c.imag + pad = max(box_width, box_height) * 0.1 + 1 + box_width += pad + box_height += pad + columns = math.ceil(math.sqrt(len(patches) + 2)) + rows = math.ceil(len(patches) / max(1, columns)) + total_height = max(1.0, box_height * rows - pad) + total_width = max(1.0, box_width * columns + 1) + scale_factor = canvas_height / max(total_height + 1, 1) + canvas_width = int(math.ceil(canvas_height * (total_width / total_height))) + + def transform_pt(plan_i2: int, pt2: complex) -> complex: + pt2 += box_width * (plan_i2 % columns) + pt2 += box_height * (plan_i2 // columns) * 1j + pt2 += pad * (0.5 + 0.5j) + pt2 += pad + pt2 -= min_c + 1 + 1j + pt2 *= scale_factor + return pt2 + + def transform_dif(dif: complex) -> complex: + return dif * scale_factor + + def pt(plan_i2: int, q2: complex) -> str: + return f"{transform_pt(plan_i2, q2).real},{transform_pt(plan_i2, q2).imag}" + + lines = [ + f"""""" + ] + + # Draw each plan element as a polygon. + clip_path_id_ptr = [0] + + lines.append( + f'' + ) + lines.append( + "X" + ) + + lines.append( + f'' + ) + lines.append( + "Z" + ) + + helper = _patch_svg_viewer_helper_single_patch_wraparound_clip if wraparound_clip else _patch_svg_viewer_helper_single_patch + for plan_i, patch in enumerate(patches): + helper( + patch=patch, + transform_pt=lambda q: transform_pt(plan_i, q), + out_lines=lines, + show_order=show_order, + opacity=opacity, + show_data_qubits=show_data_qubits, + show_measure_qubits=show_measure_qubits, + clip_path_id_ptr=clip_path_id_ptr, + available_qubits=available_qubits, + extra_used_coords=extra_used_coords, + ) + + stroke_width = abs(transform_pt(0, 0.02) - transform_pt(0, 0)) + + # Draw each element's measurement order as a zig zag arrow. + assert show_order in [False, True, "3couplerspecial", "undirected"] + if show_order: + for plan_i, plan in enumerate(patches): + for tile in plan.tiles: + c = tile.measurement_qubit + if len(tile.data_set) == 3 or c in tile.data_set: + c = 0 + for q in tile.data_set: + c += q + c /= len(tile.data_set) + pts: list[complex] = [] + + path_cmd_start = f'' + ) + delay = 0 + prev = v + else: + delay += 1 + path_cmd_start = path_cmd_start.strip() + path_cmd_start += ( + f'" fill="none" ' + f'stroke-width="{stroke_width}" ' + f'stroke="{arrow_color}" />' + ) + lines.append(path_cmd_start) + + # Draw arrow at end of arrow. + if show_order is True and len(pts) > 1: + p = pts[-1] + d2 = p - pts[-2] + if d2: + d2 /= abs(d2) + d2 *= 4 * stroke_width + a = p + d2 + b = p + d2 * 1j + c = p + d2 * -1j + lines.append( + f"' + ) + if show_order == "3couplerspecial" and len(pts) > 2: + # Show location of measurement qubit. + p = transform_pt( + plan_i, tile.ordered_data_qubits[-2] * 0.6 + c * 0.4 + ) + lines.append( + f"' + ) + + # Frames + for outline_index, outline in enumerate(patches): + if wraparound_clip and len(outline.without_wraparound_tiles().tiles) < len(outline.tiles): + p_min, p_max = min_max_complex(outline.data_set, default=0) + a = transform_pt(outline_index, p_min) + b = transform_pt(outline_index, p_max) + else: + a = transform_pt(outline_index, min_c + 0.1j + 0.1) + b = transform_pt(outline_index, max_c - 0.1j - 0.1) + lines.append( + f'' + ) + + lines.append("") + return "\n".join(lines) diff --git a/src/gen/_viz_patch_svg_test.py b/src/gen/_viz_patch_svg_test.py new file mode 100644 index 0000000..5a47445 --- /dev/null +++ b/src/gen/_viz_patch_svg_test.py @@ -0,0 +1,121 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import gen + + +def test_patch_svg_exact(): + patch = gen.Patch( + tiles=[ + gen.Tile( + ordered_data_qubits=(None, 1j, None, 2j), + measurement_qubit=(-0.5 + 1.5j), + bases="Z", + ), + gen.Tile( + ordered_data_qubits=(None, 0j, None, (1 + 0j)), + measurement_qubit=(0.5 - 0.5j), + bases="X", + ), + gen.Tile( + ordered_data_qubits=(0j, (1 + 0j), 1j, (1 + 1j)), + measurement_qubit=(0.5 + 0.5j), + bases="Z", + ), + gen.Tile( + ordered_data_qubits=(1j, 2j, (1 + 1j), (1 + 2j)), + measurement_qubit=(0.5 + 1.5j), + bases="X", + ), + gen.Tile( + ordered_data_qubits=((1 + 0j), (1 + 1j), (2 + 0j), (2 + 1j)), + measurement_qubit=(1.5 + 0.5j), + bases="X", + ), + gen.Tile( + ordered_data_qubits=((1 + 1j), (2 + 1j), (1 + 2j), (2 + 2j)), + measurement_qubit=(1.5 + 1.5j), + bases="Z", + ), + gen.Tile( + ordered_data_qubits=((1 + 2j), None, (2 + 2j), None), + measurement_qubit=(1.5 + 2.5j), + bases="X", + ), + gen.Tile( + ordered_data_qubits=((2 + 0j), None, (2 + 1j), None), + measurement_qubit=(2.5 + 0.5j), + bases="Z", + ), + ] + ) + svg_content = gen.patch_svg_viewer([patch]) + assert ( + svg_content.strip() + == """ + + +X + +Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """.strip() + ) diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..009f3be --- /dev/null +++ b/src/main.cc @@ -0,0 +1,19 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chromobius/commands/main_all.h" + +int main(int argc, const char **argv) { + return chromobius::main(argc, argv); +} diff --git a/src/main.perf.cc b/src/main.perf.cc new file mode 100644 index 0000000..ce4304d --- /dev/null +++ b/src/main.perf.cc @@ -0,0 +1,187 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "chromobius/util.perf.h" +#include "stim.h" + +RegisteredBenchmark *running_benchmark = nullptr; +std::vector *all_registered_benchmarks_data = nullptr; +uint64_t registry_initialized = 0; + +/// Describe quantity as an SI-prefixed value with two significant figures. +std::string si2(double val) { + char unit = ' '; + if (val < 1) { + if (val < 1) { + val *= 1000; + unit = 'm'; + } + if (val < 1) { + val *= 1000; + unit = 'u'; + } + if (val < 1) { + val *= 1000; + unit = 'n'; + } + if (val < 1) { + val *= 1000; + unit = 'p'; + } + } else { + if (val > 1000) { + val /= 1000; + unit = 'k'; + } + if (val > 1000) { + val /= 1000; + unit = 'M'; + } + if (val > 1000) { + val /= 1000; + unit = 'G'; + } + if (val > 1000) { + val /= 1000; + unit = 'T'; + } + } + std::stringstream ss; + if (1 <= val && val < 10) { + ss << (size_t)val << '.' << ((size_t)(val * 10) % 10); + } else if (10 <= val && val < 100) { + ss << ' ' << (size_t)val; + } else if (100 <= val && val < 1000) { + ss << (size_t)(val / 10) * 10; + } else { + ss << val; + } + ss << ' ' << unit; + return ss.str(); +} + +static std::vector known_arguments{"--only", "--target_seconds"}; + +void find_benchmarks(const std::string &filter, std::vector &out) { + bool found = false; + + if (!filter.empty() && filter[filter.size() - 1] == '*') { + std::string start = filter.substr(0, filter.size() - 1); + for (const auto &benchmark : *all_registered_benchmarks_data) { + if (benchmark.name.substr(0, start.size()) == start) { + out.push_back(benchmark); + found = true; + } + } + } else { + for (const auto &benchmark : *all_registered_benchmarks_data) { + if (benchmark.name == filter) { + out.push_back(benchmark); + found = true; + } + } + } + + if (!found) { + std::cerr << "No benchmark matching filter '" << filter << "'. Available benchmarks are:\n"; + for (auto &benchmark : *all_registered_benchmarks_data) { + std::cerr << " " << benchmark.name << "\n"; + } + exit(EXIT_FAILURE); + } +} + +double BENCHMARK_CONFIG_TARGET_SECONDS = 0.5; + +int main(int argc, const char **argv) { + stim::check_for_unknown_arguments(known_arguments, {}, nullptr, argc, argv); + const char *only = stim::find_argument("--only", argc, argv); + BENCHMARK_CONFIG_TARGET_SECONDS = stim::find_float_argument("--target_seconds", 0.5, 0, 10000, argc, argv); + + std::vector chosen_benchmarks; + if (only == nullptr) { + chosen_benchmarks = *all_registered_benchmarks_data; + } else { + std::string filter_text = only; + std::vector filters{}; + size_t s = 0; + for (size_t k = 0;; k++) { + if (only[k] == ',' || only[k] == '\0') { + filters.push_back(filter_text.substr(s, k - s)); + s = k + 1; + } + if (only[k] == '\0') { + break; + } + } + + if (filters.empty()) { + std::cerr << "No filters specified.\n"; + exit(EXIT_FAILURE); + } + + for (const auto &filter : filters) { + find_benchmarks(filter, chosen_benchmarks); + } + } + + for (auto &benchmark : chosen_benchmarks) { + running_benchmark = &benchmark; + benchmark.func(); + for (const auto &result : benchmark.results) { + double actual_seconds_per_rep = result.total_seconds / result.total_reps; + if (result.goal_seconds != -1) { + int deviation = (int)round((log(result.goal_seconds) - log(actual_seconds_per_rep)) / (log(10) / 10.0)); + std::cout << "["; + for (int k = -20; k <= 20; k++) { + if ((k < deviation && k < 0) || (k > deviation && k > 0)) { + std::cout << '.'; + } else if (k == deviation) { + std::cout << '*'; + } else if (k == 0) { + std::cout << '|'; + } else if (deviation < 0) { + std::cout << '<'; + } else { + std::cout << '>'; + } + } + std::cout << "] "; + std::cout << si2(actual_seconds_per_rep) << "s"; + std::cout << " (vs " << si2(result.goal_seconds) << "s) "; + } else { + std::cout << si2(actual_seconds_per_rep) << "s "; + } + for (const auto &e : result.marginal_rates) { + const auto &multiplier = e.second; + const auto &unit = e.first; + std::cout << "(" << si2(result.total_reps / result.total_seconds * multiplier) << unit << "/s) "; + } + std::cout << benchmark.name << "\n"; + if (benchmark.results.empty()) { + std::cerr << "`benchmark_go` was not called from BENCH(" << benchmark.name << ")"; + exit(EXIT_FAILURE); + } + } + } + + if (all_registered_benchmarks_data != nullptr) { + delete all_registered_benchmarks_data; + all_registered_benchmarks_data = nullptr; + } + return 0; +} diff --git a/test_data/color2surface_d5_transit_p100.stim b/test_data/color2surface_d5_transit_p100.stim new file mode 100644 index 0000000..9d93b6e --- /dev/null +++ b/test_data/color2surface_d5_transit_p100.stim @@ -0,0 +1,91 @@ +QUBIT_COORDS(0, -1) 0 +QUBIT_COORDS(0, 0) 1 +QUBIT_COORDS(0, 2) 2 +QUBIT_COORDS(0, 4) 3 +QUBIT_COORDS(0, 6) 4 +QUBIT_COORDS(0, 8) 5 +QUBIT_COORDS(1, 9) 6 +QUBIT_COORDS(2, 0) 7 +QUBIT_COORDS(2, 2) 8 +QUBIT_COORDS(2, 4) 9 +QUBIT_COORDS(2, 6) 10 +QUBIT_COORDS(2, 9) 11 +QUBIT_COORDS(2, 11) 12 +QUBIT_COORDS(3, 8) 13 +QUBIT_COORDS(3, 10) 14 +QUBIT_COORDS(3, 12) 15 +QUBIT_COORDS(4, 0) 16 +QUBIT_COORDS(4, 2) 17 +QUBIT_COORDS(4, 4) 18 +QUBIT_COORDS(4, 6) 19 +QUBIT_COORDS(4, 8) 20 +QUBIT_COORDS(4, 10) 21 +QUBIT_COORDS(4, 12) 22 +QUBIT_COORDS(4, 14) 23 +QUBIT_COORDS(5, 9) 24 +QUBIT_COORDS(5, 11) 25 +QUBIT_COORDS(5, 13) 26 +QUBIT_COORDS(6, 0) 27 +QUBIT_COORDS(6, 2) 28 +QUBIT_COORDS(6, 4) 29 +QUBIT_COORDS(6, 6) 30 +QUBIT_COORDS(6, 9) 31 +QUBIT_COORDS(6, 11) 32 +QUBIT_COORDS(7, 8) 33 +QUBIT_COORDS(7, 10) 34 +QUBIT_COORDS(8, 0) 35 +QUBIT_COORDS(8, 2) 36 +QUBIT_COORDS(8, 4) 37 +QUBIT_COORDS(8, 6) 38 +QUBIT_COORDS(8, 8) 39 +MPP X0*X23*X26*X32*X34*X35*X36*X37*X38*X39 +OBSERVABLE_INCLUDE(0) rec[-1] +MPP Z0*Z1*Z7*Z16*Z27*Z35 +OBSERVABLE_INCLUDE(1) rec[-1] +MPP Z2*Z3 Z4*Z5 X1*X7 Z1*Z2*Z7*Z8 X2*X3*X8*X9 Z3*Z4*Z9*Z10 Z10*Z13*Z19*Z20 X4*X5*X6*X10*X11*X13 X6*X11*X12*X14 Z5*Z6*Z11*Z13 Z6*Z11*Z12*Z14 X7*X8*X16*X17 Z8*Z9*Z17*Z18 X9*X10*X18*X19 X11*X13*X14*X20*X21*X24 X12*X14*X15*X21*X22*X25 X15*X22*X23*X26 Z11*Z13*Z14*Z20*Z21*Z24 Z12*Z14*Z15*Z21*Z22*Z25 Z15*Z22*Z23*Z26 X16*X27 Z16*Z17*Z27*Z28 X17*X18*X28*X29 Z18*Z19*Z29*Z30 Z30*Z33*Z38*Z39 X19*X20*X24*X30*X31*X33 X21*X24*X25*X31*X32*X34 X22*X25*X26*X32 Z20*Z24*Z31*Z33 Z21*Z24*Z25*Z31*Z32*Z34 Z22*Z25*Z26*Z32 X27*X28*X35*X36 Z28*Z29*Z36*Z37 X29*X30*X37*X38 X31*X33*X34*X39 Z31*Z33*Z34*Z39 Z35*Z36 Z37*Z38 +TICK +DEPOLARIZE1(0.01) 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 +TICK +MPP Z2*Z3 Z4*Z5 X1*X7 Z1*Z2*Z7*Z8 X2*X3*X8*X9 Z3*Z4*Z9*Z10 Z10*Z13*Z19*Z20 X4*X5*X6*X10*X11*X13 X6*X11*X12*X14 Z5*Z6*Z11*Z13 Z6*Z11*Z12*Z14 X7*X8*X16*X17 Z8*Z9*Z17*Z18 X9*X10*X18*X19 X11*X13*X14*X20*X21*X24 X12*X14*X15*X21*X22*X25 X15*X22*X23*X26 Z11*Z13*Z14*Z20*Z21*Z24 Z12*Z14*Z15*Z21*Z22*Z25 Z15*Z22*Z23*Z26 X16*X27 Z16*Z17*Z27*Z28 X17*X18*X28*X29 Z18*Z19*Z29*Z30 Z30*Z33*Z38*Z39 X19*X20*X24*X30*X31*X33 X21*X24*X25*X31*X32*X34 X22*X25*X26*X32 Z20*Z24*Z31*Z33 Z21*Z24*Z25*Z31*Z32*Z34 Z22*Z25*Z26*Z32 X27*X28*X35*X36 Z28*Z29*Z36*Z37 X29*X30*X37*X38 X31*X33*X34*X39 Z31*Z33*Z34*Z39 Z35*Z36 Z37*Z38 +DETECTOR(-1, 3, 0, 5) rec[-76] rec[-38] +DETECTOR(-1, 7, 0, 5) rec[-75] rec[-37] +DETECTOR(1, -1, 0, 2) rec[-74] rec[-36] +DETECTOR(1, 1, 0, 3) rec[-73] rec[-35] +DETECTOR(1, 3, 0, 0) rec[-72] rec[-34] +DETECTOR(1, 5, 0, 3) rec[-71] rec[-33] +DETECTOR(1, 7.25, 0, 5) rec[-70] rec[-32] +DETECTOR(1, 7.5, 0, 0) rec[-69] rec[-31] +DETECTOR(1, 10, 0, 2) rec[-68] rec[-30] +DETECTOR(2, 8, 0, 3) rec[-67] rec[-29] +DETECTOR(2, 10, 0, 5) rec[-66] rec[-28] +DETECTOR(3, 1, 0, 2) rec[-65] rec[-27] +DETECTOR(3, 3, 0, 5) rec[-64] rec[-26] +DETECTOR(3, 5, 0, 2) rec[-63] rec[-25] +DETECTOR(3, 9, 0, 1) rec[-62] rec[-24] +DETECTOR(3, 11, 0, 0) rec[-61] rec[-23] +DETECTOR(3, 13, 0, 2) rec[-60] rec[-22] +DETECTOR(4, 9, 0, 4) rec[-59] rec[-21] +DETECTOR(4, 11, 0, 3) rec[-58] rec[-20] +DETECTOR(4, 13, 0, 5) rec[-57] rec[-19] +DETECTOR(5, -1, 0, 2) rec[-56] rec[-18] +DETECTOR(5, 1, 0, 5) rec[-55] rec[-17] +DETECTOR(5, 3, 0, 2) rec[-54] rec[-16] +DETECTOR(5, 5, 0, 5) rec[-53] rec[-15] +DETECTOR(5, 7.25, 0, 5) rec[-52] rec[-14] +DETECTOR(5, 7.5, 0, 0) rec[-51] rec[-13] +DETECTOR(5, 10, 0, 2) rec[-50] rec[-12] +DETECTOR(5, 12, 0, 1) rec[-49] rec[-11] +DETECTOR(6, 8, 0, 3) rec[-48] rec[-10] +DETECTOR(6, 10, 0, 5) rec[-47] rec[-9] +DETECTOR(6, 12, 0, 4) rec[-46] rec[-8] +DETECTOR(7, 1, 0, 2) rec[-45] rec[-7] +DETECTOR(7, 3, 0, 5) rec[-44] rec[-6] +DETECTOR(7, 5, 0, 2) rec[-43] rec[-5] +DETECTOR(7, 9, 0, 1) rec[-42] rec[-4] +DETECTOR(8, 9, 0, 4) rec[-41] rec[-3] +DETECTOR(9, 1, 0, 3) rec[-40] rec[-2] +DETECTOR(9, 5, 0, 3) rec[-39] rec[-1] +MPP X0*X23*X26*X32*X34*X35*X36*X37*X38*X39 +OBSERVABLE_INCLUDE(0) rec[-1] +MPP Z0*Z1*Z7*Z16*Z27*Z35 +OBSERVABLE_INCLUDE(1) rec[-1] diff --git a/test_data/color2surface_d7_phenom_r7_p100.stim b/test_data/color2surface_d7_phenom_r7_p100.stim new file mode 100644 index 0000000..ee1bde6 --- /dev/null +++ b/test_data/color2surface_d7_phenom_r7_p100.stim @@ -0,0 +1,253 @@ +QUBIT_COORDS(0, -1) 0 +QUBIT_COORDS(0, 0) 1 +QUBIT_COORDS(0, 2) 2 +QUBIT_COORDS(0, 4) 3 +QUBIT_COORDS(0, 6) 4 +QUBIT_COORDS(0, 8) 5 +QUBIT_COORDS(0, 10) 6 +QUBIT_COORDS(0, 12) 7 +QUBIT_COORDS(1, 13) 8 +QUBIT_COORDS(2, 0) 9 +QUBIT_COORDS(2, 2) 10 +QUBIT_COORDS(2, 4) 11 +QUBIT_COORDS(2, 6) 12 +QUBIT_COORDS(2, 8) 13 +QUBIT_COORDS(2, 10) 14 +QUBIT_COORDS(2, 13) 15 +QUBIT_COORDS(2, 15) 16 +QUBIT_COORDS(3, 12) 17 +QUBIT_COORDS(3, 14) 18 +QUBIT_COORDS(3, 16) 19 +QUBIT_COORDS(4, 0) 20 +QUBIT_COORDS(4, 2) 21 +QUBIT_COORDS(4, 4) 22 +QUBIT_COORDS(4, 6) 23 +QUBIT_COORDS(4, 8) 24 +QUBIT_COORDS(4, 10) 25 +QUBIT_COORDS(4, 12) 26 +QUBIT_COORDS(4, 14) 27 +QUBIT_COORDS(4, 16) 28 +QUBIT_COORDS(4, 18) 29 +QUBIT_COORDS(5, 13) 30 +QUBIT_COORDS(5, 15) 31 +QUBIT_COORDS(5, 17) 32 +QUBIT_COORDS(5, 19) 33 +QUBIT_COORDS(6, 0) 34 +QUBIT_COORDS(6, 2) 35 +QUBIT_COORDS(6, 4) 36 +QUBIT_COORDS(6, 6) 37 +QUBIT_COORDS(6, 8) 38 +QUBIT_COORDS(6, 10) 39 +QUBIT_COORDS(6, 13) 40 +QUBIT_COORDS(6, 15) 41 +QUBIT_COORDS(6, 17) 42 +QUBIT_COORDS(6, 19) 43 +QUBIT_COORDS(6, 21) 44 +QUBIT_COORDS(7, 12) 45 +QUBIT_COORDS(7, 14) 46 +QUBIT_COORDS(7, 16) 47 +QUBIT_COORDS(7, 18) 48 +QUBIT_COORDS(7, 20) 49 +QUBIT_COORDS(8, 0) 50 +QUBIT_COORDS(8, 2) 51 +QUBIT_COORDS(8, 4) 52 +QUBIT_COORDS(8, 6) 53 +QUBIT_COORDS(8, 8) 54 +QUBIT_COORDS(8, 10) 55 +QUBIT_COORDS(8, 12) 56 +QUBIT_COORDS(8, 14) 57 +QUBIT_COORDS(8, 16) 58 +QUBIT_COORDS(8, 18) 59 +QUBIT_COORDS(9, 13) 60 +QUBIT_COORDS(9, 15) 61 +QUBIT_COORDS(9, 17) 62 +QUBIT_COORDS(10, 0) 63 +QUBIT_COORDS(10, 2) 64 +QUBIT_COORDS(10, 4) 65 +QUBIT_COORDS(10, 6) 66 +QUBIT_COORDS(10, 8) 67 +QUBIT_COORDS(10, 10) 68 +QUBIT_COORDS(10, 13) 69 +QUBIT_COORDS(10, 15) 70 +QUBIT_COORDS(11, 12) 71 +QUBIT_COORDS(11, 14) 72 +QUBIT_COORDS(12, 0) 73 +QUBIT_COORDS(12, 2) 74 +QUBIT_COORDS(12, 4) 75 +QUBIT_COORDS(12, 6) 76 +QUBIT_COORDS(12, 8) 77 +QUBIT_COORDS(12, 10) 78 +QUBIT_COORDS(12, 12) 79 +MPP X0*X44*X49*X59*X62*X70*X72*X73*X74*X75*X76*X77*X78*X79 +OBSERVABLE_INCLUDE(0) rec[-1] +MPP Z0*Z1*Z9*Z20*Z34*Z50*Z63*Z73 +OBSERVABLE_INCLUDE(1) rec[-1] +MPP Z2*Z3 Z4*Z5 Z6*Z7 X1*X9 Z1*Z2*Z9*Z10 X2*X3*X10*X11 Z3*Z4*Z11*Z12 X4*X5*X12*X13 Z5*Z6*Z13*Z14 Z14*Z17*Z25*Z26 X6*X7*X8*X14*X15*X17 X8*X15*X16*X18 Z7*Z8*Z15*Z17 Z8*Z15*Z16*Z18 X9*X10*X20*X21 Z10*Z11*Z21*Z22 X11*X12*X22*X23 Z12*Z13*Z23*Z24 X13*X14*X24*X25 X15*X17*X18*X26*X27*X30 X16*X18*X19*X27*X28*X31 X19*X28*X29*X32 Z15*Z17*Z18*Z26*Z27*Z30 Z16*Z18*Z19*Z27*Z28*Z31 Z19*Z28*Z29*Z32 X20*X34 Z20*Z21*Z34*Z35 X21*X22*X35*X36 Z22*Z23*Z36*Z37 X23*X24*X37*X38 Z24*Z25*Z38*Z39 Z39*Z45*Z55*Z56 X25*X26*X30*X39*X40*X45 X27*X30*X31*X40*X41*X46 X28*X31*X32*X41*X42*X47 X29*X32*X33*X42*X43*X48 X33*X43*X44*X49 Z26*Z30*Z40*Z45 Z27*Z30*Z31*Z40*Z41*Z46 Z28*Z31*Z32*Z41*Z42*Z47 Z29*Z32*Z33*Z42*Z43*Z48 Z33*Z43*Z44*Z49 X34*X35*X50*X51 Z35*Z36*Z51*Z52 X36*X37*X52*X53 Z37*Z38*Z53*Z54 X38*X39*X54*X55 X40*X45*X46*X56*X57*X60 X41*X46*X47*X57*X58*X61 X42*X47*X48*X58*X59*X62 X43*X48*X49*X59 Z40*Z45*Z46*Z56*Z57*Z60 Z41*Z46*Z47*Z57*Z58*Z61 Z42*Z47*Z48*Z58*Z59*Z62 Z43*Z48*Z49*Z59 X50*X63 Z50*Z51*Z63*Z64 X51*X52*X64*X65 Z52*Z53*Z65*Z66 X53*X54*X66*X67 Z54*Z55*Z67*Z68 Z68*Z71*Z78*Z79 X55*X56*X60*X68*X69*X71 X57*X60*X61*X69*X70*X72 X58*X61*X62*X70 Z56*Z60*Z69*Z71 Z57*Z60*Z61*Z69*Z70*Z72 Z58*Z61*Z62*Z70 X63*X64*X73*X74 Z64*Z65*Z74*Z75 X65*X66*X75*X76 Z66*Z67*Z76*Z77 X67*X68*X77*X78 X69*X71*X72*X79 Z69*Z71*Z72*Z79 Z73*Z74 Z75*Z76 Z77*Z78 +TICK +REPEAT 7 { + DEPOLARIZE1(0.01) 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 + MPP(0.01) Z2*Z3 Z4*Z5 Z6*Z7 X1*X9 Z1*Z2*Z9*Z10 X2*X3*X10*X11 Z3*Z4*Z11*Z12 X4*X5*X12*X13 Z5*Z6*Z13*Z14 Z14*Z17*Z25*Z26 X6*X7*X8*X14*X15*X17 X8*X15*X16*X18 Z7*Z8*Z15*Z17 Z8*Z15*Z16*Z18 X9*X10*X20*X21 Z10*Z11*Z21*Z22 X11*X12*X22*X23 Z12*Z13*Z23*Z24 X13*X14*X24*X25 X15*X17*X18*X26*X27*X30 X16*X18*X19*X27*X28*X31 X19*X28*X29*X32 Z15*Z17*Z18*Z26*Z27*Z30 Z16*Z18*Z19*Z27*Z28*Z31 Z19*Z28*Z29*Z32 X20*X34 Z20*Z21*Z34*Z35 X21*X22*X35*X36 Z22*Z23*Z36*Z37 X23*X24*X37*X38 Z24*Z25*Z38*Z39 Z39*Z45*Z55*Z56 X25*X26*X30*X39*X40*X45 X27*X30*X31*X40*X41*X46 X28*X31*X32*X41*X42*X47 X29*X32*X33*X42*X43*X48 X33*X43*X44*X49 Z26*Z30*Z40*Z45 Z27*Z30*Z31*Z40*Z41*Z46 Z28*Z31*Z32*Z41*Z42*Z47 Z29*Z32*Z33*Z42*Z43*Z48 Z33*Z43*Z44*Z49 X34*X35*X50*X51 Z35*Z36*Z51*Z52 X36*X37*X52*X53 Z37*Z38*Z53*Z54 X38*X39*X54*X55 X40*X45*X46*X56*X57*X60 X41*X46*X47*X57*X58*X61 X42*X47*X48*X58*X59*X62 X43*X48*X49*X59 Z40*Z45*Z46*Z56*Z57*Z60 Z41*Z46*Z47*Z57*Z58*Z61 Z42*Z47*Z48*Z58*Z59*Z62 Z43*Z48*Z49*Z59 X50*X63 Z50*Z51*Z63*Z64 X51*X52*X64*X65 Z52*Z53*Z65*Z66 X53*X54*X66*X67 Z54*Z55*Z67*Z68 Z68*Z71*Z78*Z79 X55*X56*X60*X68*X69*X71 X57*X60*X61*X69*X70*X72 X58*X61*X62*X70 Z56*Z60*Z69*Z71 Z57*Z60*Z61*Z69*Z70*Z72 Z58*Z61*Z62*Z70 X63*X64*X73*X74 Z64*Z65*Z74*Z75 X65*X66*X75*X76 Z66*Z67*Z76*Z77 X67*X68*X77*X78 X69*X71*X72*X79 Z69*Z71*Z72*Z79 Z73*Z74 Z75*Z76 Z77*Z78 + DETECTOR(-1, 3, 0, 5) rec[-156] rec[-78] + DETECTOR(-1, 7, 0, 5) rec[-155] rec[-77] + DETECTOR(-1, 11, 0, 5) rec[-154] rec[-76] + DETECTOR(1, -1, 0, 2) rec[-153] rec[-75] + DETECTOR(1, 1, 0, 3) rec[-152] rec[-74] + DETECTOR(1, 3, 0, 0) rec[-151] rec[-73] + DETECTOR(1, 5, 0, 3) rec[-150] rec[-72] + DETECTOR(1, 7, 0, 0) rec[-149] rec[-71] + DETECTOR(1, 9, 0, 3) rec[-148] rec[-70] + DETECTOR(1, 11.25, 0, 5) rec[-147] rec[-69] + DETECTOR(1, 11.5, 0, 0) rec[-146] rec[-68] + DETECTOR(1, 14, 0, 2) rec[-145] rec[-67] + DETECTOR(2, 12, 0, 3) rec[-144] rec[-66] + DETECTOR(2, 14, 0, 5) rec[-143] rec[-65] + DETECTOR(3, 1, 0, 2) rec[-142] rec[-64] + DETECTOR(3, 3, 0, 5) rec[-141] rec[-63] + DETECTOR(3, 5, 0, 2) rec[-140] rec[-62] + DETECTOR(3, 7, 0, 5) rec[-139] rec[-61] + DETECTOR(3, 9, 0, 2) rec[-138] rec[-60] + DETECTOR(3, 13, 0, 1) rec[-137] rec[-59] + DETECTOR(3, 15, 0, 0) rec[-136] rec[-58] + DETECTOR(3, 17, 0, 2) rec[-135] rec[-57] + DETECTOR(4, 13, 0, 4) rec[-134] rec[-56] + DETECTOR(4, 15, 0, 3) rec[-133] rec[-55] + DETECTOR(4, 17, 0, 5) rec[-132] rec[-54] + DETECTOR(5, -1, 0, 2) rec[-131] rec[-53] + DETECTOR(5, 1, 0, 5) rec[-130] rec[-52] + DETECTOR(5, 3, 0, 2) rec[-129] rec[-51] + DETECTOR(5, 5, 0, 5) rec[-128] rec[-50] + DETECTOR(5, 7, 0, 2) rec[-127] rec[-49] + DETECTOR(5, 9, 0, 5) rec[-126] rec[-48] + DETECTOR(5, 11.25, 0, 5) rec[-125] rec[-47] + DETECTOR(5, 11.5, 0, 0) rec[-124] rec[-46] + DETECTOR(5, 14, 0, 2) rec[-123] rec[-45] + DETECTOR(5, 16, 0, 1) rec[-122] rec[-44] + DETECTOR(5, 18, 0, 0) rec[-121] rec[-43] + DETECTOR(5, 20, 0, 2) rec[-120] rec[-42] + DETECTOR(6, 12, 0, 3) rec[-119] rec[-41] + DETECTOR(6, 14, 0, 5) rec[-118] rec[-40] + DETECTOR(6, 16, 0, 4) rec[-117] rec[-39] + DETECTOR(6, 18, 0, 3) rec[-116] rec[-38] + DETECTOR(6, 20, 0, 5) rec[-115] rec[-37] + DETECTOR(7, 1, 0, 2) rec[-114] rec[-36] + DETECTOR(7, 3, 0, 5) rec[-113] rec[-35] + DETECTOR(7, 5, 0, 2) rec[-112] rec[-34] + DETECTOR(7, 7, 0, 5) rec[-111] rec[-33] + DETECTOR(7, 9, 0, 2) rec[-110] rec[-32] + DETECTOR(7, 13, 0, 1) rec[-109] rec[-31] + DETECTOR(7, 15, 0, 0) rec[-108] rec[-30] + DETECTOR(7, 17, 0, 2) rec[-107] rec[-29] + DETECTOR(7, 19, 0, 1) rec[-106] rec[-28] + DETECTOR(8, 13, 0, 4) rec[-105] rec[-27] + DETECTOR(8, 15, 0, 3) rec[-104] rec[-26] + DETECTOR(8, 17, 0, 5) rec[-103] rec[-25] + DETECTOR(8, 19, 0, 4) rec[-102] rec[-24] + DETECTOR(9, -1, 0, 2) rec[-101] rec[-23] + DETECTOR(9, 1, 0, 3) rec[-100] rec[-22] + DETECTOR(9, 3, 0, 0) rec[-99] rec[-21] + DETECTOR(9, 5, 0, 3) rec[-98] rec[-20] + DETECTOR(9, 7, 0, 0) rec[-97] rec[-19] + DETECTOR(9, 9, 0, 3) rec[-96] rec[-18] + DETECTOR(9, 11.25, 0, 5) rec[-95] rec[-17] + DETECTOR(9, 11.5, 0, 0) rec[-94] rec[-16] + DETECTOR(9, 14, 0, 2) rec[-93] rec[-15] + DETECTOR(9, 16, 0, 1) rec[-92] rec[-14] + DETECTOR(10, 12, 0, 3) rec[-91] rec[-13] + DETECTOR(10, 14, 0, 5) rec[-90] rec[-12] + DETECTOR(10, 16, 0, 4) rec[-89] rec[-11] + DETECTOR(11, 1, 0, 2) rec[-88] rec[-10] + DETECTOR(11, 3, 0, 5) rec[-87] rec[-9] + DETECTOR(11, 5, 0, 2) rec[-86] rec[-8] + DETECTOR(11, 7, 0, 5) rec[-85] rec[-7] + DETECTOR(11, 9, 0, 2) rec[-84] rec[-6] + DETECTOR(11, 13, 0, 1) rec[-83] rec[-5] + DETECTOR(12, 13, 0, 4) rec[-82] rec[-4] + DETECTOR(13, 1, 0, 3) rec[-81] rec[-3] + DETECTOR(13, 5, 0, 3) rec[-80] rec[-2] + DETECTOR(13, 9, 0, 3) rec[-79] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK +} +MPP Z2*Z3 Z4*Z5 Z6*Z7 X1*X9 Z1*Z2*Z9*Z10 X2*X3*X10*X11 Z3*Z4*Z11*Z12 X4*X5*X12*X13 Z5*Z6*Z13*Z14 Z14*Z17*Z25*Z26 X6*X7*X8*X14*X15*X17 X8*X15*X16*X18 Z7*Z8*Z15*Z17 Z8*Z15*Z16*Z18 X9*X10*X20*X21 Z10*Z11*Z21*Z22 X11*X12*X22*X23 Z12*Z13*Z23*Z24 X13*X14*X24*X25 X15*X17*X18*X26*X27*X30 X16*X18*X19*X27*X28*X31 X19*X28*X29*X32 Z15*Z17*Z18*Z26*Z27*Z30 Z16*Z18*Z19*Z27*Z28*Z31 Z19*Z28*Z29*Z32 X20*X34 Z20*Z21*Z34*Z35 X21*X22*X35*X36 Z22*Z23*Z36*Z37 X23*X24*X37*X38 Z24*Z25*Z38*Z39 Z39*Z45*Z55*Z56 X25*X26*X30*X39*X40*X45 X27*X30*X31*X40*X41*X46 X28*X31*X32*X41*X42*X47 X29*X32*X33*X42*X43*X48 X33*X43*X44*X49 Z26*Z30*Z40*Z45 Z27*Z30*Z31*Z40*Z41*Z46 Z28*Z31*Z32*Z41*Z42*Z47 Z29*Z32*Z33*Z42*Z43*Z48 Z33*Z43*Z44*Z49 X34*X35*X50*X51 Z35*Z36*Z51*Z52 X36*X37*X52*X53 Z37*Z38*Z53*Z54 X38*X39*X54*X55 X40*X45*X46*X56*X57*X60 X41*X46*X47*X57*X58*X61 X42*X47*X48*X58*X59*X62 X43*X48*X49*X59 Z40*Z45*Z46*Z56*Z57*Z60 Z41*Z46*Z47*Z57*Z58*Z61 Z42*Z47*Z48*Z58*Z59*Z62 Z43*Z48*Z49*Z59 X50*X63 Z50*Z51*Z63*Z64 X51*X52*X64*X65 Z52*Z53*Z65*Z66 X53*X54*X66*X67 Z54*Z55*Z67*Z68 Z68*Z71*Z78*Z79 X55*X56*X60*X68*X69*X71 X57*X60*X61*X69*X70*X72 X58*X61*X62*X70 Z56*Z60*Z69*Z71 Z57*Z60*Z61*Z69*Z70*Z72 Z58*Z61*Z62*Z70 X63*X64*X73*X74 Z64*Z65*Z74*Z75 X65*X66*X75*X76 Z66*Z67*Z76*Z77 X67*X68*X77*X78 X69*X71*X72*X79 Z69*Z71*Z72*Z79 Z73*Z74 Z75*Z76 Z77*Z78 +DETECTOR(-1, 3, 0, 5) rec[-156] rec[-78] +DETECTOR(-1, 7, 0, 5) rec[-155] rec[-77] +DETECTOR(-1, 11, 0, 5) rec[-154] rec[-76] +DETECTOR(1, -1, 0, 2) rec[-153] rec[-75] +DETECTOR(1, 1, 0, 3) rec[-152] rec[-74] +DETECTOR(1, 3, 0, 0) rec[-151] rec[-73] +DETECTOR(1, 5, 0, 3) rec[-150] rec[-72] +DETECTOR(1, 7, 0, 0) rec[-149] rec[-71] +DETECTOR(1, 9, 0, 3) rec[-148] rec[-70] +DETECTOR(1, 11.25, 0, 5) rec[-147] rec[-69] +DETECTOR(1, 11.5, 0, 0) rec[-146] rec[-68] +DETECTOR(1, 14, 0, 2) rec[-145] rec[-67] +DETECTOR(2, 12, 0, 3) rec[-144] rec[-66] +DETECTOR(2, 14, 0, 5) rec[-143] rec[-65] +DETECTOR(3, 1, 0, 2) rec[-142] rec[-64] +DETECTOR(3, 3, 0, 5) rec[-141] rec[-63] +DETECTOR(3, 5, 0, 2) rec[-140] rec[-62] +DETECTOR(3, 7, 0, 5) rec[-139] rec[-61] +DETECTOR(3, 9, 0, 2) rec[-138] rec[-60] +DETECTOR(3, 13, 0, 1) rec[-137] rec[-59] +DETECTOR(3, 15, 0, 0) rec[-136] rec[-58] +DETECTOR(3, 17, 0, 2) rec[-135] rec[-57] +DETECTOR(4, 13, 0, 4) rec[-134] rec[-56] +DETECTOR(4, 15, 0, 3) rec[-133] rec[-55] +DETECTOR(4, 17, 0, 5) rec[-132] rec[-54] +DETECTOR(5, -1, 0, 2) rec[-131] rec[-53] +DETECTOR(5, 1, 0, 5) rec[-130] rec[-52] +DETECTOR(5, 3, 0, 2) rec[-129] rec[-51] +DETECTOR(5, 5, 0, 5) rec[-128] rec[-50] +DETECTOR(5, 7, 0, 2) rec[-127] rec[-49] +DETECTOR(5, 9, 0, 5) rec[-126] rec[-48] +DETECTOR(5, 11.25, 0, 5) rec[-125] rec[-47] +DETECTOR(5, 11.5, 0, 0) rec[-124] rec[-46] +DETECTOR(5, 14, 0, 2) rec[-123] rec[-45] +DETECTOR(5, 16, 0, 1) rec[-122] rec[-44] +DETECTOR(5, 18, 0, 0) rec[-121] rec[-43] +DETECTOR(5, 20, 0, 2) rec[-120] rec[-42] +DETECTOR(6, 12, 0, 3) rec[-119] rec[-41] +DETECTOR(6, 14, 0, 5) rec[-118] rec[-40] +DETECTOR(6, 16, 0, 4) rec[-117] rec[-39] +DETECTOR(6, 18, 0, 3) rec[-116] rec[-38] +DETECTOR(6, 20, 0, 5) rec[-115] rec[-37] +DETECTOR(7, 1, 0, 2) rec[-114] rec[-36] +DETECTOR(7, 3, 0, 5) rec[-113] rec[-35] +DETECTOR(7, 5, 0, 2) rec[-112] rec[-34] +DETECTOR(7, 7, 0, 5) rec[-111] rec[-33] +DETECTOR(7, 9, 0, 2) rec[-110] rec[-32] +DETECTOR(7, 13, 0, 1) rec[-109] rec[-31] +DETECTOR(7, 15, 0, 0) rec[-108] rec[-30] +DETECTOR(7, 17, 0, 2) rec[-107] rec[-29] +DETECTOR(7, 19, 0, 1) rec[-106] rec[-28] +DETECTOR(8, 13, 0, 4) rec[-105] rec[-27] +DETECTOR(8, 15, 0, 3) rec[-104] rec[-26] +DETECTOR(8, 17, 0, 5) rec[-103] rec[-25] +DETECTOR(8, 19, 0, 4) rec[-102] rec[-24] +DETECTOR(9, -1, 0, 2) rec[-101] rec[-23] +DETECTOR(9, 1, 0, 3) rec[-100] rec[-22] +DETECTOR(9, 3, 0, 0) rec[-99] rec[-21] +DETECTOR(9, 5, 0, 3) rec[-98] rec[-20] +DETECTOR(9, 7, 0, 0) rec[-97] rec[-19] +DETECTOR(9, 9, 0, 3) rec[-96] rec[-18] +DETECTOR(9, 11.25, 0, 5) rec[-95] rec[-17] +DETECTOR(9, 11.5, 0, 0) rec[-94] rec[-16] +DETECTOR(9, 14, 0, 2) rec[-93] rec[-15] +DETECTOR(9, 16, 0, 1) rec[-92] rec[-14] +DETECTOR(10, 12, 0, 3) rec[-91] rec[-13] +DETECTOR(10, 14, 0, 5) rec[-90] rec[-12] +DETECTOR(10, 16, 0, 4) rec[-89] rec[-11] +DETECTOR(11, 1, 0, 2) rec[-88] rec[-10] +DETECTOR(11, 3, 0, 5) rec[-87] rec[-9] +DETECTOR(11, 5, 0, 2) rec[-86] rec[-8] +DETECTOR(11, 7, 0, 5) rec[-85] rec[-7] +DETECTOR(11, 9, 0, 2) rec[-84] rec[-6] +DETECTOR(11, 13, 0, 1) rec[-83] rec[-5] +DETECTOR(12, 13, 0, 4) rec[-82] rec[-4] +DETECTOR(13, 1, 0, 3) rec[-81] rec[-3] +DETECTOR(13, 5, 0, 3) rec[-80] rec[-2] +DETECTOR(13, 9, 0, 3) rec[-79] rec[-1] +MPP X0*X44*X49*X59*X62*X70*X72*X73*X74*X75*X76*X77*X78*X79 +OBSERVABLE_INCLUDE(0) rec[-1] +MPP Z0*Z1*Z9*Z20*Z34*Z50*Z63*Z73 +OBSERVABLE_INCLUDE(1) rec[-1] diff --git a/test_data/fix_check_1.stim b/test_data/fix_check_1.stim new file mode 100644 index 0000000..60cd840 --- /dev/null +++ b/test_data/fix_check_1.stim @@ -0,0 +1,619 @@ +QUBIT_COORDS(0, -1) 0 +QUBIT_COORDS(0, 0) 1 +QUBIT_COORDS(0, 2) 2 +QUBIT_COORDS(0, 4) 3 +QUBIT_COORDS(0, 6) 4 +QUBIT_COORDS(0, 8) 5 +QUBIT_COORDS(0, 10) 6 +QUBIT_COORDS(0, 12) 7 +QUBIT_COORDS(0, 14) 8 +QUBIT_COORDS(0, 16) 9 +QUBIT_COORDS(0, 18) 10 +QUBIT_COORDS(0, 20) 11 +QUBIT_COORDS(1, 21) 12 +QUBIT_COORDS(2, 0) 13 +QUBIT_COORDS(2, 2) 14 +QUBIT_COORDS(2, 4) 15 +QUBIT_COORDS(2, 6) 16 +QUBIT_COORDS(2, 8) 17 +QUBIT_COORDS(2, 10) 18 +QUBIT_COORDS(2, 12) 19 +QUBIT_COORDS(2, 14) 20 +QUBIT_COORDS(2, 16) 21 +QUBIT_COORDS(2, 18) 22 +QUBIT_COORDS(2, 21) 23 +QUBIT_COORDS(2, 23) 24 +QUBIT_COORDS(3, 20) 25 +QUBIT_COORDS(3, 22) 26 +QUBIT_COORDS(3, 24) 27 +QUBIT_COORDS(4, 0) 28 +QUBIT_COORDS(4, 2) 29 +QUBIT_COORDS(4, 4) 30 +QUBIT_COORDS(4, 6) 31 +QUBIT_COORDS(4, 8) 32 +QUBIT_COORDS(4, 10) 33 +QUBIT_COORDS(4, 12) 34 +QUBIT_COORDS(4, 14) 35 +QUBIT_COORDS(4, 16) 36 +QUBIT_COORDS(4, 18) 37 +QUBIT_COORDS(4, 20) 38 +QUBIT_COORDS(4, 22) 39 +QUBIT_COORDS(4, 24) 40 +QUBIT_COORDS(4, 26) 41 +QUBIT_COORDS(5, 21) 42 +QUBIT_COORDS(5, 23) 43 +QUBIT_COORDS(5, 25) 44 +QUBIT_COORDS(5, 27) 45 +QUBIT_COORDS(6, 0) 46 +QUBIT_COORDS(6, 2) 47 +QUBIT_COORDS(6, 4) 48 +QUBIT_COORDS(6, 6) 49 +QUBIT_COORDS(6, 8) 50 +QUBIT_COORDS(6, 10) 51 +QUBIT_COORDS(6, 12) 52 +QUBIT_COORDS(6, 14) 53 +QUBIT_COORDS(6, 16) 54 +QUBIT_COORDS(6, 18) 55 +QUBIT_COORDS(6, 21) 56 +QUBIT_COORDS(6, 23) 57 +QUBIT_COORDS(6, 25) 58 +QUBIT_COORDS(6, 27) 59 +QUBIT_COORDS(6, 29) 60 +QUBIT_COORDS(7, 20) 61 +QUBIT_COORDS(7, 22) 62 +QUBIT_COORDS(7, 24) 63 +QUBIT_COORDS(7, 26) 64 +QUBIT_COORDS(7, 28) 65 +QUBIT_COORDS(7, 30) 66 +QUBIT_COORDS(8, 0) 67 +QUBIT_COORDS(8, 2) 68 +QUBIT_COORDS(8, 4) 69 +QUBIT_COORDS(8, 6) 70 +QUBIT_COORDS(8, 8) 71 +QUBIT_COORDS(8, 10) 72 +QUBIT_COORDS(8, 12) 73 +QUBIT_COORDS(8, 14) 74 +QUBIT_COORDS(8, 16) 75 +QUBIT_COORDS(8, 18) 76 +QUBIT_COORDS(8, 20) 77 +QUBIT_COORDS(8, 22) 78 +QUBIT_COORDS(8, 24) 79 +QUBIT_COORDS(8, 26) 80 +QUBIT_COORDS(8, 28) 81 +QUBIT_COORDS(8, 30) 82 +QUBIT_COORDS(8, 32) 83 +QUBIT_COORDS(9, 21) 84 +QUBIT_COORDS(9, 23) 85 +QUBIT_COORDS(9, 25) 86 +QUBIT_COORDS(9, 27) 87 +QUBIT_COORDS(9, 29) 88 +QUBIT_COORDS(9, 31) 89 +QUBIT_COORDS(9, 33) 90 +QUBIT_COORDS(10, 0) 91 +QUBIT_COORDS(10, 2) 92 +QUBIT_COORDS(10, 4) 93 +QUBIT_COORDS(10, 6) 94 +QUBIT_COORDS(10, 8) 95 +QUBIT_COORDS(10, 10) 96 +QUBIT_COORDS(10, 12) 97 +QUBIT_COORDS(10, 14) 98 +QUBIT_COORDS(10, 16) 99 +QUBIT_COORDS(10, 18) 100 +QUBIT_COORDS(10, 21) 101 +QUBIT_COORDS(10, 23) 102 +QUBIT_COORDS(10, 25) 103 +QUBIT_COORDS(10, 27) 104 +QUBIT_COORDS(10, 29) 105 +QUBIT_COORDS(10, 31) 106 +QUBIT_COORDS(10, 33) 107 +QUBIT_COORDS(10, 35) 108 +QUBIT_COORDS(11, 20) 109 +QUBIT_COORDS(11, 22) 110 +QUBIT_COORDS(11, 24) 111 +QUBIT_COORDS(11, 26) 112 +QUBIT_COORDS(11, 28) 113 +QUBIT_COORDS(11, 30) 114 +QUBIT_COORDS(11, 32) 115 +QUBIT_COORDS(11, 34) 116 +QUBIT_COORDS(12, 0) 117 +QUBIT_COORDS(12, 2) 118 +QUBIT_COORDS(12, 4) 119 +QUBIT_COORDS(12, 6) 120 +QUBIT_COORDS(12, 8) 121 +QUBIT_COORDS(12, 10) 122 +QUBIT_COORDS(12, 12) 123 +QUBIT_COORDS(12, 14) 124 +QUBIT_COORDS(12, 16) 125 +QUBIT_COORDS(12, 18) 126 +QUBIT_COORDS(12, 20) 127 +QUBIT_COORDS(12, 22) 128 +QUBIT_COORDS(12, 24) 129 +QUBIT_COORDS(12, 26) 130 +QUBIT_COORDS(12, 28) 131 +QUBIT_COORDS(12, 30) 132 +QUBIT_COORDS(12, 32) 133 +QUBIT_COORDS(13, 21) 134 +QUBIT_COORDS(13, 23) 135 +QUBIT_COORDS(13, 25) 136 +QUBIT_COORDS(13, 27) 137 +QUBIT_COORDS(13, 29) 138 +QUBIT_COORDS(13, 31) 139 +QUBIT_COORDS(14, 0) 140 +QUBIT_COORDS(14, 2) 141 +QUBIT_COORDS(14, 4) 142 +QUBIT_COORDS(14, 6) 143 +QUBIT_COORDS(14, 8) 144 +QUBIT_COORDS(14, 10) 145 +QUBIT_COORDS(14, 12) 146 +QUBIT_COORDS(14, 14) 147 +QUBIT_COORDS(14, 16) 148 +QUBIT_COORDS(14, 18) 149 +QUBIT_COORDS(14, 21) 150 +QUBIT_COORDS(14, 23) 151 +QUBIT_COORDS(14, 25) 152 +QUBIT_COORDS(14, 27) 153 +QUBIT_COORDS(14, 29) 154 +QUBIT_COORDS(15, 20) 155 +QUBIT_COORDS(15, 22) 156 +QUBIT_COORDS(15, 24) 157 +QUBIT_COORDS(15, 26) 158 +QUBIT_COORDS(15, 28) 159 +QUBIT_COORDS(16, 0) 160 +QUBIT_COORDS(16, 2) 161 +QUBIT_COORDS(16, 4) 162 +QUBIT_COORDS(16, 6) 163 +QUBIT_COORDS(16, 8) 164 +QUBIT_COORDS(16, 10) 165 +QUBIT_COORDS(16, 12) 166 +QUBIT_COORDS(16, 14) 167 +QUBIT_COORDS(16, 16) 168 +QUBIT_COORDS(16, 18) 169 +QUBIT_COORDS(16, 20) 170 +QUBIT_COORDS(16, 22) 171 +QUBIT_COORDS(16, 24) 172 +QUBIT_COORDS(16, 26) 173 +QUBIT_COORDS(17, 21) 174 +QUBIT_COORDS(17, 23) 175 +QUBIT_COORDS(17, 25) 176 +QUBIT_COORDS(18, 0) 177 +QUBIT_COORDS(18, 2) 178 +QUBIT_COORDS(18, 4) 179 +QUBIT_COORDS(18, 6) 180 +QUBIT_COORDS(18, 8) 181 +QUBIT_COORDS(18, 10) 182 +QUBIT_COORDS(18, 12) 183 +QUBIT_COORDS(18, 14) 184 +QUBIT_COORDS(18, 16) 185 +QUBIT_COORDS(18, 18) 186 +QUBIT_COORDS(18, 21) 187 +QUBIT_COORDS(18, 23) 188 +QUBIT_COORDS(19, 20) 189 +QUBIT_COORDS(19, 22) 190 +QUBIT_COORDS(20, 0) 191 +QUBIT_COORDS(20, 2) 192 +QUBIT_COORDS(20, 4) 193 +QUBIT_COORDS(20, 6) 194 +QUBIT_COORDS(20, 8) 195 +QUBIT_COORDS(20, 10) 196 +QUBIT_COORDS(20, 12) 197 +QUBIT_COORDS(20, 14) 198 +QUBIT_COORDS(20, 16) 199 +QUBIT_COORDS(20, 18) 200 +QUBIT_COORDS(20, 20) 201 +MPP X0*X108*X116*X133*X139*X154*X159*X173*X176*X188*X190*X191*X192*X193*X194*X195*X196*X197*X198*X199*X200*X201 +OBSERVABLE_INCLUDE(0) rec[-1] +MPP Z0*Z1*Z13*Z28*Z46*Z67*Z91*Z117*Z140*Z160*Z177*Z191 +OBSERVABLE_INCLUDE(1) rec[-1] +MPP Z2*Z3 Z4*Z5 Z6*Z7 Z8*Z9 Z10*Z11 X1*X13 Z1*Z2*Z13*Z14 X2*X3*X14*X15 Z3*Z4*Z15*Z16 X4*X5*X16*X17 Z5*Z6*Z17*Z18 X6*X7*X18*X19 Z7*Z8*Z19*Z20 X8*X9*X20*X21 Z9*Z10*Z21*Z22 Z22*Z25*Z37*Z38 X10*X11*X12*X22*X23*X25 X12*X23*X24*X26 Z11*Z12*Z23*Z25 Z12*Z23*Z24*Z26 X13*X14*X28*X29 Z14*Z15*Z29*Z30 X15*X16*X30*X31 Z16*Z17*Z31*Z32 X17*X18*X32*X33 Z18*Z19*Z33*Z34 X19*X20*X34*X35 Z20*Z21*Z35*Z36 X21*X22*X36*X37 X23*X25*X26*X38*X39*X42 X24*X26*X27*X39*X40*X43 X27*X40*X41*X44 Z23*Z25*Z26*Z38*Z39*Z42 Z24*Z26*Z27*Z39*Z40*Z43 Z27*Z40*Z41*Z44 X28*X46 Z28*Z29*Z46*Z47 X29*X30*X47*X48 Z30*Z31*Z48*Z49 X31*X32*X49*X50 Z32*Z33*Z50*Z51 X33*X34*X51*X52 Z34*Z35*Z52*Z53 X35*X36*X53*X54 Z36*Z37*Z54*Z55 Z55*Z61*Z76*Z77 X37*X38*X42*X55*X56*X61 X39*X42*X43*X56*X57*X62 X40*X43*X44*X57*X58*X63 X41*X44*X45*X58*X59*X64 X45*X59*X60*X65 Z38*Z42*Z56*Z61 Z39*Z42*Z43*Z56*Z57*Z62 Z40*Z43*Z44*Z57*Z58*Z63 Z41*Z44*Z45*Z58*Z59*Z64 Z45*Z59*Z60*Z65 X46*X47*X67*X68 Z47*Z48*Z68*Z69 X48*X49*X69*X70 Z49*Z50*Z70*Z71 X50*X51*X71*X72 Z51*Z52*Z72*Z73 X52*X53*X73*X74 Z53*Z54*Z74*Z75 X54*X55*X75*X76 X56*X61*X62*X77*X78*X84 X57*X62*X63*X78*X79*X85 X58*X63*X64*X79*X80*X86 X59*X64*X65*X80*X81*X87 X60*X65*X66*X81*X82*X88 X66*X82*X83*X89 Z56*Z61*Z62*Z77*Z78*Z84 Z57*Z62*Z63*Z78*Z79*Z85 Z58*Z63*Z64*Z79*Z80*Z86 Z59*Z64*Z65*Z80*Z81*Z87 Z60*Z65*Z66*Z81*Z82*Z88 Z66*Z82*Z83*Z89 X67*X91 Z67*Z68*Z91*Z92 X68*X69*X92*X93 Z69*Z70*Z93*Z94 X70*X71*X94*X95 Z71*Z72*Z95*Z96 X72*X73*X96*X97 Z73*Z74*Z97*Z98 X74*X75*X98*X99 Z75*Z76*Z99*Z100 Z100*Z109*Z126*Z127 X76*X77*X84*X100*X101*X109 X78*X84*X85*X101*X102*X110 X79*X85*X86*X102*X103*X111 X80*X86*X87*X103*X104*X112 X81*X87*X88*X104*X105*X113 X82*X88*X89*X105*X106*X114 X83*X89*X90*X106*X107*X115 X90*X107*X108*X116 Z77*Z84*Z101*Z109 Z78*Z84*Z85*Z101*Z102*Z110 Z79*Z85*Z86*Z102*Z103*Z111 Z80*Z86*Z87*Z103*Z104*Z112 Z81*Z87*Z88*Z104*Z105*Z113 Z82*Z88*Z89*Z105*Z106*Z114 Z83*Z89*Z90*Z106*Z107*Z115 Z90*Z107*Z108*Z116 X91*X92*X117*X118 Z92*Z93*Z118*Z119 X93*X94*X119*X120 Z94*Z95*Z120*Z121 X95*X96*X121*X122 Z96*Z97*Z122*Z123 X97*X98*X123*X124 Z98*Z99*Z124*Z125 X99*X100*X125*X126 X101*X109*X110*X127*X128*X134 X102*X110*X111*X128*X129*X135 X103*X111*X112*X129*X130*X136 X104*X112*X113*X130*X131*X137 X105*X113*X114*X131*X132*X138 X106*X114*X115*X132*X133*X139 X107*X115*X116*X133 Z101*Z109*Z110*Z127*Z128*Z134 Z102*Z110*Z111*Z128*Z129*Z135 Z103*Z111*Z112*Z129*Z130*Z136 Z104*Z112*Z113*Z130*Z131*Z137 Z105*Z113*Z114*Z131*Z132*Z138 Z106*Z114*Z115*Z132*Z133*Z139 Z107*Z115*Z116*Z133 X117*X140 Z117*Z118*Z140*Z141 X118*X119*X141*X142 Z119*Z120*Z142*Z143 X120*X121*X143*X144 Z121*Z122*Z144*Z145 X122*X123*X145*X146 Z123*Z124*Z146*Z147 X124*X125*X147*X148 Z125*Z126*Z148*Z149 Z149*Z155*Z169*Z170 X126*X127*X134*X149*X150*X155 X128*X134*X135*X150*X151*X156 X129*X135*X136*X151*X152*X157 X130*X136*X137*X152*X153*X158 X131*X137*X138*X153*X154*X159 X132*X138*X139*X154 Z127*Z134*Z150*Z155 Z128*Z134*Z135*Z150*Z151*Z156 Z129*Z135*Z136*Z151*Z152*Z157 Z130*Z136*Z137*Z152*Z153*Z158 Z131*Z137*Z138*Z153*Z154*Z159 Z132*Z138*Z139*Z154 X140*X141*X160*X161 Z141*Z142*Z161*Z162 X142*X143*X162*X163 Z143*Z144*Z163*Z164 X144*X145*X164*X165 Z145*Z146*Z165*Z166 X146*X147*X166*X167 Z147*Z148*Z167*Z168 X148*X149*X168*X169 X150*X155*X156*X170*X171*X174 X151*X156*X157*X171*X172*X175 X152*X157*X158*X172*X173*X176 X153*X158*X159*X173 Z150*Z155*Z156*Z170*Z171*Z174 Z151*Z156*Z157*Z171*Z172*Z175 Z152*Z157*Z158*Z172*Z173*Z176 Z153*Z158*Z159*Z173 X160*X177 Z160*Z161*Z177*Z178 X161*X162*X178*X179 Z162*Z163*Z179*Z180 X163*X164*X180*X181 Z164*Z165*Z181*Z182 X165*X166*X182*X183 Z166*Z167*Z183*Z184 X167*X168*X184*X185 Z168*Z169*Z185*Z186 Z186*Z189*Z200*Z201 X169*X170*X174*X186*X187*X189 X171*X174*X175*X187*X188*X190 X172*X175*X176*X188 Z170*Z174*Z187*Z189 Z171*Z174*Z175*Z187*Z188*Z190 Z172*Z175*Z176*Z188 X177*X178*X191*X192 Z178*Z179*Z192*Z193 X179*X180*X193*X194 Z180*Z181*Z194*Z195 X181*X182*X195*X196 Z182*Z183*Z196*Z197 X183*X184*X197*X198 Z184*Z185*Z198*Z199 X185*X186*X199*X200 X187*X189*X190*X201 Z187*Z189*Z190*Z201 Z191*Z192 Z193*Z194 Z195*Z196 Z197*Z198 Z199*Z200 +TICK +REPEAT 44 { + DEPOLARIZE1(0.005) 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 + MPP(0.005) Z2*Z3 Z4*Z5 Z6*Z7 Z8*Z9 Z10*Z11 X1*X13 Z1*Z2*Z13*Z14 X2*X3*X14*X15 Z3*Z4*Z15*Z16 X4*X5*X16*X17 Z5*Z6*Z17*Z18 X6*X7*X18*X19 Z7*Z8*Z19*Z20 X8*X9*X20*X21 Z9*Z10*Z21*Z22 Z22*Z25*Z37*Z38 X10*X11*X12*X22*X23*X25 X12*X23*X24*X26 Z11*Z12*Z23*Z25 Z12*Z23*Z24*Z26 X13*X14*X28*X29 Z14*Z15*Z29*Z30 X15*X16*X30*X31 Z16*Z17*Z31*Z32 X17*X18*X32*X33 Z18*Z19*Z33*Z34 X19*X20*X34*X35 Z20*Z21*Z35*Z36 X21*X22*X36*X37 X23*X25*X26*X38*X39*X42 X24*X26*X27*X39*X40*X43 X27*X40*X41*X44 Z23*Z25*Z26*Z38*Z39*Z42 Z24*Z26*Z27*Z39*Z40*Z43 Z27*Z40*Z41*Z44 X28*X46 Z28*Z29*Z46*Z47 X29*X30*X47*X48 Z30*Z31*Z48*Z49 X31*X32*X49*X50 Z32*Z33*Z50*Z51 X33*X34*X51*X52 Z34*Z35*Z52*Z53 X35*X36*X53*X54 Z36*Z37*Z54*Z55 Z55*Z61*Z76*Z77 X37*X38*X42*X55*X56*X61 X39*X42*X43*X56*X57*X62 X40*X43*X44*X57*X58*X63 X41*X44*X45*X58*X59*X64 X45*X59*X60*X65 Z38*Z42*Z56*Z61 Z39*Z42*Z43*Z56*Z57*Z62 Z40*Z43*Z44*Z57*Z58*Z63 Z41*Z44*Z45*Z58*Z59*Z64 Z45*Z59*Z60*Z65 X46*X47*X67*X68 Z47*Z48*Z68*Z69 X48*X49*X69*X70 Z49*Z50*Z70*Z71 X50*X51*X71*X72 Z51*Z52*Z72*Z73 X52*X53*X73*X74 Z53*Z54*Z74*Z75 X54*X55*X75*X76 X56*X61*X62*X77*X78*X84 X57*X62*X63*X78*X79*X85 X58*X63*X64*X79*X80*X86 X59*X64*X65*X80*X81*X87 X60*X65*X66*X81*X82*X88 X66*X82*X83*X89 Z56*Z61*Z62*Z77*Z78*Z84 Z57*Z62*Z63*Z78*Z79*Z85 Z58*Z63*Z64*Z79*Z80*Z86 Z59*Z64*Z65*Z80*Z81*Z87 Z60*Z65*Z66*Z81*Z82*Z88 Z66*Z82*Z83*Z89 X67*X91 Z67*Z68*Z91*Z92 X68*X69*X92*X93 Z69*Z70*Z93*Z94 X70*X71*X94*X95 Z71*Z72*Z95*Z96 X72*X73*X96*X97 Z73*Z74*Z97*Z98 X74*X75*X98*X99 Z75*Z76*Z99*Z100 Z100*Z109*Z126*Z127 X76*X77*X84*X100*X101*X109 X78*X84*X85*X101*X102*X110 X79*X85*X86*X102*X103*X111 X80*X86*X87*X103*X104*X112 X81*X87*X88*X104*X105*X113 X82*X88*X89*X105*X106*X114 X83*X89*X90*X106*X107*X115 X90*X107*X108*X116 Z77*Z84*Z101*Z109 Z78*Z84*Z85*Z101*Z102*Z110 Z79*Z85*Z86*Z102*Z103*Z111 Z80*Z86*Z87*Z103*Z104*Z112 Z81*Z87*Z88*Z104*Z105*Z113 Z82*Z88*Z89*Z105*Z106*Z114 Z83*Z89*Z90*Z106*Z107*Z115 Z90*Z107*Z108*Z116 X91*X92*X117*X118 Z92*Z93*Z118*Z119 X93*X94*X119*X120 Z94*Z95*Z120*Z121 X95*X96*X121*X122 Z96*Z97*Z122*Z123 X97*X98*X123*X124 Z98*Z99*Z124*Z125 X99*X100*X125*X126 X101*X109*X110*X127*X128*X134 X102*X110*X111*X128*X129*X135 X103*X111*X112*X129*X130*X136 X104*X112*X113*X130*X131*X137 X105*X113*X114*X131*X132*X138 X106*X114*X115*X132*X133*X139 X107*X115*X116*X133 Z101*Z109*Z110*Z127*Z128*Z134 Z102*Z110*Z111*Z128*Z129*Z135 Z103*Z111*Z112*Z129*Z130*Z136 Z104*Z112*Z113*Z130*Z131*Z137 Z105*Z113*Z114*Z131*Z132*Z138 Z106*Z114*Z115*Z132*Z133*Z139 Z107*Z115*Z116*Z133 X117*X140 Z117*Z118*Z140*Z141 X118*X119*X141*X142 Z119*Z120*Z142*Z143 X120*X121*X143*X144 Z121*Z122*Z144*Z145 X122*X123*X145*X146 Z123*Z124*Z146*Z147 X124*X125*X147*X148 Z125*Z126*Z148*Z149 Z149*Z155*Z169*Z170 X126*X127*X134*X149*X150*X155 X128*X134*X135*X150*X151*X156 X129*X135*X136*X151*X152*X157 X130*X136*X137*X152*X153*X158 X131*X137*X138*X153*X154*X159 X132*X138*X139*X154 Z127*Z134*Z150*Z155 Z128*Z134*Z135*Z150*Z151*Z156 Z129*Z135*Z136*Z151*Z152*Z157 Z130*Z136*Z137*Z152*Z153*Z158 Z131*Z137*Z138*Z153*Z154*Z159 Z132*Z138*Z139*Z154 X140*X141*X160*X161 Z141*Z142*Z161*Z162 X142*X143*X162*X163 Z143*Z144*Z163*Z164 X144*X145*X164*X165 Z145*Z146*Z165*Z166 X146*X147*X166*X167 Z147*Z148*Z167*Z168 X148*X149*X168*X169 X150*X155*X156*X170*X171*X174 X151*X156*X157*X171*X172*X175 X152*X157*X158*X172*X173*X176 X153*X158*X159*X173 Z150*Z155*Z156*Z170*Z171*Z174 Z151*Z156*Z157*Z171*Z172*Z175 Z152*Z157*Z158*Z172*Z173*Z176 Z153*Z158*Z159*Z173 X160*X177 Z160*Z161*Z177*Z178 X161*X162*X178*X179 Z162*Z163*Z179*Z180 X163*X164*X180*X181 Z164*Z165*Z181*Z182 X165*X166*X182*X183 Z166*Z167*Z183*Z184 X167*X168*X184*X185 Z168*Z169*Z185*Z186 Z186*Z189*Z200*Z201 X169*X170*X174*X186*X187*X189 X171*X174*X175*X187*X188*X190 X172*X175*X176*X188 Z170*Z174*Z187*Z189 Z171*Z174*Z175*Z187*Z188*Z190 Z172*Z175*Z176*Z188 X177*X178*X191*X192 Z178*Z179*Z192*Z193 X179*X180*X193*X194 Z180*Z181*Z194*Z195 X181*X182*X195*X196 Z182*Z183*Z196*Z197 X183*X184*X197*X198 Z184*Z185*Z198*Z199 X185*X186*X199*X200 X187*X189*X190*X201 Z187*Z189*Z190*Z201 Z191*Z192 Z193*Z194 Z195*Z196 Z197*Z198 Z199*Z200 + DETECTOR(-1, 3, 0, 5) rec[-400] rec[-200] + DETECTOR(-1, 7, 0, 5) rec[-399] rec[-199] + DETECTOR(-1, 11, 0, 5) rec[-398] rec[-198] + DETECTOR(-1, 15, 0, 5) rec[-397] rec[-197] + DETECTOR(-1, 19, 0, 5) rec[-396] rec[-196] + DETECTOR(1, -1, 0, 2) rec[-395] rec[-195] + DETECTOR(1, 1, 0, 3) rec[-394] rec[-194] + DETECTOR(1, 3, 0, 0) rec[-393] rec[-193] + DETECTOR(1, 5, 0, 3) rec[-392] rec[-192] + DETECTOR(1, 7, 0, 0) rec[-391] rec[-191] + DETECTOR(1, 9, 0, 3) rec[-390] rec[-190] + DETECTOR(1, 11, 0, 0) rec[-389] rec[-189] + DETECTOR(1, 13, 0, 3) rec[-388] rec[-188] + DETECTOR(1, 15, 0, 0) rec[-387] rec[-187] + DETECTOR(1, 17, 0, 3) rec[-386] rec[-186] + DETECTOR(1, 19.25, 0, 5) rec[-385] rec[-185] + DETECTOR(1, 19.5, 0, 0) rec[-384] rec[-184] + DETECTOR(1, 22, 0, 2) rec[-383] rec[-183] + DETECTOR(2, 20, 0, 3) rec[-382] rec[-182] + DETECTOR(2, 22, 0, 5) rec[-381] rec[-181] + DETECTOR(3, 1, 0, 2) rec[-380] rec[-180] + DETECTOR(3, 3, 0, 5) rec[-379] rec[-179] + DETECTOR(3, 5, 0, 2) rec[-378] rec[-178] + DETECTOR(3, 7, 0, 5) rec[-377] rec[-177] + DETECTOR(3, 9, 0, 2) rec[-376] rec[-176] + DETECTOR(3, 11, 0, 5) rec[-375] rec[-175] + DETECTOR(3, 13, 0, 2) rec[-374] rec[-174] + DETECTOR(3, 15, 0, 5) rec[-373] rec[-173] + DETECTOR(3, 17, 0, 2) rec[-372] rec[-172] + DETECTOR(3, 21, 0, 1) rec[-371] rec[-171] + DETECTOR(3, 23, 0, 0) rec[-370] rec[-170] + DETECTOR(3, 25, 0, 2) rec[-369] rec[-169] + DETECTOR(4, 21, 0, 4) rec[-368] rec[-168] + DETECTOR(4, 23, 0, 3) rec[-367] rec[-167] + DETECTOR(4, 25, 0, 5) rec[-366] rec[-166] + DETECTOR(5, -1, 0, 2) rec[-365] rec[-165] + DETECTOR(5, 1, 0, 5) rec[-364] rec[-164] + DETECTOR(5, 3, 0, 2) rec[-363] rec[-163] + DETECTOR(5, 5, 0, 5) rec[-362] rec[-162] + DETECTOR(5, 7, 0, 2) rec[-361] rec[-161] + DETECTOR(5, 9, 0, 5) rec[-360] rec[-160] + DETECTOR(5, 11, 0, 2) rec[-359] rec[-159] + DETECTOR(5, 13, 0, 5) rec[-358] rec[-158] + DETECTOR(5, 15, 0, 2) rec[-357] rec[-157] + DETECTOR(5, 17, 0, 5) rec[-356] rec[-156] + DETECTOR(5, 19.25, 0, 5) rec[-355] rec[-155] + DETECTOR(5, 19.5, 0, 0) rec[-354] rec[-154] + DETECTOR(5, 22, 0, 2) rec[-353] rec[-153] + DETECTOR(5, 24, 0, 1) rec[-352] rec[-152] + DETECTOR(5, 26, 0, 0) rec[-351] rec[-151] + DETECTOR(5, 28, 0, 2) rec[-350] rec[-150] + DETECTOR(6, 20, 0, 3) rec[-349] rec[-149] + DETECTOR(6, 22, 0, 5) rec[-348] rec[-148] + DETECTOR(6, 24, 0, 4) rec[-347] rec[-147] + DETECTOR(6, 26, 0, 3) rec[-346] rec[-146] + DETECTOR(6, 28, 0, 5) rec[-345] rec[-145] + DETECTOR(7, 1, 0, 2) rec[-344] rec[-144] + DETECTOR(7, 3, 0, 5) rec[-343] rec[-143] + DETECTOR(7, 5, 0, 2) rec[-342] rec[-142] + DETECTOR(7, 7, 0, 5) rec[-341] rec[-141] + DETECTOR(7, 9, 0, 2) rec[-340] rec[-140] + DETECTOR(7, 11, 0, 5) rec[-339] rec[-139] + DETECTOR(7, 13, 0, 2) rec[-338] rec[-138] + DETECTOR(7, 15, 0, 5) rec[-337] rec[-137] + DETECTOR(7, 17, 0, 2) rec[-336] rec[-136] + DETECTOR(7, 21, 0, 1) rec[-335] rec[-135] + DETECTOR(7, 23, 0, 0) rec[-334] rec[-134] + DETECTOR(7, 25, 0, 2) rec[-333] rec[-133] + DETECTOR(7, 27, 0, 1) rec[-332] rec[-132] + DETECTOR(7, 29, 0, 0) rec[-331] rec[-131] + DETECTOR(7, 31, 0, 2) rec[-330] rec[-130] + DETECTOR(8, 21, 0, 4) rec[-329] rec[-129] + DETECTOR(8, 23, 0, 3) rec[-328] rec[-128] + DETECTOR(8, 25, 0, 5) rec[-327] rec[-127] + DETECTOR(8, 27, 0, 4) rec[-326] rec[-126] + DETECTOR(8, 29, 0, 3) rec[-325] rec[-125] + DETECTOR(8, 31, 0, 5) rec[-324] rec[-124] + DETECTOR(9, -1, 0, 2) rec[-323] rec[-123] + DETECTOR(9, 1, 0, 3) rec[-322] rec[-122] + DETECTOR(9, 3, 0, 0) rec[-321] rec[-121] + DETECTOR(9, 5, 0, 3) rec[-320] rec[-120] + DETECTOR(9, 7, 0, 0) rec[-319] rec[-119] + DETECTOR(9, 9, 0, 3) rec[-318] rec[-118] + DETECTOR(9, 11, 0, 0) rec[-317] rec[-117] + DETECTOR(9, 13, 0, 3) rec[-316] rec[-116] + DETECTOR(9, 15, 0, 0) rec[-315] rec[-115] + DETECTOR(9, 17, 0, 3) rec[-314] rec[-114] + DETECTOR(9, 19.25, 0, 5) rec[-313] rec[-113] + DETECTOR(9, 19.5, 0, 0) rec[-312] rec[-112] + DETECTOR(9, 22, 0, 2) rec[-311] rec[-111] + DETECTOR(9, 24, 0, 1) rec[-310] rec[-110] + DETECTOR(9, 26, 0, 0) rec[-309] rec[-109] + DETECTOR(9, 28, 0, 2) rec[-308] rec[-108] + DETECTOR(9, 30, 0, 1) rec[-307] rec[-107] + DETECTOR(9, 32, 0, 0) rec[-306] rec[-106] + DETECTOR(9, 34, 0, 2) rec[-305] rec[-105] + DETECTOR(10, 20, 0, 3) rec[-304] rec[-104] + DETECTOR(10, 22, 0, 5) rec[-303] rec[-103] + DETECTOR(10, 24, 0, 4) rec[-302] rec[-102] + DETECTOR(10, 26, 0, 3) rec[-301] rec[-101] + DETECTOR(10, 28, 0, 5) rec[-300] rec[-100] + DETECTOR(10, 30, 0, 4) rec[-299] rec[-99] + DETECTOR(10, 32, 0, 3) rec[-298] rec[-98] + DETECTOR(10, 34, 0, 5) rec[-297] rec[-97] + DETECTOR(11, 1, 0, 2) rec[-296] rec[-96] + DETECTOR(11, 3, 0, 5) rec[-295] rec[-95] + DETECTOR(11, 5, 0, 2) rec[-294] rec[-94] + DETECTOR(11, 7, 0, 5) rec[-293] rec[-93] + DETECTOR(11, 9, 0, 2) rec[-292] rec[-92] + DETECTOR(11, 11, 0, 5) rec[-291] rec[-91] + DETECTOR(11, 13, 0, 2) rec[-290] rec[-90] + DETECTOR(11, 15, 0, 5) rec[-289] rec[-89] + DETECTOR(11, 17, 0, 2) rec[-288] rec[-88] + DETECTOR(11, 21, 0, 1) rec[-287] rec[-87] + DETECTOR(11, 23, 0, 0) rec[-286] rec[-86] + DETECTOR(11, 25, 0, 2) rec[-285] rec[-85] + DETECTOR(11, 27, 0, 1) rec[-284] rec[-84] + DETECTOR(11, 29, 0, 0) rec[-283] rec[-83] + DETECTOR(11, 31, 0, 2) rec[-282] rec[-82] + DETECTOR(11, 33, 0, 1) rec[-281] rec[-81] + DETECTOR(12, 21, 0, 4) rec[-280] rec[-80] + DETECTOR(12, 23, 0, 3) rec[-279] rec[-79] + DETECTOR(12, 25, 0, 5) rec[-278] rec[-78] + DETECTOR(12, 27, 0, 4) rec[-277] rec[-77] + DETECTOR(12, 29, 0, 3) rec[-276] rec[-76] + DETECTOR(12, 31, 0, 5) rec[-275] rec[-75] + DETECTOR(12, 33, 0, 4) rec[-274] rec[-74] + DETECTOR(13, -1, 0, 2) rec[-273] rec[-73] + DETECTOR(13, 1, 0, 3) rec[-272] rec[-72] + DETECTOR(13, 3, 0, 0) rec[-271] rec[-71] + DETECTOR(13, 5, 0, 3) rec[-270] rec[-70] + DETECTOR(13, 7, 0, 0) rec[-269] rec[-69] + DETECTOR(13, 9, 0, 3) rec[-268] rec[-68] + DETECTOR(13, 11, 0, 0) rec[-267] rec[-67] + DETECTOR(13, 13, 0, 3) rec[-266] rec[-66] + DETECTOR(13, 15, 0, 0) rec[-265] rec[-65] + DETECTOR(13, 17, 0, 3) rec[-264] rec[-64] + DETECTOR(13, 19.25, 0, 5) rec[-263] rec[-63] + DETECTOR(13, 19.5, 0, 0) rec[-262] rec[-62] + DETECTOR(13, 22, 0, 2) rec[-261] rec[-61] + DETECTOR(13, 24, 0, 1) rec[-260] rec[-60] + DETECTOR(13, 26, 0, 0) rec[-259] rec[-59] + DETECTOR(13, 28, 0, 2) rec[-258] rec[-58] + DETECTOR(13, 30, 0, 1) rec[-257] rec[-57] + DETECTOR(14, 20, 0, 3) rec[-256] rec[-56] + DETECTOR(14, 22, 0, 5) rec[-255] rec[-55] + DETECTOR(14, 24, 0, 4) rec[-254] rec[-54] + DETECTOR(14, 26, 0, 3) rec[-253] rec[-53] + DETECTOR(14, 28, 0, 5) rec[-252] rec[-52] + DETECTOR(14, 30, 0, 4) rec[-251] rec[-51] + DETECTOR(15, 1, 0, 2) rec[-250] rec[-50] + DETECTOR(15, 3, 0, 5) rec[-249] rec[-49] + DETECTOR(15, 5, 0, 2) rec[-248] rec[-48] + DETECTOR(15, 7, 0, 5) rec[-247] rec[-47] + DETECTOR(15, 9, 0, 2) rec[-246] rec[-46] + DETECTOR(15, 11, 0, 5) rec[-245] rec[-45] + DETECTOR(15, 13, 0, 2) rec[-244] rec[-44] + DETECTOR(15, 15, 0, 5) rec[-243] rec[-43] + DETECTOR(15, 17, 0, 2) rec[-242] rec[-42] + DETECTOR(15, 21, 0, 1) rec[-241] rec[-41] + DETECTOR(15, 23, 0, 0) rec[-240] rec[-40] + DETECTOR(15, 25, 0, 2) rec[-239] rec[-39] + DETECTOR(15, 27, 0, 1) rec[-238] rec[-38] + DETECTOR(16, 21, 0, 4) rec[-237] rec[-37] + DETECTOR(16, 23, 0, 3) rec[-236] rec[-36] + DETECTOR(16, 25, 0, 5) rec[-235] rec[-35] + DETECTOR(16, 27, 0, 4) rec[-234] rec[-34] + DETECTOR(17, -1, 0, 2) rec[-233] rec[-33] + DETECTOR(17, 1, 0, 3) rec[-232] rec[-32] + DETECTOR(17, 3, 0, 0) rec[-231] rec[-31] + DETECTOR(17, 5, 0, 3) rec[-230] rec[-30] + DETECTOR(17, 7, 0, 0) rec[-229] rec[-29] + DETECTOR(17, 9, 0, 3) rec[-228] rec[-28] + DETECTOR(17, 11, 0, 0) rec[-227] rec[-27] + DETECTOR(17, 13, 0, 3) rec[-226] rec[-26] + DETECTOR(17, 15, 0, 0) rec[-225] rec[-25] + DETECTOR(17, 17, 0, 3) rec[-224] rec[-24] + DETECTOR(17, 19.25, 0, 5) rec[-223] rec[-23] + DETECTOR(17, 19.5, 0, 0) rec[-222] rec[-22] + DETECTOR(17, 22, 0, 2) rec[-221] rec[-21] + DETECTOR(17, 24, 0, 1) rec[-220] rec[-20] + DETECTOR(18, 20, 0, 3) rec[-219] rec[-19] + DETECTOR(18, 22, 0, 5) rec[-218] rec[-18] + DETECTOR(18, 24, 0, 4) rec[-217] rec[-17] + DETECTOR(19, 1, 0, 2) rec[-216] rec[-16] + DETECTOR(19, 3, 0, 5) rec[-215] rec[-15] + DETECTOR(19, 5, 0, 2) rec[-214] rec[-14] + DETECTOR(19, 7, 0, 5) rec[-213] rec[-13] + DETECTOR(19, 9, 0, 2) rec[-212] rec[-12] + DETECTOR(19, 11, 0, 5) rec[-211] rec[-11] + DETECTOR(19, 13, 0, 2) rec[-210] rec[-10] + DETECTOR(19, 15, 0, 5) rec[-209] rec[-9] + DETECTOR(19, 17, 0, 2) rec[-208] rec[-8] + DETECTOR(19, 21, 0, 1) rec[-207] rec[-7] + DETECTOR(20, 21, 0, 4) rec[-206] rec[-6] + DETECTOR(21, 1, 0, 3) rec[-205] rec[-5] + DETECTOR(21, 5, 0, 3) rec[-204] rec[-4] + DETECTOR(21, 9, 0, 3) rec[-203] rec[-3] + DETECTOR(21, 13, 0, 3) rec[-202] rec[-2] + DETECTOR(21, 17, 0, 3) rec[-201] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK +} +MPP Z2*Z3 Z4*Z5 Z6*Z7 Z8*Z9 Z10*Z11 X1*X13 Z1*Z2*Z13*Z14 X2*X3*X14*X15 Z3*Z4*Z15*Z16 X4*X5*X16*X17 Z5*Z6*Z17*Z18 X6*X7*X18*X19 Z7*Z8*Z19*Z20 X8*X9*X20*X21 Z9*Z10*Z21*Z22 Z22*Z25*Z37*Z38 X10*X11*X12*X22*X23*X25 X12*X23*X24*X26 Z11*Z12*Z23*Z25 Z12*Z23*Z24*Z26 X13*X14*X28*X29 Z14*Z15*Z29*Z30 X15*X16*X30*X31 Z16*Z17*Z31*Z32 X17*X18*X32*X33 Z18*Z19*Z33*Z34 X19*X20*X34*X35 Z20*Z21*Z35*Z36 X21*X22*X36*X37 X23*X25*X26*X38*X39*X42 X24*X26*X27*X39*X40*X43 X27*X40*X41*X44 Z23*Z25*Z26*Z38*Z39*Z42 Z24*Z26*Z27*Z39*Z40*Z43 Z27*Z40*Z41*Z44 X28*X46 Z28*Z29*Z46*Z47 X29*X30*X47*X48 Z30*Z31*Z48*Z49 X31*X32*X49*X50 Z32*Z33*Z50*Z51 X33*X34*X51*X52 Z34*Z35*Z52*Z53 X35*X36*X53*X54 Z36*Z37*Z54*Z55 Z55*Z61*Z76*Z77 X37*X38*X42*X55*X56*X61 X39*X42*X43*X56*X57*X62 X40*X43*X44*X57*X58*X63 X41*X44*X45*X58*X59*X64 X45*X59*X60*X65 Z38*Z42*Z56*Z61 Z39*Z42*Z43*Z56*Z57*Z62 Z40*Z43*Z44*Z57*Z58*Z63 Z41*Z44*Z45*Z58*Z59*Z64 Z45*Z59*Z60*Z65 X46*X47*X67*X68 Z47*Z48*Z68*Z69 X48*X49*X69*X70 Z49*Z50*Z70*Z71 X50*X51*X71*X72 Z51*Z52*Z72*Z73 X52*X53*X73*X74 Z53*Z54*Z74*Z75 X54*X55*X75*X76 X56*X61*X62*X77*X78*X84 X57*X62*X63*X78*X79*X85 X58*X63*X64*X79*X80*X86 X59*X64*X65*X80*X81*X87 X60*X65*X66*X81*X82*X88 X66*X82*X83*X89 Z56*Z61*Z62*Z77*Z78*Z84 Z57*Z62*Z63*Z78*Z79*Z85 Z58*Z63*Z64*Z79*Z80*Z86 Z59*Z64*Z65*Z80*Z81*Z87 Z60*Z65*Z66*Z81*Z82*Z88 Z66*Z82*Z83*Z89 X67*X91 Z67*Z68*Z91*Z92 X68*X69*X92*X93 Z69*Z70*Z93*Z94 X70*X71*X94*X95 Z71*Z72*Z95*Z96 X72*X73*X96*X97 Z73*Z74*Z97*Z98 X74*X75*X98*X99 Z75*Z76*Z99*Z100 Z100*Z109*Z126*Z127 X76*X77*X84*X100*X101*X109 X78*X84*X85*X101*X102*X110 X79*X85*X86*X102*X103*X111 X80*X86*X87*X103*X104*X112 X81*X87*X88*X104*X105*X113 X82*X88*X89*X105*X106*X114 X83*X89*X90*X106*X107*X115 X90*X107*X108*X116 Z77*Z84*Z101*Z109 Z78*Z84*Z85*Z101*Z102*Z110 Z79*Z85*Z86*Z102*Z103*Z111 Z80*Z86*Z87*Z103*Z104*Z112 Z81*Z87*Z88*Z104*Z105*Z113 Z82*Z88*Z89*Z105*Z106*Z114 Z83*Z89*Z90*Z106*Z107*Z115 Z90*Z107*Z108*Z116 X91*X92*X117*X118 Z92*Z93*Z118*Z119 X93*X94*X119*X120 Z94*Z95*Z120*Z121 X95*X96*X121*X122 Z96*Z97*Z122*Z123 X97*X98*X123*X124 Z98*Z99*Z124*Z125 X99*X100*X125*X126 X101*X109*X110*X127*X128*X134 X102*X110*X111*X128*X129*X135 X103*X111*X112*X129*X130*X136 X104*X112*X113*X130*X131*X137 X105*X113*X114*X131*X132*X138 X106*X114*X115*X132*X133*X139 X107*X115*X116*X133 Z101*Z109*Z110*Z127*Z128*Z134 Z102*Z110*Z111*Z128*Z129*Z135 Z103*Z111*Z112*Z129*Z130*Z136 Z104*Z112*Z113*Z130*Z131*Z137 Z105*Z113*Z114*Z131*Z132*Z138 Z106*Z114*Z115*Z132*Z133*Z139 Z107*Z115*Z116*Z133 X117*X140 Z117*Z118*Z140*Z141 X118*X119*X141*X142 Z119*Z120*Z142*Z143 X120*X121*X143*X144 Z121*Z122*Z144*Z145 X122*X123*X145*X146 Z123*Z124*Z146*Z147 X124*X125*X147*X148 Z125*Z126*Z148*Z149 Z149*Z155*Z169*Z170 X126*X127*X134*X149*X150*X155 X128*X134*X135*X150*X151*X156 X129*X135*X136*X151*X152*X157 X130*X136*X137*X152*X153*X158 X131*X137*X138*X153*X154*X159 X132*X138*X139*X154 Z127*Z134*Z150*Z155 Z128*Z134*Z135*Z150*Z151*Z156 Z129*Z135*Z136*Z151*Z152*Z157 Z130*Z136*Z137*Z152*Z153*Z158 Z131*Z137*Z138*Z153*Z154*Z159 Z132*Z138*Z139*Z154 X140*X141*X160*X161 Z141*Z142*Z161*Z162 X142*X143*X162*X163 Z143*Z144*Z163*Z164 X144*X145*X164*X165 Z145*Z146*Z165*Z166 X146*X147*X166*X167 Z147*Z148*Z167*Z168 X148*X149*X168*X169 X150*X155*X156*X170*X171*X174 X151*X156*X157*X171*X172*X175 X152*X157*X158*X172*X173*X176 X153*X158*X159*X173 Z150*Z155*Z156*Z170*Z171*Z174 Z151*Z156*Z157*Z171*Z172*Z175 Z152*Z157*Z158*Z172*Z173*Z176 Z153*Z158*Z159*Z173 X160*X177 Z160*Z161*Z177*Z178 X161*X162*X178*X179 Z162*Z163*Z179*Z180 X163*X164*X180*X181 Z164*Z165*Z181*Z182 X165*X166*X182*X183 Z166*Z167*Z183*Z184 X167*X168*X184*X185 Z168*Z169*Z185*Z186 Z186*Z189*Z200*Z201 X169*X170*X174*X186*X187*X189 X171*X174*X175*X187*X188*X190 X172*X175*X176*X188 Z170*Z174*Z187*Z189 Z171*Z174*Z175*Z187*Z188*Z190 Z172*Z175*Z176*Z188 X177*X178*X191*X192 Z178*Z179*Z192*Z193 X179*X180*X193*X194 Z180*Z181*Z194*Z195 X181*X182*X195*X196 Z182*Z183*Z196*Z197 X183*X184*X197*X198 Z184*Z185*Z198*Z199 X185*X186*X199*X200 X187*X189*X190*X201 Z187*Z189*Z190*Z201 Z191*Z192 Z193*Z194 Z195*Z196 Z197*Z198 Z199*Z200 +DETECTOR(-1, 3, 0, 5) rec[-400] rec[-200] +DETECTOR(-1, 7, 0, 5) rec[-399] rec[-199] +DETECTOR(-1, 11, 0, 5) rec[-398] rec[-198] +DETECTOR(-1, 15, 0, 5) rec[-397] rec[-197] +DETECTOR(-1, 19, 0, 5) rec[-396] rec[-196] +DETECTOR(1, -1, 0, 2) rec[-395] rec[-195] +DETECTOR(1, 1, 0, 3) rec[-394] rec[-194] +DETECTOR(1, 3, 0, 0) rec[-393] rec[-193] +DETECTOR(1, 5, 0, 3) rec[-392] rec[-192] +DETECTOR(1, 7, 0, 0) rec[-391] rec[-191] +DETECTOR(1, 9, 0, 3) rec[-390] rec[-190] +DETECTOR(1, 11, 0, 0) rec[-389] rec[-189] +DETECTOR(1, 13, 0, 3) rec[-388] rec[-188] +DETECTOR(1, 15, 0, 0) rec[-387] rec[-187] +DETECTOR(1, 17, 0, 3) rec[-386] rec[-186] +DETECTOR(1, 19.25, 0, 5) rec[-385] rec[-185] +DETECTOR(1, 19.5, 0, 0) rec[-384] rec[-184] +DETECTOR(1, 22, 0, 2) rec[-383] rec[-183] +DETECTOR(2, 20, 0, 3) rec[-382] rec[-182] +DETECTOR(2, 22, 0, 5) rec[-381] rec[-181] +DETECTOR(3, 1, 0, 2) rec[-380] rec[-180] +DETECTOR(3, 3, 0, 5) rec[-379] rec[-179] +DETECTOR(3, 5, 0, 2) rec[-378] rec[-178] +DETECTOR(3, 7, 0, 5) rec[-377] rec[-177] +DETECTOR(3, 9, 0, 2) rec[-376] rec[-176] +DETECTOR(3, 11, 0, 5) rec[-375] rec[-175] +DETECTOR(3, 13, 0, 2) rec[-374] rec[-174] +DETECTOR(3, 15, 0, 5) rec[-373] rec[-173] +DETECTOR(3, 17, 0, 2) rec[-372] rec[-172] +DETECTOR(3, 21, 0, 1) rec[-371] rec[-171] +DETECTOR(3, 23, 0, 0) rec[-370] rec[-170] +DETECTOR(3, 25, 0, 2) rec[-369] rec[-169] +DETECTOR(4, 21, 0, 4) rec[-368] rec[-168] +DETECTOR(4, 23, 0, 3) rec[-367] rec[-167] +DETECTOR(4, 25, 0, 5) rec[-366] rec[-166] +DETECTOR(5, -1, 0, 2) rec[-365] rec[-165] +DETECTOR(5, 1, 0, 5) rec[-364] rec[-164] +DETECTOR(5, 3, 0, 2) rec[-363] rec[-163] +DETECTOR(5, 5, 0, 5) rec[-362] rec[-162] +DETECTOR(5, 7, 0, 2) rec[-361] rec[-161] +DETECTOR(5, 9, 0, 5) rec[-360] rec[-160] +DETECTOR(5, 11, 0, 2) rec[-359] rec[-159] +DETECTOR(5, 13, 0, 5) rec[-358] rec[-158] +DETECTOR(5, 15, 0, 2) rec[-357] rec[-157] +DETECTOR(5, 17, 0, 5) rec[-356] rec[-156] +DETECTOR(5, 19.25, 0, 5) rec[-355] rec[-155] +DETECTOR(5, 19.5, 0, 0) rec[-354] rec[-154] +DETECTOR(5, 22, 0, 2) rec[-353] rec[-153] +DETECTOR(5, 24, 0, 1) rec[-352] rec[-152] +DETECTOR(5, 26, 0, 0) rec[-351] rec[-151] +DETECTOR(5, 28, 0, 2) rec[-350] rec[-150] +DETECTOR(6, 20, 0, 3) rec[-349] rec[-149] +DETECTOR(6, 22, 0, 5) rec[-348] rec[-148] +DETECTOR(6, 24, 0, 4) rec[-347] rec[-147] +DETECTOR(6, 26, 0, 3) rec[-346] rec[-146] +DETECTOR(6, 28, 0, 5) rec[-345] rec[-145] +DETECTOR(7, 1, 0, 2) rec[-344] rec[-144] +DETECTOR(7, 3, 0, 5) rec[-343] rec[-143] +DETECTOR(7, 5, 0, 2) rec[-342] rec[-142] +DETECTOR(7, 7, 0, 5) rec[-341] rec[-141] +DETECTOR(7, 9, 0, 2) rec[-340] rec[-140] +DETECTOR(7, 11, 0, 5) rec[-339] rec[-139] +DETECTOR(7, 13, 0, 2) rec[-338] rec[-138] +DETECTOR(7, 15, 0, 5) rec[-337] rec[-137] +DETECTOR(7, 17, 0, 2) rec[-336] rec[-136] +DETECTOR(7, 21, 0, 1) rec[-335] rec[-135] +DETECTOR(7, 23, 0, 0) rec[-334] rec[-134] +DETECTOR(7, 25, 0, 2) rec[-333] rec[-133] +DETECTOR(7, 27, 0, 1) rec[-332] rec[-132] +DETECTOR(7, 29, 0, 0) rec[-331] rec[-131] +DETECTOR(7, 31, 0, 2) rec[-330] rec[-130] +DETECTOR(8, 21, 0, 4) rec[-329] rec[-129] +DETECTOR(8, 23, 0, 3) rec[-328] rec[-128] +DETECTOR(8, 25, 0, 5) rec[-327] rec[-127] +DETECTOR(8, 27, 0, 4) rec[-326] rec[-126] +DETECTOR(8, 29, 0, 3) rec[-325] rec[-125] +DETECTOR(8, 31, 0, 5) rec[-324] rec[-124] +DETECTOR(9, -1, 0, 2) rec[-323] rec[-123] +DETECTOR(9, 1, 0, 3) rec[-322] rec[-122] +DETECTOR(9, 3, 0, 0) rec[-321] rec[-121] +DETECTOR(9, 5, 0, 3) rec[-320] rec[-120] +DETECTOR(9, 7, 0, 0) rec[-319] rec[-119] +DETECTOR(9, 9, 0, 3) rec[-318] rec[-118] +DETECTOR(9, 11, 0, 0) rec[-317] rec[-117] +DETECTOR(9, 13, 0, 3) rec[-316] rec[-116] +DETECTOR(9, 15, 0, 0) rec[-315] rec[-115] +DETECTOR(9, 17, 0, 3) rec[-314] rec[-114] +DETECTOR(9, 19.25, 0, 5) rec[-313] rec[-113] +DETECTOR(9, 19.5, 0, 0) rec[-312] rec[-112] +DETECTOR(9, 22, 0, 2) rec[-311] rec[-111] +DETECTOR(9, 24, 0, 1) rec[-310] rec[-110] +DETECTOR(9, 26, 0, 0) rec[-309] rec[-109] +DETECTOR(9, 28, 0, 2) rec[-308] rec[-108] +DETECTOR(9, 30, 0, 1) rec[-307] rec[-107] +DETECTOR(9, 32, 0, 0) rec[-306] rec[-106] +DETECTOR(9, 34, 0, 2) rec[-305] rec[-105] +DETECTOR(10, 20, 0, 3) rec[-304] rec[-104] +DETECTOR(10, 22, 0, 5) rec[-303] rec[-103] +DETECTOR(10, 24, 0, 4) rec[-302] rec[-102] +DETECTOR(10, 26, 0, 3) rec[-301] rec[-101] +DETECTOR(10, 28, 0, 5) rec[-300] rec[-100] +DETECTOR(10, 30, 0, 4) rec[-299] rec[-99] +DETECTOR(10, 32, 0, 3) rec[-298] rec[-98] +DETECTOR(10, 34, 0, 5) rec[-297] rec[-97] +DETECTOR(11, 1, 0, 2) rec[-296] rec[-96] +DETECTOR(11, 3, 0, 5) rec[-295] rec[-95] +DETECTOR(11, 5, 0, 2) rec[-294] rec[-94] +DETECTOR(11, 7, 0, 5) rec[-293] rec[-93] +DETECTOR(11, 9, 0, 2) rec[-292] rec[-92] +DETECTOR(11, 11, 0, 5) rec[-291] rec[-91] +DETECTOR(11, 13, 0, 2) rec[-290] rec[-90] +DETECTOR(11, 15, 0, 5) rec[-289] rec[-89] +DETECTOR(11, 17, 0, 2) rec[-288] rec[-88] +DETECTOR(11, 21, 0, 1) rec[-287] rec[-87] +DETECTOR(11, 23, 0, 0) rec[-286] rec[-86] +DETECTOR(11, 25, 0, 2) rec[-285] rec[-85] +DETECTOR(11, 27, 0, 1) rec[-284] rec[-84] +DETECTOR(11, 29, 0, 0) rec[-283] rec[-83] +DETECTOR(11, 31, 0, 2) rec[-282] rec[-82] +DETECTOR(11, 33, 0, 1) rec[-281] rec[-81] +DETECTOR(12, 21, 0, 4) rec[-280] rec[-80] +DETECTOR(12, 23, 0, 3) rec[-279] rec[-79] +DETECTOR(12, 25, 0, 5) rec[-278] rec[-78] +DETECTOR(12, 27, 0, 4) rec[-277] rec[-77] +DETECTOR(12, 29, 0, 3) rec[-276] rec[-76] +DETECTOR(12, 31, 0, 5) rec[-275] rec[-75] +DETECTOR(12, 33, 0, 4) rec[-274] rec[-74] +DETECTOR(13, -1, 0, 2) rec[-273] rec[-73] +DETECTOR(13, 1, 0, 3) rec[-272] rec[-72] +DETECTOR(13, 3, 0, 0) rec[-271] rec[-71] +DETECTOR(13, 5, 0, 3) rec[-270] rec[-70] +DETECTOR(13, 7, 0, 0) rec[-269] rec[-69] +DETECTOR(13, 9, 0, 3) rec[-268] rec[-68] +DETECTOR(13, 11, 0, 0) rec[-267] rec[-67] +DETECTOR(13, 13, 0, 3) rec[-266] rec[-66] +DETECTOR(13, 15, 0, 0) rec[-265] rec[-65] +DETECTOR(13, 17, 0, 3) rec[-264] rec[-64] +DETECTOR(13, 19.25, 0, 5) rec[-263] rec[-63] +DETECTOR(13, 19.5, 0, 0) rec[-262] rec[-62] +DETECTOR(13, 22, 0, 2) rec[-261] rec[-61] +DETECTOR(13, 24, 0, 1) rec[-260] rec[-60] +DETECTOR(13, 26, 0, 0) rec[-259] rec[-59] +DETECTOR(13, 28, 0, 2) rec[-258] rec[-58] +DETECTOR(13, 30, 0, 1) rec[-257] rec[-57] +DETECTOR(14, 20, 0, 3) rec[-256] rec[-56] +DETECTOR(14, 22, 0, 5) rec[-255] rec[-55] +DETECTOR(14, 24, 0, 4) rec[-254] rec[-54] +DETECTOR(14, 26, 0, 3) rec[-253] rec[-53] +DETECTOR(14, 28, 0, 5) rec[-252] rec[-52] +DETECTOR(14, 30, 0, 4) rec[-251] rec[-51] +DETECTOR(15, 1, 0, 2) rec[-250] rec[-50] +DETECTOR(15, 3, 0, 5) rec[-249] rec[-49] +DETECTOR(15, 5, 0, 2) rec[-248] rec[-48] +DETECTOR(15, 7, 0, 5) rec[-247] rec[-47] +DETECTOR(15, 9, 0, 2) rec[-246] rec[-46] +DETECTOR(15, 11, 0, 5) rec[-245] rec[-45] +DETECTOR(15, 13, 0, 2) rec[-244] rec[-44] +DETECTOR(15, 15, 0, 5) rec[-243] rec[-43] +DETECTOR(15, 17, 0, 2) rec[-242] rec[-42] +DETECTOR(15, 21, 0, 1) rec[-241] rec[-41] +DETECTOR(15, 23, 0, 0) rec[-240] rec[-40] +DETECTOR(15, 25, 0, 2) rec[-239] rec[-39] +DETECTOR(15, 27, 0, 1) rec[-238] rec[-38] +DETECTOR(16, 21, 0, 4) rec[-237] rec[-37] +DETECTOR(16, 23, 0, 3) rec[-236] rec[-36] +DETECTOR(16, 25, 0, 5) rec[-235] rec[-35] +DETECTOR(16, 27, 0, 4) rec[-234] rec[-34] +DETECTOR(17, -1, 0, 2) rec[-233] rec[-33] +DETECTOR(17, 1, 0, 3) rec[-232] rec[-32] +DETECTOR(17, 3, 0, 0) rec[-231] rec[-31] +DETECTOR(17, 5, 0, 3) rec[-230] rec[-30] +DETECTOR(17, 7, 0, 0) rec[-229] rec[-29] +DETECTOR(17, 9, 0, 3) rec[-228] rec[-28] +DETECTOR(17, 11, 0, 0) rec[-227] rec[-27] +DETECTOR(17, 13, 0, 3) rec[-226] rec[-26] +DETECTOR(17, 15, 0, 0) rec[-225] rec[-25] +DETECTOR(17, 17, 0, 3) rec[-224] rec[-24] +DETECTOR(17, 19.25, 0, 5) rec[-223] rec[-23] +DETECTOR(17, 19.5, 0, 0) rec[-222] rec[-22] +DETECTOR(17, 22, 0, 2) rec[-221] rec[-21] +DETECTOR(17, 24, 0, 1) rec[-220] rec[-20] +DETECTOR(18, 20, 0, 3) rec[-219] rec[-19] +DETECTOR(18, 22, 0, 5) rec[-218] rec[-18] +DETECTOR(18, 24, 0, 4) rec[-217] rec[-17] +DETECTOR(19, 1, 0, 2) rec[-216] rec[-16] +DETECTOR(19, 3, 0, 5) rec[-215] rec[-15] +DETECTOR(19, 5, 0, 2) rec[-214] rec[-14] +DETECTOR(19, 7, 0, 5) rec[-213] rec[-13] +DETECTOR(19, 9, 0, 2) rec[-212] rec[-12] +DETECTOR(19, 11, 0, 5) rec[-211] rec[-11] +DETECTOR(19, 13, 0, 2) rec[-210] rec[-10] +DETECTOR(19, 15, 0, 5) rec[-209] rec[-9] +DETECTOR(19, 17, 0, 2) rec[-208] rec[-8] +DETECTOR(19, 21, 0, 1) rec[-207] rec[-7] +DETECTOR(20, 21, 0, 4) rec[-206] rec[-6] +DETECTOR(21, 1, 0, 3) rec[-205] rec[-5] +DETECTOR(21, 5, 0, 3) rec[-204] rec[-4] +DETECTOR(21, 9, 0, 3) rec[-203] rec[-3] +DETECTOR(21, 13, 0, 3) rec[-202] rec[-2] +DETECTOR(21, 17, 0, 3) rec[-201] rec[-1] +MPP X0*X108*X116*X133*X139*X154*X159*X173*X176*X188*X190*X191*X192*X193*X194*X195*X196*X197*X198*X199*X200*X201 +OBSERVABLE_INCLUDE(0) rec[-1] +MPP Z0*Z1*Z13*Z28*Z46*Z67*Z91*Z117*Z140*Z160*Z177*Z191 +OBSERVABLE_INCLUDE(1) rec[-1] diff --git a/test_data/midout488_color_code_d9_r33_p1000.stim b/test_data/midout488_color_code_d9_r33_p1000.stim new file mode 100644 index 0000000..c05148d --- /dev/null +++ b/test_data/midout488_color_code_d9_r33_p1000.stim @@ -0,0 +1,381 @@ +QUBIT_COORDS(0, 0) 0 +QUBIT_COORDS(0, 1) 1 +QUBIT_COORDS(0, 2) 2 +QUBIT_COORDS(1, 0) 3 +QUBIT_COORDS(1, 1) 4 +QUBIT_COORDS(1, 2) 5 +QUBIT_COORDS(2, 0) 6 +QUBIT_COORDS(2, 1) 7 +QUBIT_COORDS(2, 2) 8 +QUBIT_COORDS(2, 3) 9 +QUBIT_COORDS(2, 4) 10 +QUBIT_COORDS(2, 5) 11 +QUBIT_COORDS(2, 6) 12 +QUBIT_COORDS(3, 0) 13 +QUBIT_COORDS(3, 1) 14 +QUBIT_COORDS(3, 2) 15 +QUBIT_COORDS(3, 3) 16 +QUBIT_COORDS(3, 4) 17 +QUBIT_COORDS(3, 5) 18 +QUBIT_COORDS(3, 6) 19 +QUBIT_COORDS(4, 0) 20 +QUBIT_COORDS(4, 1) 21 +QUBIT_COORDS(4, 2) 22 +QUBIT_COORDS(4, 3) 23 +QUBIT_COORDS(4, 4) 24 +QUBIT_COORDS(4, 5) 25 +QUBIT_COORDS(4, 6) 26 +QUBIT_COORDS(4, 7) 27 +QUBIT_COORDS(4, 8) 28 +QUBIT_COORDS(5, 0) 29 +QUBIT_COORDS(5, 1) 30 +QUBIT_COORDS(5, 2) 31 +QUBIT_COORDS(5, 3) 32 +QUBIT_COORDS(5, 4) 33 +QUBIT_COORDS(5, 5) 34 +QUBIT_COORDS(5, 6) 35 +QUBIT_COORDS(5, 7) 36 +QUBIT_COORDS(5, 8) 37 +QUBIT_COORDS(6, 0) 38 +QUBIT_COORDS(6, 1) 39 +QUBIT_COORDS(6, 2) 40 +QUBIT_COORDS(6, 3) 41 +QUBIT_COORDS(6, 4) 42 +QUBIT_COORDS(6, 5) 43 +QUBIT_COORDS(6, 6) 44 +QUBIT_COORDS(6, 7) 45 +QUBIT_COORDS(6, 8) 46 +QUBIT_COORDS(7, 0) 47 +QUBIT_COORDS(7, 1) 48 +QUBIT_COORDS(7, 2) 49 +QUBIT_COORDS(7, 3) 50 +QUBIT_COORDS(7, 4) 51 +QUBIT_COORDS(8, 0) 52 +QUBIT_COORDS(8, 1) 53 +QUBIT_COORDS(8, 2) 54 +QUBIT_COORDS(8, 3) 55 +QUBIT_COORDS(8, 4) 56 +RX 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 0 3 4 5 10 13 14 15 16 17 18 19 28 29 30 31 32 33 34 35 36 37 43 47 48 49 50 51 53 +R 1 7 9 11 21 23 25 27 39 41 45 55 +X_ERROR(0.001) 1 7 9 11 21 23 25 27 39 41 45 55 +Z_ERROR(0.001) 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 0 3 4 5 10 13 14 15 16 17 18 19 28 29 30 31 32 33 34 35 36 37 43 47 48 49 50 51 53 +TICK +CX 4 1 6 3 8 5 14 7 16 9 18 11 20 13 22 15 24 17 26 19 30 21 32 23 34 25 36 27 38 29 40 31 42 33 44 35 46 37 48 39 50 41 52 47 54 49 56 51 +DEPOLARIZE2(0.001) 4 1 6 3 8 5 14 7 16 9 18 11 20 13 22 15 24 17 26 19 30 21 32 23 34 25 36 27 38 29 40 31 42 33 44 35 46 37 48 39 50 41 52 47 54 49 56 51 +DEPOLARIZE1(0.001) 0 2 10 12 28 43 45 53 55 +TICK +CX 2 1 5 4 8 7 10 9 12 11 15 14 17 16 19 18 22 21 24 23 26 25 28 27 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 49 48 51 50 54 53 56 55 +DEPOLARIZE2(0.001) 2 1 5 4 8 7 10 9 12 11 15 14 17 16 19 18 22 21 24 23 26 25 28 27 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 49 48 51 50 54 53 56 55 +DEPOLARIZE1(0.001) 0 3 6 13 20 29 38 47 52 +TICK +CX 0 1 3 4 6 7 9 8 10 11 13 14 16 15 17 18 20 21 23 22 24 25 27 26 29 30 32 31 33 34 36 35 38 39 41 40 42 43 45 44 47 48 50 49 52 53 55 54 +DEPOLARIZE2(0.001) 0 1 3 4 6 7 9 8 10 11 13 14 16 15 17 18 20 21 23 22 24 25 27 26 29 30 32 31 33 34 36 35 38 39 41 40 42 43 45 44 47 48 50 49 52 53 55 54 +DEPOLARIZE1(0.001) 2 5 12 19 28 37 46 51 56 +TICK +CX 1 0 4 3 7 6 8 9 11 10 14 13 15 16 18 17 21 20 22 23 25 24 26 27 30 29 31 32 34 33 35 36 39 38 40 41 43 42 44 45 48 47 49 50 53 52 54 55 +DEPOLARIZE2(0.001) 1 0 4 3 7 6 8 9 11 10 14 13 15 16 18 17 21 20 22 23 25 24 26 27 30 29 31 32 34 33 35 36 39 38 40 41 43 42 44 45 48 47 49 50 53 52 54 55 +DEPOLARIZE1(0.001) 2 5 12 19 28 37 46 51 56 +TICK +CX 1 2 4 5 7 8 9 10 11 12 14 15 16 17 18 19 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 48 49 50 51 53 54 55 56 +DEPOLARIZE2(0.001) 1 2 4 5 7 8 9 10 11 12 14 15 16 17 18 19 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 48 49 50 51 53 54 55 56 +DEPOLARIZE1(0.001) 0 3 6 13 20 29 38 47 52 +TICK +CX 1 4 3 6 5 8 7 14 9 16 11 18 13 20 15 22 17 24 19 26 21 30 23 32 25 34 27 36 29 38 31 40 33 42 35 44 37 46 39 48 41 50 47 52 49 54 51 56 +DEPOLARIZE2(0.001) 1 4 3 6 5 8 7 14 9 16 11 18 13 20 15 22 17 24 19 26 21 30 23 32 25 34 27 36 29 38 31 40 33 42 35 44 37 46 39 48 41 50 47 52 49 54 51 56 +DEPOLARIZE1(0.001) 0 2 10 12 28 43 45 53 55 +TICK +MX(0.001) 1 7 9 11 21 23 25 27 39 41 45 55 +M(0.001) 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 1 7 9 11 21 23 25 27 39 41 45 55 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 0 3 4 5 10 13 14 15 16 17 18 19 28 29 30 31 32 33 34 35 36 37 43 47 48 49 50 51 53 +TICK +RX 1 7 9 11 21 23 25 27 39 41 45 55 +R 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 +OBSERVABLE_INCLUDE(0) rec[-20] rec[-22] rec[-24] rec[-25] rec[-27] rec[-28] +X_ERROR(0.001) 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 +Z_ERROR(0.001) 1 7 9 11 21 23 25 27 39 41 45 55 +DEPOLARIZE1(0.001) 0 3 4 5 10 13 14 15 16 17 18 19 28 29 30 31 32 33 34 35 36 37 43 47 48 49 50 51 53 +TICK +CX 1 4 3 6 5 8 7 14 9 16 11 18 13 20 15 22 17 24 19 26 21 30 23 32 25 34 27 36 29 38 31 40 33 42 35 44 37 46 39 48 41 50 47 52 49 54 51 56 +DEPOLARIZE2(0.001) 1 4 3 6 5 8 7 14 9 16 11 18 13 20 15 22 17 24 19 26 21 30 23 32 25 34 27 36 29 38 31 40 33 42 35 44 37 46 39 48 41 50 47 52 49 54 51 56 +DEPOLARIZE1(0.001) 0 2 10 12 28 43 45 53 55 +TICK +CX 1 2 4 5 7 8 9 10 11 12 14 15 16 17 18 19 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 48 49 50 51 53 54 55 56 +DEPOLARIZE2(0.001) 1 2 4 5 7 8 9 10 11 12 14 15 16 17 18 19 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 48 49 50 51 53 54 55 56 +DEPOLARIZE1(0.001) 0 3 6 13 20 29 38 47 52 +TICK +CX 1 0 4 3 7 6 8 9 11 10 14 13 15 16 18 17 21 20 22 23 25 24 26 27 30 29 31 32 34 33 35 36 39 38 40 41 43 42 44 45 48 47 49 50 53 52 54 55 +DETECTOR(0, 1, 0, 1) rec[-28] +DETECTOR(2, 1, 0, 1) rec[-27] +DETECTOR(2, 3, 0, 0) rec[-26] +DETECTOR(2, 5, 0, 1) rec[-25] +DETECTOR(4, 1, 0, 1) rec[-24] +DETECTOR(4, 3, 0, 0) rec[-23] +DETECTOR(4, 5, 0, 1) rec[-22] +DETECTOR(4, 7, 0, 0) rec[-21] +DETECTOR(6, 1, 0, 1) rec[-20] +DETECTOR(6, 3, 0, 0) rec[-19] +DETECTOR(6, 7, 0, 0) rec[-18] +DETECTOR(8, 3, 0, 0) rec[-17] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE2(0.001) 1 0 4 3 7 6 8 9 11 10 14 13 15 16 18 17 21 20 22 23 25 24 26 27 30 29 31 32 34 33 35 36 39 38 40 41 43 42 44 45 48 47 49 50 53 52 54 55 +DEPOLARIZE1(0.001) 2 5 12 19 28 37 46 51 56 +TICK +CX 0 1 3 4 6 7 9 8 10 11 13 14 16 15 17 18 20 21 23 22 24 25 27 26 29 30 32 31 33 34 36 35 38 39 41 40 42 43 45 44 47 48 50 49 52 53 55 54 +DEPOLARIZE2(0.001) 0 1 3 4 6 7 9 8 10 11 13 14 16 15 17 18 20 21 23 22 24 25 27 26 29 30 32 31 33 34 36 35 38 39 41 40 42 43 45 44 47 48 50 49 52 53 55 54 +DEPOLARIZE1(0.001) 2 5 12 19 28 37 46 51 56 +TICK +CX 2 1 5 4 8 7 10 9 12 11 15 14 17 16 19 18 22 21 24 23 26 25 28 27 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 49 48 51 50 54 53 56 55 +DEPOLARIZE2(0.001) 2 1 5 4 8 7 10 9 12 11 15 14 17 16 19 18 22 21 24 23 26 25 28 27 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 49 48 51 50 54 53 56 55 +DEPOLARIZE1(0.001) 0 3 6 13 20 29 38 47 52 +TICK +CX 4 1 6 3 8 5 14 7 16 9 18 11 20 13 22 15 24 17 26 19 30 21 32 23 34 25 36 27 38 29 40 31 42 33 44 35 46 37 48 39 50 41 52 47 54 49 56 51 +DEPOLARIZE2(0.001) 4 1 6 3 8 5 14 7 16 9 18 11 20 13 22 15 24 17 26 19 30 21 32 23 34 25 36 27 38 29 40 31 42 33 44 35 46 37 48 39 50 41 52 47 54 49 56 51 +DEPOLARIZE1(0.001) 0 2 10 12 28 43 45 53 55 +TICK +MX(0.001) 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 +M(0.001) 1 7 9 11 21 23 25 27 39 41 45 55 +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 1 7 9 11 21 23 25 27 39 41 45 55 0 3 4 5 10 13 14 15 16 17 18 19 28 29 30 31 32 33 34 35 36 37 43 47 48 49 50 51 53 +TICK +RX 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 +R 1 7 9 11 21 23 25 27 39 41 45 55 +OBSERVABLE_INCLUDE(0) rec[-13] rec[-15] rec[-16] rec[-18] rec[-20] rec[-22] rec[-24] rec[-25] rec[-27] rec[-28] +X_ERROR(0.001) 1 7 9 11 21 23 25 27 39 41 45 55 +Z_ERROR(0.001) 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 +DEPOLARIZE1(0.001) 0 3 4 5 10 13 14 15 16 17 18 19 28 29 30 31 32 33 34 35 36 37 43 47 48 49 50 51 53 +TICK +CX 4 1 6 3 8 5 14 7 16 9 18 11 20 13 22 15 24 17 26 19 30 21 32 23 34 25 36 27 38 29 40 31 42 33 44 35 46 37 48 39 50 41 52 47 54 49 56 51 +DEPOLARIZE2(0.001) 4 1 6 3 8 5 14 7 16 9 18 11 20 13 22 15 24 17 26 19 30 21 32 23 34 25 36 27 38 29 40 31 42 33 44 35 46 37 48 39 50 41 52 47 54 49 56 51 +DEPOLARIZE1(0.001) 0 2 10 12 28 43 45 53 55 +TICK +CX 2 1 5 4 8 7 10 9 12 11 15 14 17 16 19 18 22 21 24 23 26 25 28 27 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 49 48 51 50 54 53 56 55 +DEPOLARIZE2(0.001) 2 1 5 4 8 7 10 9 12 11 15 14 17 16 19 18 22 21 24 23 26 25 28 27 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 49 48 51 50 54 53 56 55 +DEPOLARIZE1(0.001) 0 3 6 13 20 29 38 47 52 +TICK +CX 0 1 3 4 6 7 9 8 10 11 13 14 16 15 17 18 20 21 23 22 24 25 27 26 29 30 32 31 33 34 36 35 38 39 41 40 42 43 45 44 47 48 50 49 52 53 55 54 +DETECTOR(0, 1, 0, 4) rec[-44] rec[-12] +DETECTOR(0, 2, 0, 0) rec[-56] rec[-28] +DETECTOR(2, 0, 0, 2) rec[-55] rec[-27] +DETECTOR(2, 1, 0, 4) rec[-43] rec[-11] +DETECTOR(2, 2, 0, 0) rec[-55] rec[-54] rec[-26] +DETECTOR(2, 3, 0, 3) rec[-42] rec[-10] +DETECTOR(2, 5, 0, 4) rec[-41] rec[-9] +DETECTOR(2, 6, 0, 0) rec[-53] rec[-25] +DETECTOR(4, 0, 0, 2) rec[-52] rec[-24] +DETECTOR(4, 1, 0, 4) rec[-40] rec[-8] +DETECTOR(4, 2, 0, 0) rec[-52] rec[-51] rec[-23] +DETECTOR(4, 3, 0, 3) rec[-39] rec[-38] rec[-7] +DETECTOR(4, 4, 0, 2) rec[-50] rec[-22] +DETECTOR(4, 5, 0, 4) rec[-38] rec[-6] +DETECTOR(4, 6, 0, 0) rec[-50] rec[-49] rec[-21] +DETECTOR(4, 7, 0, 3) rec[-37] rec[-5] +DETECTOR(6, 0, 0, 2) rec[-48] rec[-20] +DETECTOR(6, 1, 0, 4) rec[-36] rec[-4] +DETECTOR(6, 2, 0, 0) rec[-48] rec[-47] rec[-19] +DETECTOR(6, 3, 0, 3) rec[-35] rec[-34] rec[-3] +DETECTOR(6, 4, 0, 2) rec[-18] +DETECTOR(6, 6, 0, 0) rec[-46] rec[-17] +DETECTOR(6, 7, 0, 3) rec[-33] rec[-32] rec[-2] +DETECTOR(6, 8, 0, 2) rec[-16] +DETECTOR(8, 0, 0, 2) rec[-15] +DETECTOR(8, 2, 0, 0) rec[-45] rec[-14] +DETECTOR(8, 3, 0, 3) rec[-30] rec[-29] rec[-1] +DETECTOR(8, 4, 0, 2) rec[-13] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE2(0.001) 0 1 3 4 6 7 9 8 10 11 13 14 16 15 17 18 20 21 23 22 24 25 27 26 29 30 32 31 33 34 36 35 38 39 41 40 42 43 45 44 47 48 50 49 52 53 55 54 +DEPOLARIZE1(0.001) 2 5 12 19 28 37 46 51 56 +TICK +REPEAT 15 { + CX 1 0 4 3 7 6 8 9 11 10 14 13 15 16 18 17 21 20 22 23 25 24 26 27 30 29 31 32 34 33 35 36 39 38 40 41 43 42 44 45 48 47 49 50 53 52 54 55 + DEPOLARIZE2(0.001) 1 0 4 3 7 6 8 9 11 10 14 13 15 16 18 17 21 20 22 23 25 24 26 27 30 29 31 32 34 33 35 36 39 38 40 41 43 42 44 45 48 47 49 50 53 52 54 55 + DEPOLARIZE1(0.001) 2 5 12 19 28 37 46 51 56 + TICK + CX 1 2 4 5 7 8 9 10 11 12 14 15 16 17 18 19 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 48 49 50 51 53 54 55 56 + DEPOLARIZE2(0.001) 1 2 4 5 7 8 9 10 11 12 14 15 16 17 18 19 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 48 49 50 51 53 54 55 56 + DEPOLARIZE1(0.001) 0 3 6 13 20 29 38 47 52 + TICK + CX 1 4 3 6 5 8 7 14 9 16 11 18 13 20 15 22 17 24 19 26 21 30 23 32 25 34 27 36 29 38 31 40 33 42 35 44 37 46 39 48 41 50 47 52 49 54 51 56 + DEPOLARIZE2(0.001) 1 4 3 6 5 8 7 14 9 16 11 18 13 20 15 22 17 24 19 26 21 30 23 32 25 34 27 36 29 38 31 40 33 42 35 44 37 46 39 48 41 50 47 52 49 54 51 56 + DEPOLARIZE1(0.001) 0 2 10 12 28 43 45 53 55 + TICK + MX(0.001) 1 7 9 11 21 23 25 27 39 41 45 55 + M(0.001) 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 1 7 9 11 21 23 25 27 39 41 45 55 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 0 3 4 5 10 13 14 15 16 17 18 19 28 29 30 31 32 33 34 35 36 37 43 47 48 49 50 51 53 + TICK + RX 1 7 9 11 21 23 25 27 39 41 45 55 + R 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 + OBSERVABLE_INCLUDE(0) rec[-20] rec[-22] rec[-24] rec[-25] rec[-27] rec[-28] + X_ERROR(0.001) 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 + Z_ERROR(0.001) 1 7 9 11 21 23 25 27 39 41 45 55 + DEPOLARIZE1(0.001) 0 3 4 5 10 13 14 15 16 17 18 19 28 29 30 31 32 33 34 35 36 37 43 47 48 49 50 51 53 + TICK + CX 1 4 3 6 5 8 7 14 9 16 11 18 13 20 15 22 17 24 19 26 21 30 23 32 25 34 27 36 29 38 31 40 33 42 35 44 37 46 39 48 41 50 47 52 49 54 51 56 + DEPOLARIZE2(0.001) 1 4 3 6 5 8 7 14 9 16 11 18 13 20 15 22 17 24 19 26 21 30 23 32 25 34 27 36 29 38 31 40 33 42 35 44 37 46 39 48 41 50 47 52 49 54 51 56 + DEPOLARIZE1(0.001) 0 2 10 12 28 43 45 53 55 + TICK + CX 1 2 4 5 7 8 9 10 11 12 14 15 16 17 18 19 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 48 49 50 51 53 54 55 56 + DEPOLARIZE2(0.001) 1 2 4 5 7 8 9 10 11 12 14 15 16 17 18 19 21 22 23 24 25 26 27 28 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 48 49 50 51 53 54 55 56 + DEPOLARIZE1(0.001) 0 3 6 13 20 29 38 47 52 + TICK + CX 1 0 4 3 7 6 8 9 11 10 14 13 15 16 18 17 21 20 22 23 25 24 26 27 30 29 31 32 34 33 35 36 39 38 40 41 43 42 44 45 48 47 49 50 53 52 54 55 + DETECTOR(0, 1, 0, 1) rec[-56] rec[-28] + DETECTOR(0, 2, 0, 3) rec[-40] rec[-16] + DETECTOR(2, 0, 0, 5) rec[-39] rec[-15] + DETECTOR(2, 1, 0, 1) rec[-55] rec[-27] + DETECTOR(2, 2, 0, 3) rec[-39] rec[-38] rec[-14] + DETECTOR(2, 3, 0, 0) rec[-54] rec[-26] + DETECTOR(2, 5, 0, 1) rec[-53] rec[-25] + DETECTOR(2, 6, 0, 3) rec[-37] rec[-13] + DETECTOR(4, 0, 0, 5) rec[-36] rec[-12] + DETECTOR(4, 1, 0, 1) rec[-52] rec[-24] + DETECTOR(4, 2, 0, 3) rec[-36] rec[-35] rec[-11] + DETECTOR(4, 3, 0, 0) rec[-51] rec[-50] rec[-23] + DETECTOR(4, 4, 0, 5) rec[-34] rec[-10] + DETECTOR(4, 5, 0, 1) rec[-50] rec[-22] + DETECTOR(4, 6, 0, 3) rec[-34] rec[-33] rec[-9] + DETECTOR(4, 7, 0, 0) rec[-49] rec[-21] + DETECTOR(6, 0, 0, 5) rec[-32] rec[-8] + DETECTOR(6, 1, 0, 1) rec[-48] rec[-20] + DETECTOR(6, 2, 0, 3) rec[-32] rec[-31] rec[-7] + DETECTOR(6, 3, 0, 0) rec[-47] rec[-46] rec[-19] + DETECTOR(6, 4, 0, 5) rec[-6] + DETECTOR(6, 6, 0, 3) rec[-30] rec[-5] + DETECTOR(6, 7, 0, 0) rec[-45] rec[-44] rec[-18] + DETECTOR(6, 8, 0, 5) rec[-4] + DETECTOR(8, 0, 0, 5) rec[-3] + DETECTOR(8, 2, 0, 3) rec[-29] rec[-2] + DETECTOR(8, 3, 0, 0) rec[-42] rec[-41] rec[-17] + DETECTOR(8, 4, 0, 5) rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 1 0 4 3 7 6 8 9 11 10 14 13 15 16 18 17 21 20 22 23 25 24 26 27 30 29 31 32 34 33 35 36 39 38 40 41 43 42 44 45 48 47 49 50 53 52 54 55 + DEPOLARIZE1(0.001) 2 5 12 19 28 37 46 51 56 + TICK + CX 0 1 3 4 6 7 9 8 10 11 13 14 16 15 17 18 20 21 23 22 24 25 27 26 29 30 32 31 33 34 36 35 38 39 41 40 42 43 45 44 47 48 50 49 52 53 55 54 + DEPOLARIZE2(0.001) 0 1 3 4 6 7 9 8 10 11 13 14 16 15 17 18 20 21 23 22 24 25 27 26 29 30 32 31 33 34 36 35 38 39 41 40 42 43 45 44 47 48 50 49 52 53 55 54 + DEPOLARIZE1(0.001) 2 5 12 19 28 37 46 51 56 + TICK + CX 2 1 5 4 8 7 10 9 12 11 15 14 17 16 19 18 22 21 24 23 26 25 28 27 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 49 48 51 50 54 53 56 55 + DEPOLARIZE2(0.001) 2 1 5 4 8 7 10 9 12 11 15 14 17 16 19 18 22 21 24 23 26 25 28 27 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 49 48 51 50 54 53 56 55 + DEPOLARIZE1(0.001) 0 3 6 13 20 29 38 47 52 + TICK + CX 4 1 6 3 8 5 14 7 16 9 18 11 20 13 22 15 24 17 26 19 30 21 32 23 34 25 36 27 38 29 40 31 42 33 44 35 46 37 48 39 50 41 52 47 54 49 56 51 + DEPOLARIZE2(0.001) 4 1 6 3 8 5 14 7 16 9 18 11 20 13 22 15 24 17 26 19 30 21 32 23 34 25 36 27 38 29 40 31 42 33 44 35 46 37 48 39 50 41 52 47 54 49 56 51 + DEPOLARIZE1(0.001) 0 2 10 12 28 43 45 53 55 + TICK + MX(0.001) 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 + M(0.001) 1 7 9 11 21 23 25 27 39 41 45 55 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 1 7 9 11 21 23 25 27 39 41 45 55 0 3 4 5 10 13 14 15 16 17 18 19 28 29 30 31 32 33 34 35 36 37 43 47 48 49 50 51 53 + TICK + RX 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 + R 1 7 9 11 21 23 25 27 39 41 45 55 + OBSERVABLE_INCLUDE(0) rec[-13] rec[-15] rec[-16] rec[-18] rec[-20] rec[-22] rec[-24] rec[-25] rec[-27] rec[-28] + X_ERROR(0.001) 1 7 9 11 21 23 25 27 39 41 45 55 + Z_ERROR(0.001) 2 6 8 12 20 22 24 26 38 40 42 44 46 52 54 56 + DEPOLARIZE1(0.001) 0 3 4 5 10 13 14 15 16 17 18 19 28 29 30 31 32 33 34 35 36 37 43 47 48 49 50 51 53 + TICK + CX 4 1 6 3 8 5 14 7 16 9 18 11 20 13 22 15 24 17 26 19 30 21 32 23 34 25 36 27 38 29 40 31 42 33 44 35 46 37 48 39 50 41 52 47 54 49 56 51 + DEPOLARIZE2(0.001) 4 1 6 3 8 5 14 7 16 9 18 11 20 13 22 15 24 17 26 19 30 21 32 23 34 25 36 27 38 29 40 31 42 33 44 35 46 37 48 39 50 41 52 47 54 49 56 51 + DEPOLARIZE1(0.001) 0 2 10 12 28 43 45 53 55 + TICK + CX 2 1 5 4 8 7 10 9 12 11 15 14 17 16 19 18 22 21 24 23 26 25 28 27 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 49 48 51 50 54 53 56 55 + DEPOLARIZE2(0.001) 2 1 5 4 8 7 10 9 12 11 15 14 17 16 19 18 22 21 24 23 26 25 28 27 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 49 48 51 50 54 53 56 55 + DEPOLARIZE1(0.001) 0 3 6 13 20 29 38 47 52 + TICK + CX 0 1 3 4 6 7 9 8 10 11 13 14 16 15 17 18 20 21 23 22 24 25 27 26 29 30 32 31 33 34 36 35 38 39 41 40 42 43 45 44 47 48 50 49 52 53 55 54 + DETECTOR(0, 1, 0, 4) rec[-44] rec[-12] + DETECTOR(0, 2, 0, 0) rec[-56] rec[-28] + DETECTOR(2, 0, 0, 2) rec[-55] rec[-27] + DETECTOR(2, 1, 0, 4) rec[-43] rec[-11] + DETECTOR(2, 2, 0, 0) rec[-55] rec[-54] rec[-26] + DETECTOR(2, 3, 0, 3) rec[-42] rec[-10] + DETECTOR(2, 5, 0, 4) rec[-41] rec[-9] + DETECTOR(2, 6, 0, 0) rec[-53] rec[-25] + DETECTOR(4, 0, 0, 2) rec[-52] rec[-24] + DETECTOR(4, 1, 0, 4) rec[-40] rec[-8] + DETECTOR(4, 2, 0, 0) rec[-52] rec[-51] rec[-23] + DETECTOR(4, 3, 0, 3) rec[-39] rec[-38] rec[-7] + DETECTOR(4, 4, 0, 2) rec[-50] rec[-22] + DETECTOR(4, 5, 0, 4) rec[-38] rec[-6] + DETECTOR(4, 6, 0, 0) rec[-50] rec[-49] rec[-21] + DETECTOR(4, 7, 0, 3) rec[-37] rec[-5] + DETECTOR(6, 0, 0, 2) rec[-48] rec[-20] + DETECTOR(6, 1, 0, 4) rec[-36] rec[-4] + DETECTOR(6, 2, 0, 0) rec[-48] rec[-47] rec[-19] + DETECTOR(6, 3, 0, 3) rec[-35] rec[-34] rec[-3] + DETECTOR(6, 4, 0, 2) rec[-18] + DETECTOR(6, 6, 0, 0) rec[-46] rec[-17] + DETECTOR(6, 7, 0, 3) rec[-33] rec[-32] rec[-2] + DETECTOR(6, 8, 0, 2) rec[-16] + DETECTOR(8, 0, 0, 2) rec[-15] + DETECTOR(8, 2, 0, 0) rec[-45] rec[-14] + DETECTOR(8, 3, 0, 3) rec[-30] rec[-29] rec[-1] + DETECTOR(8, 4, 0, 2) rec[-13] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 0 1 3 4 6 7 9 8 10 11 13 14 16 15 17 18 20 21 23 22 24 25 27 26 29 30 32 31 33 34 36 35 38 39 41 40 42 43 45 44 47 48 50 49 52 53 55 54 + DEPOLARIZE1(0.001) 2 5 12 19 28 37 46 51 56 + TICK +} +CX 54 55 53 52 49 50 48 47 44 45 43 42 40 41 39 38 35 36 34 33 31 32 30 29 26 27 25 24 22 23 21 20 18 17 15 16 14 13 11 10 8 9 7 6 4 3 1 0 +DEPOLARIZE2(0.001) 54 55 53 52 49 50 48 47 44 45 43 42 40 41 39 38 35 36 34 33 31 32 30 29 26 27 25 24 22 23 21 20 18 17 15 16 14 13 11 10 8 9 7 6 4 3 1 0 +DEPOLARIZE1(0.001) 2 5 12 19 28 37 46 51 56 +TICK +CX 55 56 53 54 50 51 48 49 45 46 43 44 41 42 39 40 36 37 34 35 32 33 30 31 27 28 25 26 23 24 21 22 18 19 16 17 14 15 11 12 9 10 7 8 4 5 1 2 +DEPOLARIZE2(0.001) 55 56 53 54 50 51 48 49 45 46 43 44 41 42 39 40 36 37 34 35 32 33 30 31 27 28 25 26 23 24 21 22 18 19 16 17 14 15 11 12 9 10 7 8 4 5 1 2 +DEPOLARIZE1(0.001) 0 3 6 13 20 29 38 47 52 +TICK +CX 51 56 49 54 47 52 41 50 39 48 37 46 35 44 33 42 31 40 29 38 27 36 25 34 23 32 21 30 19 26 17 24 15 22 13 20 11 18 9 16 7 14 5 8 3 6 1 4 +DEPOLARIZE2(0.001) 51 56 49 54 47 52 41 50 39 48 37 46 35 44 33 42 31 40 29 38 27 36 25 34 23 32 21 30 19 26 17 24 15 22 13 20 11 18 9 16 7 14 5 8 3 6 1 4 +DEPOLARIZE1(0.001) 0 2 10 12 28 43 45 53 55 +TICK +M(0.001) 56 54 52 46 44 42 40 38 26 24 22 20 12 8 6 2 +MX(0.001) 53 51 50 49 48 47 43 37 36 35 34 33 32 31 30 29 28 19 18 17 16 15 14 13 10 5 4 3 0 55 45 41 39 27 25 23 21 11 9 7 1 +DETECTOR(0, 1, 0, 1) rec[-85] rec[-1] +DETECTOR(0, 2, 0, 0) rec[-15] rec[-13] rec[-1] +DETECTOR(0, 2, 0, 3) rec[-69] rec[-42] +DETECTOR(2, 0, 0, 2) rec[-19] rec[-16] rec[-15] rec[-2] +DETECTOR(2, 0, 0, 5) rec[-68] rec[-43] +DETECTOR(2, 1, 0, 1) rec[-84] rec[-2] +DETECTOR(2, 2, 0, 0) rec[-21] rec[-19] rec[-17] rec[-15] rec[-14] rec[-3] rec[-2] +DETECTOR(2, 2, 0, 3) rec[-68] rec[-67] rec[-44] +DETECTOR(2, 3, 0, 0) rec[-83] rec[-3] +DETECTOR(2, 5, 0, 1) rec[-82] rec[-4] +DETECTOR(2, 6, 0, 0) rec[-23] rec[-17] rec[-4] +DETECTOR(2, 6, 0, 3) rec[-66] rec[-45] +DETECTOR(4, 0, 0, 2) rec[-27] rec[-20] rec[-19] rec[-5] +DETECTOR(4, 0, 0, 5) rec[-65] rec[-46] +DETECTOR(4, 1, 0, 1) rec[-81] rec[-5] +DETECTOR(4, 2, 0, 0) rec[-29] rec[-27] rec[-22] rec[-21] rec[-19] rec[-18] rec[-6] rec[-5] +DETECTOR(4, 2, 0, 3) rec[-65] rec[-64] rec[-47] +DETECTOR(4, 3, 0, 0) rec[-80] rec[-79] rec[-6] +DETECTOR(4, 4, 0, 2) rec[-31] rec[-24] rec[-23] rec[-20] rec[-7] +DETECTOR(4, 4, 0, 5) rec[-63] rec[-48] +DETECTOR(4, 5, 0, 1) rec[-79] rec[-7] +DETECTOR(4, 6, 0, 0) rec[-33] rec[-31] rec[-25] rec[-23] rec[-22] rec[-8] rec[-7] +DETECTOR(4, 6, 0, 3) rec[-63] rec[-62] rec[-49] +DETECTOR(4, 7, 0, 0) rec[-78] rec[-8] +DETECTOR(6, 0, 0, 2) rec[-37] rec[-28] rec[-27] rec[-9] +DETECTOR(6, 0, 0, 5) rec[-61] rec[-50] +DETECTOR(6, 1, 0, 1) rec[-77] rec[-9] +DETECTOR(6, 2, 0, 0) rec[-39] rec[-37] rec[-30] rec[-29] rec[-27] rec[-26] rec[-10] rec[-9] +DETECTOR(6, 2, 0, 3) rec[-61] rec[-60] rec[-51] +DETECTOR(6, 3, 0, 0) rec[-76] rec[-75] rec[-10] +DETECTOR(6, 4, 0, 2) rec[-35] rec[-32] rec[-31] rec[-28] +DETECTOR(6, 4, 0, 5) rec[-52] +DETECTOR(6, 6, 0, 0) rec[-35] rec[-34] rec[-33] rec[-31] rec[-30] rec[-11] +DETECTOR(6, 6, 0, 3) rec[-59] rec[-53] +DETECTOR(6, 7, 0, 0) rec[-74] rec[-73] rec[-11] +DETECTOR(6, 8, 0, 2) rec[-34] rec[-32] +DETECTOR(6, 8, 0, 5) rec[-54] +DETECTOR(8, 0, 0, 2) rec[-41] rec[-38] rec[-37] +DETECTOR(8, 0, 0, 5) rec[-55] +DETECTOR(8, 2, 0, 0) rec[-41] rec[-40] rec[-39] rec[-37] rec[-36] rec[-12] +DETECTOR(8, 2, 0, 3) rec[-58] rec[-56] +DETECTOR(8, 3, 0, 0) rec[-71] rec[-70] rec[-12] +DETECTOR(8, 4, 0, 2) rec[-40] rec[-38] +DETECTOR(8, 4, 0, 5) rec[-57] +OBSERVABLE_INCLUDE(0) rec[-41] rec[-40] rec[-35] rec[-34] rec[-25] rec[-9] rec[-7] rec[-5] rec[-4] rec[-2] rec[-1] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 56 54 52 46 44 42 40 38 26 24 22 20 12 8 6 2 53 51 50 49 48 47 43 37 36 35 34 33 32 31 30 29 28 19 18 17 16 15 14 13 10 5 4 3 0 55 45 41 39 27 25 23 21 11 9 7 1 diff --git a/test_data/midout_color_code_d25_r100_p1000.stim b/test_data/midout_color_code_d25_r100_p1000.stim new file mode 100644 index 0000000..06c2ed5 --- /dev/null +++ b/test_data/midout_color_code_d25_r100_p1000.stim @@ -0,0 +1,2196 @@ +QUBIT_COORDS(0, 1) 0 +QUBIT_COORDS(1, 1) 1 +QUBIT_COORDS(1, 2) 2 +QUBIT_COORDS(1, 3) 3 +QUBIT_COORDS(1, 4) 4 +QUBIT_COORDS(1, 5) 5 +QUBIT_COORDS(1, 6) 6 +QUBIT_COORDS(2, 1) 7 +QUBIT_COORDS(2, 2) 8 +QUBIT_COORDS(2, 3) 9 +QUBIT_COORDS(2, 4) 10 +QUBIT_COORDS(2, 5) 11 +QUBIT_COORDS(2, 6) 12 +QUBIT_COORDS(2, 7) 13 +QUBIT_COORDS(3, 1) 14 +QUBIT_COORDS(3, 2) 15 +QUBIT_COORDS(3, 3) 16 +QUBIT_COORDS(3, 4) 17 +QUBIT_COORDS(3, 5) 18 +QUBIT_COORDS(3, 6) 19 +QUBIT_COORDS(3, 7) 20 +QUBIT_COORDS(3, 8) 21 +QUBIT_COORDS(3, 9) 22 +QUBIT_COORDS(3, 10) 23 +QUBIT_COORDS(3, 11) 24 +QUBIT_COORDS(3, 12) 25 +QUBIT_COORDS(4, 1) 26 +QUBIT_COORDS(4, 2) 27 +QUBIT_COORDS(4, 3) 28 +QUBIT_COORDS(4, 4) 29 +QUBIT_COORDS(4, 5) 30 +QUBIT_COORDS(4, 6) 31 +QUBIT_COORDS(4, 7) 32 +QUBIT_COORDS(4, 8) 33 +QUBIT_COORDS(4, 9) 34 +QUBIT_COORDS(4, 10) 35 +QUBIT_COORDS(4, 11) 36 +QUBIT_COORDS(4, 12) 37 +QUBIT_COORDS(4, 13) 38 +QUBIT_COORDS(5, 1) 39 +QUBIT_COORDS(5, 2) 40 +QUBIT_COORDS(5, 3) 41 +QUBIT_COORDS(5, 4) 42 +QUBIT_COORDS(5, 5) 43 +QUBIT_COORDS(5, 6) 44 +QUBIT_COORDS(5, 7) 45 +QUBIT_COORDS(5, 8) 46 +QUBIT_COORDS(5, 9) 47 +QUBIT_COORDS(5, 10) 48 +QUBIT_COORDS(5, 11) 49 +QUBIT_COORDS(5, 12) 50 +QUBIT_COORDS(5, 13) 51 +QUBIT_COORDS(5, 14) 52 +QUBIT_COORDS(5, 15) 53 +QUBIT_COORDS(5, 16) 54 +QUBIT_COORDS(5, 17) 55 +QUBIT_COORDS(5, 18) 56 +QUBIT_COORDS(6, 1) 57 +QUBIT_COORDS(6, 2) 58 +QUBIT_COORDS(6, 3) 59 +QUBIT_COORDS(6, 4) 60 +QUBIT_COORDS(6, 5) 61 +QUBIT_COORDS(6, 6) 62 +QUBIT_COORDS(6, 7) 63 +QUBIT_COORDS(6, 8) 64 +QUBIT_COORDS(6, 9) 65 +QUBIT_COORDS(6, 10) 66 +QUBIT_COORDS(6, 11) 67 +QUBIT_COORDS(6, 12) 68 +QUBIT_COORDS(6, 13) 69 +QUBIT_COORDS(6, 14) 70 +QUBIT_COORDS(6, 15) 71 +QUBIT_COORDS(6, 16) 72 +QUBIT_COORDS(6, 17) 73 +QUBIT_COORDS(6, 18) 74 +QUBIT_COORDS(6, 19) 75 +QUBIT_COORDS(7, 1) 76 +QUBIT_COORDS(7, 2) 77 +QUBIT_COORDS(7, 3) 78 +QUBIT_COORDS(7, 4) 79 +QUBIT_COORDS(7, 5) 80 +QUBIT_COORDS(7, 6) 81 +QUBIT_COORDS(7, 7) 82 +QUBIT_COORDS(7, 8) 83 +QUBIT_COORDS(7, 9) 84 +QUBIT_COORDS(7, 10) 85 +QUBIT_COORDS(7, 11) 86 +QUBIT_COORDS(7, 12) 87 +QUBIT_COORDS(7, 13) 88 +QUBIT_COORDS(7, 14) 89 +QUBIT_COORDS(7, 15) 90 +QUBIT_COORDS(7, 16) 91 +QUBIT_COORDS(7, 17) 92 +QUBIT_COORDS(7, 18) 93 +QUBIT_COORDS(7, 19) 94 +QUBIT_COORDS(7, 20) 95 +QUBIT_COORDS(7, 21) 96 +QUBIT_COORDS(7, 22) 97 +QUBIT_COORDS(7, 23) 98 +QUBIT_COORDS(7, 24) 99 +QUBIT_COORDS(8, 1) 100 +QUBIT_COORDS(8, 2) 101 +QUBIT_COORDS(8, 3) 102 +QUBIT_COORDS(8, 4) 103 +QUBIT_COORDS(8, 5) 104 +QUBIT_COORDS(8, 6) 105 +QUBIT_COORDS(8, 7) 106 +QUBIT_COORDS(8, 8) 107 +QUBIT_COORDS(8, 9) 108 +QUBIT_COORDS(8, 10) 109 +QUBIT_COORDS(8, 11) 110 +QUBIT_COORDS(8, 12) 111 +QUBIT_COORDS(8, 13) 112 +QUBIT_COORDS(8, 14) 113 +QUBIT_COORDS(8, 15) 114 +QUBIT_COORDS(8, 16) 115 +QUBIT_COORDS(8, 17) 116 +QUBIT_COORDS(8, 18) 117 +QUBIT_COORDS(8, 19) 118 +QUBIT_COORDS(8, 20) 119 +QUBIT_COORDS(8, 21) 120 +QUBIT_COORDS(8, 22) 121 +QUBIT_COORDS(8, 23) 122 +QUBIT_COORDS(8, 24) 123 +QUBIT_COORDS(8, 25) 124 +QUBIT_COORDS(9, 1) 125 +QUBIT_COORDS(9, 2) 126 +QUBIT_COORDS(9, 3) 127 +QUBIT_COORDS(9, 4) 128 +QUBIT_COORDS(9, 5) 129 +QUBIT_COORDS(9, 6) 130 +QUBIT_COORDS(9, 7) 131 +QUBIT_COORDS(9, 8) 132 +QUBIT_COORDS(9, 9) 133 +QUBIT_COORDS(9, 10) 134 +QUBIT_COORDS(9, 11) 135 +QUBIT_COORDS(9, 12) 136 +QUBIT_COORDS(9, 13) 137 +QUBIT_COORDS(9, 14) 138 +QUBIT_COORDS(9, 15) 139 +QUBIT_COORDS(9, 16) 140 +QUBIT_COORDS(9, 17) 141 +QUBIT_COORDS(9, 18) 142 +QUBIT_COORDS(9, 19) 143 +QUBIT_COORDS(9, 20) 144 +QUBIT_COORDS(9, 21) 145 +QUBIT_COORDS(9, 22) 146 +QUBIT_COORDS(9, 23) 147 +QUBIT_COORDS(9, 24) 148 +QUBIT_COORDS(9, 25) 149 +QUBIT_COORDS(9, 26) 150 +QUBIT_COORDS(9, 27) 151 +QUBIT_COORDS(9, 28) 152 +QUBIT_COORDS(9, 29) 153 +QUBIT_COORDS(9, 30) 154 +QUBIT_COORDS(10, 1) 155 +QUBIT_COORDS(10, 2) 156 +QUBIT_COORDS(10, 3) 157 +QUBIT_COORDS(10, 4) 158 +QUBIT_COORDS(10, 5) 159 +QUBIT_COORDS(10, 6) 160 +QUBIT_COORDS(10, 7) 161 +QUBIT_COORDS(10, 8) 162 +QUBIT_COORDS(10, 9) 163 +QUBIT_COORDS(10, 10) 164 +QUBIT_COORDS(10, 11) 165 +QUBIT_COORDS(10, 12) 166 +QUBIT_COORDS(10, 13) 167 +QUBIT_COORDS(10, 14) 168 +QUBIT_COORDS(10, 15) 169 +QUBIT_COORDS(10, 16) 170 +QUBIT_COORDS(10, 17) 171 +QUBIT_COORDS(10, 18) 172 +QUBIT_COORDS(10, 19) 173 +QUBIT_COORDS(10, 20) 174 +QUBIT_COORDS(10, 21) 175 +QUBIT_COORDS(10, 22) 176 +QUBIT_COORDS(10, 23) 177 +QUBIT_COORDS(10, 24) 178 +QUBIT_COORDS(10, 25) 179 +QUBIT_COORDS(10, 26) 180 +QUBIT_COORDS(10, 27) 181 +QUBIT_COORDS(10, 28) 182 +QUBIT_COORDS(10, 29) 183 +QUBIT_COORDS(10, 30) 184 +QUBIT_COORDS(10, 31) 185 +QUBIT_COORDS(11, 1) 186 +QUBIT_COORDS(11, 2) 187 +QUBIT_COORDS(11, 3) 188 +QUBIT_COORDS(11, 4) 189 +QUBIT_COORDS(11, 5) 190 +QUBIT_COORDS(11, 6) 191 +QUBIT_COORDS(11, 7) 192 +QUBIT_COORDS(11, 8) 193 +QUBIT_COORDS(11, 9) 194 +QUBIT_COORDS(11, 10) 195 +QUBIT_COORDS(11, 11) 196 +QUBIT_COORDS(11, 12) 197 +QUBIT_COORDS(11, 13) 198 +QUBIT_COORDS(11, 14) 199 +QUBIT_COORDS(11, 15) 200 +QUBIT_COORDS(11, 16) 201 +QUBIT_COORDS(11, 17) 202 +QUBIT_COORDS(11, 18) 203 +QUBIT_COORDS(11, 19) 204 +QUBIT_COORDS(11, 20) 205 +QUBIT_COORDS(11, 21) 206 +QUBIT_COORDS(11, 22) 207 +QUBIT_COORDS(11, 23) 208 +QUBIT_COORDS(11, 24) 209 +QUBIT_COORDS(11, 25) 210 +QUBIT_COORDS(11, 26) 211 +QUBIT_COORDS(11, 27) 212 +QUBIT_COORDS(11, 28) 213 +QUBIT_COORDS(11, 29) 214 +QUBIT_COORDS(11, 30) 215 +QUBIT_COORDS(11, 31) 216 +QUBIT_COORDS(11, 32) 217 +QUBIT_COORDS(11, 33) 218 +QUBIT_COORDS(11, 34) 219 +QUBIT_COORDS(11, 35) 220 +QUBIT_COORDS(11, 36) 221 +QUBIT_COORDS(12, 1) 222 +QUBIT_COORDS(12, 2) 223 +QUBIT_COORDS(12, 3) 224 +QUBIT_COORDS(12, 4) 225 +QUBIT_COORDS(12, 5) 226 +QUBIT_COORDS(12, 6) 227 +QUBIT_COORDS(12, 7) 228 +QUBIT_COORDS(12, 8) 229 +QUBIT_COORDS(12, 9) 230 +QUBIT_COORDS(12, 10) 231 +QUBIT_COORDS(12, 11) 232 +QUBIT_COORDS(12, 12) 233 +QUBIT_COORDS(12, 13) 234 +QUBIT_COORDS(12, 14) 235 +QUBIT_COORDS(12, 15) 236 +QUBIT_COORDS(12, 16) 237 +QUBIT_COORDS(12, 17) 238 +QUBIT_COORDS(12, 18) 239 +QUBIT_COORDS(12, 19) 240 +QUBIT_COORDS(12, 20) 241 +QUBIT_COORDS(12, 21) 242 +QUBIT_COORDS(12, 22) 243 +QUBIT_COORDS(12, 23) 244 +QUBIT_COORDS(12, 24) 245 +QUBIT_COORDS(12, 25) 246 +QUBIT_COORDS(12, 26) 247 +QUBIT_COORDS(12, 27) 248 +QUBIT_COORDS(12, 28) 249 +QUBIT_COORDS(12, 29) 250 +QUBIT_COORDS(12, 30) 251 +QUBIT_COORDS(12, 31) 252 +QUBIT_COORDS(12, 32) 253 +QUBIT_COORDS(12, 33) 254 +QUBIT_COORDS(12, 34) 255 +QUBIT_COORDS(12, 35) 256 +QUBIT_COORDS(12, 36) 257 +QUBIT_COORDS(12, 37) 258 +QUBIT_COORDS(13, 1) 259 +QUBIT_COORDS(13, 2) 260 +QUBIT_COORDS(13, 3) 261 +QUBIT_COORDS(13, 4) 262 +QUBIT_COORDS(13, 5) 263 +QUBIT_COORDS(13, 6) 264 +QUBIT_COORDS(13, 7) 265 +QUBIT_COORDS(13, 8) 266 +QUBIT_COORDS(13, 9) 267 +QUBIT_COORDS(13, 10) 268 +QUBIT_COORDS(13, 11) 269 +QUBIT_COORDS(13, 12) 270 +QUBIT_COORDS(13, 13) 271 +QUBIT_COORDS(13, 14) 272 +QUBIT_COORDS(13, 15) 273 +QUBIT_COORDS(13, 16) 274 +QUBIT_COORDS(13, 17) 275 +QUBIT_COORDS(13, 18) 276 +QUBIT_COORDS(13, 19) 277 +QUBIT_COORDS(13, 20) 278 +QUBIT_COORDS(13, 21) 279 +QUBIT_COORDS(13, 22) 280 +QUBIT_COORDS(13, 23) 281 +QUBIT_COORDS(13, 24) 282 +QUBIT_COORDS(13, 25) 283 +QUBIT_COORDS(13, 26) 284 +QUBIT_COORDS(13, 27) 285 +QUBIT_COORDS(13, 28) 286 +QUBIT_COORDS(13, 29) 287 +QUBIT_COORDS(13, 30) 288 +QUBIT_COORDS(13, 31) 289 +QUBIT_COORDS(13, 32) 290 +QUBIT_COORDS(13, 33) 291 +QUBIT_COORDS(13, 34) 292 +QUBIT_COORDS(13, 35) 293 +QUBIT_COORDS(14, 1) 294 +QUBIT_COORDS(14, 2) 295 +QUBIT_COORDS(14, 3) 296 +QUBIT_COORDS(14, 4) 297 +QUBIT_COORDS(14, 5) 298 +QUBIT_COORDS(14, 6) 299 +QUBIT_COORDS(14, 7) 300 +QUBIT_COORDS(14, 8) 301 +QUBIT_COORDS(14, 9) 302 +QUBIT_COORDS(14, 10) 303 +QUBIT_COORDS(14, 11) 304 +QUBIT_COORDS(14, 12) 305 +QUBIT_COORDS(14, 13) 306 +QUBIT_COORDS(14, 14) 307 +QUBIT_COORDS(14, 15) 308 +QUBIT_COORDS(14, 16) 309 +QUBIT_COORDS(14, 17) 310 +QUBIT_COORDS(14, 18) 311 +QUBIT_COORDS(14, 19) 312 +QUBIT_COORDS(14, 20) 313 +QUBIT_COORDS(14, 21) 314 +QUBIT_COORDS(14, 22) 315 +QUBIT_COORDS(14, 23) 316 +QUBIT_COORDS(14, 24) 317 +QUBIT_COORDS(14, 25) 318 +QUBIT_COORDS(14, 26) 319 +QUBIT_COORDS(14, 27) 320 +QUBIT_COORDS(14, 28) 321 +QUBIT_COORDS(14, 29) 322 +QUBIT_COORDS(14, 30) 323 +QUBIT_COORDS(14, 31) 324 +QUBIT_COORDS(14, 32) 325 +QUBIT_COORDS(14, 33) 326 +QUBIT_COORDS(14, 34) 327 +QUBIT_COORDS(15, 1) 328 +QUBIT_COORDS(15, 2) 329 +QUBIT_COORDS(15, 3) 330 +QUBIT_COORDS(15, 4) 331 +QUBIT_COORDS(15, 5) 332 +QUBIT_COORDS(15, 6) 333 +QUBIT_COORDS(15, 7) 334 +QUBIT_COORDS(15, 8) 335 +QUBIT_COORDS(15, 9) 336 +QUBIT_COORDS(15, 10) 337 +QUBIT_COORDS(15, 11) 338 +QUBIT_COORDS(15, 12) 339 +QUBIT_COORDS(15, 13) 340 +QUBIT_COORDS(15, 14) 341 +QUBIT_COORDS(15, 15) 342 +QUBIT_COORDS(15, 16) 343 +QUBIT_COORDS(15, 17) 344 +QUBIT_COORDS(15, 18) 345 +QUBIT_COORDS(15, 19) 346 +QUBIT_COORDS(15, 20) 347 +QUBIT_COORDS(15, 21) 348 +QUBIT_COORDS(15, 22) 349 +QUBIT_COORDS(15, 23) 350 +QUBIT_COORDS(15, 24) 351 +QUBIT_COORDS(15, 25) 352 +QUBIT_COORDS(15, 26) 353 +QUBIT_COORDS(15, 27) 354 +QUBIT_COORDS(15, 28) 355 +QUBIT_COORDS(15, 29) 356 +QUBIT_COORDS(16, 1) 357 +QUBIT_COORDS(16, 2) 358 +QUBIT_COORDS(16, 3) 359 +QUBIT_COORDS(16, 4) 360 +QUBIT_COORDS(16, 5) 361 +QUBIT_COORDS(16, 6) 362 +QUBIT_COORDS(16, 7) 363 +QUBIT_COORDS(16, 8) 364 +QUBIT_COORDS(16, 9) 365 +QUBIT_COORDS(16, 10) 366 +QUBIT_COORDS(16, 11) 367 +QUBIT_COORDS(16, 12) 368 +QUBIT_COORDS(16, 13) 369 +QUBIT_COORDS(16, 14) 370 +QUBIT_COORDS(16, 15) 371 +QUBIT_COORDS(16, 16) 372 +QUBIT_COORDS(16, 17) 373 +QUBIT_COORDS(16, 18) 374 +QUBIT_COORDS(16, 19) 375 +QUBIT_COORDS(16, 20) 376 +QUBIT_COORDS(16, 21) 377 +QUBIT_COORDS(16, 22) 378 +QUBIT_COORDS(16, 23) 379 +QUBIT_COORDS(16, 24) 380 +QUBIT_COORDS(16, 25) 381 +QUBIT_COORDS(16, 26) 382 +QUBIT_COORDS(16, 27) 383 +QUBIT_COORDS(16, 28) 384 +QUBIT_COORDS(17, 1) 385 +QUBIT_COORDS(17, 2) 386 +QUBIT_COORDS(17, 3) 387 +QUBIT_COORDS(17, 4) 388 +QUBIT_COORDS(17, 5) 389 +QUBIT_COORDS(17, 6) 390 +QUBIT_COORDS(17, 7) 391 +QUBIT_COORDS(17, 8) 392 +QUBIT_COORDS(17, 9) 393 +QUBIT_COORDS(17, 10) 394 +QUBIT_COORDS(17, 11) 395 +QUBIT_COORDS(17, 12) 396 +QUBIT_COORDS(17, 13) 397 +QUBIT_COORDS(17, 14) 398 +QUBIT_COORDS(17, 15) 399 +QUBIT_COORDS(17, 16) 400 +QUBIT_COORDS(17, 17) 401 +QUBIT_COORDS(17, 18) 402 +QUBIT_COORDS(17, 19) 403 +QUBIT_COORDS(17, 20) 404 +QUBIT_COORDS(17, 21) 405 +QUBIT_COORDS(17, 22) 406 +QUBIT_COORDS(17, 23) 407 +QUBIT_COORDS(18, 1) 408 +QUBIT_COORDS(18, 2) 409 +QUBIT_COORDS(18, 3) 410 +QUBIT_COORDS(18, 4) 411 +QUBIT_COORDS(18, 5) 412 +QUBIT_COORDS(18, 6) 413 +QUBIT_COORDS(18, 7) 414 +QUBIT_COORDS(18, 8) 415 +QUBIT_COORDS(18, 9) 416 +QUBIT_COORDS(18, 10) 417 +QUBIT_COORDS(18, 11) 418 +QUBIT_COORDS(18, 12) 419 +QUBIT_COORDS(18, 13) 420 +QUBIT_COORDS(18, 14) 421 +QUBIT_COORDS(18, 15) 422 +QUBIT_COORDS(18, 16) 423 +QUBIT_COORDS(18, 17) 424 +QUBIT_COORDS(18, 18) 425 +QUBIT_COORDS(18, 19) 426 +QUBIT_COORDS(18, 20) 427 +QUBIT_COORDS(18, 21) 428 +QUBIT_COORDS(18, 22) 429 +QUBIT_COORDS(19, 1) 430 +QUBIT_COORDS(19, 2) 431 +QUBIT_COORDS(19, 3) 432 +QUBIT_COORDS(19, 4) 433 +QUBIT_COORDS(19, 5) 434 +QUBIT_COORDS(19, 6) 435 +QUBIT_COORDS(19, 7) 436 +QUBIT_COORDS(19, 8) 437 +QUBIT_COORDS(19, 9) 438 +QUBIT_COORDS(19, 10) 439 +QUBIT_COORDS(19, 11) 440 +QUBIT_COORDS(19, 12) 441 +QUBIT_COORDS(19, 13) 442 +QUBIT_COORDS(19, 14) 443 +QUBIT_COORDS(19, 15) 444 +QUBIT_COORDS(19, 16) 445 +QUBIT_COORDS(19, 17) 446 +QUBIT_COORDS(20, 1) 447 +QUBIT_COORDS(20, 2) 448 +QUBIT_COORDS(20, 3) 449 +QUBIT_COORDS(20, 4) 450 +QUBIT_COORDS(20, 5) 451 +QUBIT_COORDS(20, 6) 452 +QUBIT_COORDS(20, 7) 453 +QUBIT_COORDS(20, 8) 454 +QUBIT_COORDS(20, 9) 455 +QUBIT_COORDS(20, 10) 456 +QUBIT_COORDS(20, 11) 457 +QUBIT_COORDS(20, 12) 458 +QUBIT_COORDS(20, 13) 459 +QUBIT_COORDS(20, 14) 460 +QUBIT_COORDS(20, 15) 461 +QUBIT_COORDS(20, 16) 462 +QUBIT_COORDS(21, 1) 463 +QUBIT_COORDS(21, 2) 464 +QUBIT_COORDS(21, 3) 465 +QUBIT_COORDS(21, 4) 466 +QUBIT_COORDS(21, 5) 467 +QUBIT_COORDS(21, 6) 468 +QUBIT_COORDS(21, 7) 469 +QUBIT_COORDS(21, 8) 470 +QUBIT_COORDS(21, 9) 471 +QUBIT_COORDS(21, 10) 472 +QUBIT_COORDS(21, 11) 473 +QUBIT_COORDS(22, 1) 474 +QUBIT_COORDS(22, 2) 475 +QUBIT_COORDS(22, 3) 476 +QUBIT_COORDS(22, 4) 477 +QUBIT_COORDS(22, 5) 478 +QUBIT_COORDS(22, 6) 479 +QUBIT_COORDS(22, 7) 480 +QUBIT_COORDS(22, 8) 481 +QUBIT_COORDS(22, 9) 482 +QUBIT_COORDS(22, 10) 483 +QUBIT_COORDS(23, 1) 484 +QUBIT_COORDS(23, 2) 485 +QUBIT_COORDS(23, 3) 486 +QUBIT_COORDS(23, 4) 487 +QUBIT_COORDS(23, 5) 488 +QUBIT_COORDS(24, 1) 489 +QUBIT_COORDS(24, 2) 490 +QUBIT_COORDS(24, 3) 491 +QUBIT_COORDS(24, 4) 492 +RX 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 +R 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 +X_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 +Z_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 +TICK +CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 38 51 40 58 42 60 44 62 46 64 48 66 50 68 52 70 54 72 56 74 57 76 59 78 61 80 63 82 65 84 67 86 69 88 71 90 73 92 75 94 77 101 79 103 81 105 83 107 85 109 87 111 89 113 91 115 93 117 95 119 97 121 99 123 100 125 102 127 104 129 106 131 108 133 110 135 112 137 114 139 116 141 118 143 120 145 122 147 124 149 126 156 128 158 130 160 132 162 134 164 136 166 138 168 140 170 142 172 144 174 146 176 148 178 150 180 152 182 154 184 155 186 157 188 159 190 161 192 163 194 165 196 167 198 169 200 171 202 173 204 175 206 177 208 179 210 181 212 183 214 185 216 187 223 189 225 191 227 193 229 195 231 197 233 199 235 201 237 203 239 205 241 207 243 209 245 211 247 213 249 215 251 217 253 219 255 221 257 222 259 224 261 226 263 228 265 230 267 232 269 234 271 236 273 238 275 240 277 242 279 244 281 246 283 248 285 250 287 252 289 254 291 256 293 260 295 262 297 264 299 266 301 268 303 270 305 272 307 274 309 276 311 278 313 280 315 282 317 284 319 286 321 288 323 290 325 292 327 294 328 296 330 298 332 300 334 302 336 304 338 306 340 308 342 310 344 312 346 314 348 316 350 318 352 320 354 322 356 329 358 331 360 333 362 335 364 337 366 339 368 341 370 343 372 345 374 347 376 349 378 351 380 353 382 355 384 357 385 359 387 361 389 363 391 365 393 367 395 369 397 371 399 373 401 375 403 377 405 379 407 386 409 388 411 390 413 392 415 394 417 396 419 398 421 400 423 402 425 404 427 406 429 408 430 410 432 412 434 414 436 416 438 418 440 420 442 422 444 424 446 431 448 433 450 435 452 437 454 439 456 441 458 443 460 445 462 447 463 449 465 451 467 453 469 455 471 457 473 464 475 466 477 468 479 470 481 472 483 474 484 476 486 478 488 485 490 487 492 +DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 38 51 40 58 42 60 44 62 46 64 48 66 50 68 52 70 54 72 56 74 57 76 59 78 61 80 63 82 65 84 67 86 69 88 71 90 73 92 75 94 77 101 79 103 81 105 83 107 85 109 87 111 89 113 91 115 93 117 95 119 97 121 99 123 100 125 102 127 104 129 106 131 108 133 110 135 112 137 114 139 116 141 118 143 120 145 122 147 124 149 126 156 128 158 130 160 132 162 134 164 136 166 138 168 140 170 142 172 144 174 146 176 148 178 150 180 152 182 154 184 155 186 157 188 159 190 161 192 163 194 165 196 167 198 169 200 171 202 173 204 175 206 177 208 179 210 181 212 183 214 185 216 187 223 189 225 191 227 193 229 195 231 197 233 199 235 201 237 203 239 205 241 207 243 209 245 211 247 213 249 215 251 217 253 219 255 221 257 222 259 224 261 226 263 228 265 230 267 232 269 234 271 236 273 238 275 240 277 242 279 244 281 246 283 248 285 250 287 252 289 254 291 256 293 260 295 262 297 264 299 266 301 268 303 270 305 272 307 274 309 276 311 278 313 280 315 282 317 284 319 286 321 288 323 290 325 292 327 294 328 296 330 298 332 300 334 302 336 304 338 306 340 308 342 310 344 312 346 314 348 316 350 318 352 320 354 322 356 329 358 331 360 333 362 335 364 337 366 339 368 341 370 343 372 345 374 347 376 349 378 351 380 353 382 355 384 357 385 359 387 361 389 363 391 365 393 367 395 369 397 371 399 373 401 375 403 377 405 379 407 386 409 388 411 390 413 392 415 394 417 396 419 398 421 400 423 402 425 404 427 406 429 408 430 410 432 412 434 414 436 416 438 418 440 420 442 422 444 424 446 431 448 433 450 435 452 437 454 439 456 441 458 443 460 445 462 447 463 449 465 451 467 453 469 455 471 457 473 464 475 466 477 468 479 470 481 472 483 474 484 476 486 478 488 485 490 487 492 +DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 +TICK +CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 50 49 52 51 54 53 56 55 58 57 60 59 62 61 64 63 66 65 68 67 70 69 72 71 74 73 77 76 79 78 81 80 83 82 85 84 87 86 89 88 91 90 93 92 95 94 97 96 99 98 101 100 103 102 105 104 107 106 109 108 111 110 113 112 115 114 117 116 119 118 121 120 123 122 126 125 128 127 130 129 132 131 134 133 136 135 138 137 140 139 142 141 144 143 146 145 148 147 150 149 152 151 154 153 156 155 158 157 160 159 162 161 164 163 166 165 168 167 170 169 172 171 174 173 176 175 178 177 180 179 182 181 184 183 187 186 189 188 191 190 193 192 195 194 197 196 199 198 201 200 203 202 205 204 207 206 209 208 211 210 213 212 215 214 217 216 219 218 221 220 223 222 225 224 227 226 229 228 231 230 233 232 235 234 237 236 239 238 241 240 243 242 245 244 247 246 249 248 251 250 253 252 255 254 257 256 260 259 262 261 264 263 266 265 268 267 270 269 272 271 274 273 276 275 278 277 280 279 282 281 284 283 286 285 288 287 290 289 292 291 295 294 297 296 299 298 301 300 303 302 305 304 307 306 309 308 311 310 313 312 315 314 317 316 319 318 321 320 323 322 325 324 327 326 329 328 331 330 333 332 335 334 337 336 339 338 341 340 343 342 345 344 347 346 349 348 351 350 353 352 355 354 358 357 360 359 362 361 364 363 366 365 368 367 370 369 372 371 374 373 376 375 378 377 380 379 382 381 384 383 386 385 388 387 390 389 392 391 394 393 396 395 398 397 400 399 402 401 404 403 406 405 409 408 411 410 413 412 415 414 417 416 419 418 421 420 423 422 425 424 427 426 429 428 431 430 433 432 435 434 437 436 439 438 441 440 443 442 445 444 448 447 450 449 452 451 454 453 456 455 458 457 460 459 462 461 464 463 466 465 468 467 470 469 472 471 475 474 477 476 479 478 481 480 483 482 485 484 487 486 490 489 492 491 +DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 50 49 52 51 54 53 56 55 58 57 60 59 62 61 64 63 66 65 68 67 70 69 72 71 74 73 77 76 79 78 81 80 83 82 85 84 87 86 89 88 91 90 93 92 95 94 97 96 99 98 101 100 103 102 105 104 107 106 109 108 111 110 113 112 115 114 117 116 119 118 121 120 123 122 126 125 128 127 130 129 132 131 134 133 136 135 138 137 140 139 142 141 144 143 146 145 148 147 150 149 152 151 154 153 156 155 158 157 160 159 162 161 164 163 166 165 168 167 170 169 172 171 174 173 176 175 178 177 180 179 182 181 184 183 187 186 189 188 191 190 193 192 195 194 197 196 199 198 201 200 203 202 205 204 207 206 209 208 211 210 213 212 215 214 217 216 219 218 221 220 223 222 225 224 227 226 229 228 231 230 233 232 235 234 237 236 239 238 241 240 243 242 245 244 247 246 249 248 251 250 253 252 255 254 257 256 260 259 262 261 264 263 266 265 268 267 270 269 272 271 274 273 276 275 278 277 280 279 282 281 284 283 286 285 288 287 290 289 292 291 295 294 297 296 299 298 301 300 303 302 305 304 307 306 309 308 311 310 313 312 315 314 317 316 319 318 321 320 323 322 325 324 327 326 329 328 331 330 333 332 335 334 337 336 339 338 341 340 343 342 345 344 347 346 349 348 351 350 353 352 355 354 358 357 360 359 362 361 364 363 366 365 368 367 370 369 372 371 374 373 376 375 378 377 380 379 382 381 384 383 386 385 388 387 390 389 392 391 394 393 396 395 398 397 400 399 402 401 404 403 406 405 409 408 411 410 413 412 415 414 417 416 419 418 421 420 423 422 425 424 427 426 429 428 431 430 433 432 435 434 437 436 439 438 441 440 443 442 445 444 448 447 450 449 452 451 454 453 456 455 458 457 460 459 462 461 464 463 466 465 468 467 470 469 472 471 475 474 477 476 479 478 481 480 483 482 485 484 487 486 490 489 492 491 +DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 +TICK +CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 51 50 53 52 55 54 59 58 61 60 63 62 65 64 67 66 69 68 71 70 73 72 75 74 78 77 80 79 82 81 84 83 86 85 88 87 90 89 92 91 94 93 96 95 98 97 102 101 104 103 106 105 108 107 110 109 112 111 114 113 116 115 118 117 120 119 122 121 124 123 127 126 129 128 131 130 133 132 135 134 137 136 139 138 141 140 143 142 145 144 147 146 149 148 151 150 153 152 157 156 159 158 161 160 163 162 165 164 167 166 169 168 171 170 173 172 175 174 177 176 179 178 181 180 183 182 185 184 188 187 190 189 192 191 194 193 196 195 198 197 200 199 202 201 204 203 206 205 208 207 210 209 212 211 214 213 216 215 218 217 220 219 224 223 226 225 228 227 230 229 232 231 234 233 236 235 238 237 240 239 242 241 244 243 246 245 248 247 250 249 252 251 254 253 256 255 258 257 261 260 263 262 265 264 267 266 269 268 271 270 273 272 275 274 277 276 279 278 281 280 283 282 285 284 287 286 289 288 291 290 293 292 296 295 298 297 300 299 302 301 304 303 306 305 308 307 310 309 312 311 314 313 316 315 318 317 320 319 322 321 324 323 326 325 330 329 332 331 334 333 336 335 338 337 340 339 342 341 344 343 346 345 348 347 350 349 352 351 354 353 356 355 359 358 361 360 363 362 365 364 367 366 369 368 371 370 373 372 375 374 377 376 379 378 381 380 383 382 387 386 389 388 391 390 393 392 395 394 397 396 399 398 401 400 403 402 405 404 407 406 410 409 412 411 414 413 416 415 418 417 420 419 422 421 424 423 426 425 428 427 432 431 434 433 436 435 438 437 440 439 442 441 444 443 446 445 449 448 451 450 453 452 455 454 457 456 459 458 461 460 465 464 467 466 469 468 471 470 473 472 476 475 478 477 480 479 482 481 486 485 488 487 491 490 +DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 51 50 53 52 55 54 59 58 61 60 63 62 65 64 67 66 69 68 71 70 73 72 75 74 78 77 80 79 82 81 84 83 86 85 88 87 90 89 92 91 94 93 96 95 98 97 102 101 104 103 106 105 108 107 110 109 112 111 114 113 116 115 118 117 120 119 122 121 124 123 127 126 129 128 131 130 133 132 135 134 137 136 139 138 141 140 143 142 145 144 147 146 149 148 151 150 153 152 157 156 159 158 161 160 163 162 165 164 167 166 169 168 171 170 173 172 175 174 177 176 179 178 181 180 183 182 185 184 188 187 190 189 192 191 194 193 196 195 198 197 200 199 202 201 204 203 206 205 208 207 210 209 212 211 214 213 216 215 218 217 220 219 224 223 226 225 228 227 230 229 232 231 234 233 236 235 238 237 240 239 242 241 244 243 246 245 248 247 250 249 252 251 254 253 256 255 258 257 261 260 263 262 265 264 267 266 269 268 271 270 273 272 275 274 277 276 279 278 281 280 283 282 285 284 287 286 289 288 291 290 293 292 296 295 298 297 300 299 302 301 304 303 306 305 308 307 310 309 312 311 314 313 316 315 318 317 320 319 322 321 324 323 326 325 330 329 332 331 334 333 336 335 338 337 340 339 342 341 344 343 346 345 348 347 350 349 352 351 354 353 356 355 359 358 361 360 363 362 365 364 367 366 369 368 371 370 373 372 375 374 377 376 379 378 381 380 383 382 387 386 389 388 391 390 393 392 395 394 397 396 399 398 401 400 403 402 405 404 407 406 410 409 412 411 414 413 416 415 418 417 420 419 422 421 424 423 426 425 428 427 432 431 434 433 436 435 438 437 440 439 442 441 444 443 446 445 449 448 451 450 453 452 455 454 457 456 459 458 461 460 465 464 467 466 469 468 471 470 473 472 476 475 478 477 480 479 482 481 486 485 488 487 491 490 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 +TICK +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 +DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 +DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 +TICK +MX(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 +M(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 +TICK +RX 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 +R 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 +OBSERVABLE_INCLUDE(0) rec[-124] rec[-131] rec[-141] rec[-154] rec[-170] rec[-189] rec[-206] rec[-220] rec[-231] rec[-239] rec[-244] rec[-246] +X_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 +Z_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 +DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 +DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 +DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 +TICK +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 +DETECTOR(1, 1, 0, 1) rec[-246] +DETECTOR(1, 5, 0, 0) rec[-245] +DETECTOR(3, 1, 0, 1) rec[-244] +DETECTOR(3, 3, 0, 2) rec[-243] +DETECTOR(3, 5, 0, 0) rec[-242] +DETECTOR(3, 7, 0, 1) rec[-241] +DETECTOR(3, 11, 0, 0) rec[-240] +DETECTOR(5, 1, 0, 1) rec[-239] +DETECTOR(5, 3, 0, 2) rec[-238] +DETECTOR(5, 5, 0, 0) rec[-237] +DETECTOR(5, 7, 0, 1) rec[-236] +DETECTOR(5, 9, 0, 2) rec[-235] +DETECTOR(5, 11, 0, 0) rec[-234] +DETECTOR(5, 13, 0, 1) rec[-233] +DETECTOR(5, 17, 0, 0) rec[-232] +DETECTOR(7, 1, 0, 1) rec[-231] +DETECTOR(7, 3, 0, 2) rec[-230] +DETECTOR(7, 5, 0, 0) rec[-229] +DETECTOR(7, 7, 0, 1) rec[-228] +DETECTOR(7, 9, 0, 2) rec[-227] +DETECTOR(7, 11, 0, 0) rec[-226] +DETECTOR(7, 13, 0, 1) rec[-225] +DETECTOR(7, 15, 0, 2) rec[-224] +DETECTOR(7, 17, 0, 0) rec[-223] +DETECTOR(7, 19, 0, 1) rec[-222] +DETECTOR(7, 23, 0, 0) rec[-221] +DETECTOR(9, 1, 0, 1) rec[-220] +DETECTOR(9, 3, 0, 2) rec[-219] +DETECTOR(9, 5, 0, 0) rec[-218] +DETECTOR(9, 7, 0, 1) rec[-217] +DETECTOR(9, 9, 0, 2) rec[-216] +DETECTOR(9, 11, 0, 0) rec[-215] +DETECTOR(9, 13, 0, 1) rec[-214] +DETECTOR(9, 15, 0, 2) rec[-213] +DETECTOR(9, 17, 0, 0) rec[-212] +DETECTOR(9, 19, 0, 1) rec[-211] +DETECTOR(9, 21, 0, 2) rec[-210] +DETECTOR(9, 23, 0, 0) rec[-209] +DETECTOR(9, 25, 0, 1) rec[-208] +DETECTOR(9, 29, 0, 0) rec[-207] +DETECTOR(11, 1, 0, 1) rec[-206] +DETECTOR(11, 3, 0, 2) rec[-205] +DETECTOR(11, 5, 0, 0) rec[-204] +DETECTOR(11, 7, 0, 1) rec[-203] +DETECTOR(11, 9, 0, 2) rec[-202] +DETECTOR(11, 11, 0, 0) rec[-201] +DETECTOR(11, 13, 0, 1) rec[-200] +DETECTOR(11, 15, 0, 2) rec[-199] +DETECTOR(11, 17, 0, 0) rec[-198] +DETECTOR(11, 19, 0, 1) rec[-197] +DETECTOR(11, 21, 0, 2) rec[-196] +DETECTOR(11, 23, 0, 0) rec[-195] +DETECTOR(11, 25, 0, 1) rec[-194] +DETECTOR(11, 27, 0, 2) rec[-193] +DETECTOR(11, 29, 0, 0) rec[-192] +DETECTOR(11, 31, 0, 1) rec[-191] +DETECTOR(11, 35, 0, 0) rec[-190] +DETECTOR(13, 1, 0, 1) rec[-189] +DETECTOR(13, 3, 0, 2) rec[-188] +DETECTOR(13, 5, 0, 0) rec[-187] +DETECTOR(13, 7, 0, 1) rec[-186] +DETECTOR(13, 9, 0, 2) rec[-185] +DETECTOR(13, 11, 0, 0) rec[-184] +DETECTOR(13, 13, 0, 1) rec[-183] +DETECTOR(13, 15, 0, 2) rec[-182] +DETECTOR(13, 17, 0, 0) rec[-181] +DETECTOR(13, 19, 0, 1) rec[-180] +DETECTOR(13, 21, 0, 2) rec[-179] +DETECTOR(13, 23, 0, 0) rec[-178] +DETECTOR(13, 25, 0, 1) rec[-177] +DETECTOR(13, 27, 0, 2) rec[-176] +DETECTOR(13, 29, 0, 0) rec[-175] +DETECTOR(13, 31, 0, 1) rec[-174] +DETECTOR(13, 33, 0, 2) rec[-173] +DETECTOR(13, 35, 0, 0) rec[-172] +DETECTOR(14, 33, 0, 2) rec[-171] +DETECTOR(15, 1, 0, 1) rec[-170] +DETECTOR(15, 3, 0, 2) rec[-169] +DETECTOR(15, 5, 0, 0) rec[-168] +DETECTOR(15, 7, 0, 1) rec[-167] +DETECTOR(15, 9, 0, 2) rec[-166] +DETECTOR(15, 11, 0, 0) rec[-165] +DETECTOR(15, 13, 0, 1) rec[-164] +DETECTOR(15, 15, 0, 2) rec[-163] +DETECTOR(15, 17, 0, 0) rec[-162] +DETECTOR(15, 19, 0, 1) rec[-161] +DETECTOR(15, 21, 0, 2) rec[-160] +DETECTOR(15, 23, 0, 0) rec[-159] +DETECTOR(15, 25, 0, 1) rec[-158] +DETECTOR(15, 27, 0, 2) rec[-157] +DETECTOR(15, 29, 0, 0) rec[-156] +DETECTOR(16, 27, 0, 2) rec[-155] +DETECTOR(17, 1, 0, 1) rec[-154] +DETECTOR(17, 3, 0, 2) rec[-153] +DETECTOR(17, 5, 0, 0) rec[-152] +DETECTOR(17, 7, 0, 1) rec[-151] +DETECTOR(17, 9, 0, 2) rec[-150] +DETECTOR(17, 11, 0, 0) rec[-149] +DETECTOR(17, 13, 0, 1) rec[-148] +DETECTOR(17, 15, 0, 2) rec[-147] +DETECTOR(17, 17, 0, 0) rec[-146] +DETECTOR(17, 19, 0, 1) rec[-145] +DETECTOR(17, 21, 0, 2) rec[-144] +DETECTOR(17, 23, 0, 0) rec[-143] +DETECTOR(18, 21, 0, 2) rec[-142] +DETECTOR(19, 1, 0, 1) rec[-141] +DETECTOR(19, 3, 0, 2) rec[-140] +DETECTOR(19, 5, 0, 0) rec[-139] +DETECTOR(19, 7, 0, 1) rec[-138] +DETECTOR(19, 9, 0, 2) rec[-137] +DETECTOR(19, 11, 0, 0) rec[-136] +DETECTOR(19, 13, 0, 1) rec[-135] +DETECTOR(19, 15, 0, 2) rec[-134] +DETECTOR(19, 17, 0, 0) rec[-133] +DETECTOR(20, 15, 0, 2) rec[-132] +DETECTOR(21, 1, 0, 1) rec[-131] +DETECTOR(21, 3, 0, 2) rec[-130] +DETECTOR(21, 5, 0, 0) rec[-129] +DETECTOR(21, 7, 0, 1) rec[-128] +DETECTOR(21, 9, 0, 2) rec[-127] +DETECTOR(21, 11, 0, 0) rec[-126] +DETECTOR(22, 9, 0, 2) rec[-125] +DETECTOR(23, 1, 0, 1) rec[-124] +DETECTOR(23, 3, 0, 2) rec[-123] +DETECTOR(23, 5, 0, 0) rec[-122] +DETECTOR(24, 3, 0, 2) rec[-121] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 +TICK +CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 51 50 53 52 55 54 59 58 61 60 63 62 65 64 67 66 69 68 71 70 73 72 75 74 78 77 80 79 82 81 84 83 86 85 88 87 90 89 92 91 94 93 96 95 98 97 102 101 104 103 106 105 108 107 110 109 112 111 114 113 116 115 118 117 120 119 122 121 124 123 127 126 129 128 131 130 133 132 135 134 137 136 139 138 141 140 143 142 145 144 147 146 149 148 151 150 153 152 157 156 159 158 161 160 163 162 165 164 167 166 169 168 171 170 173 172 175 174 177 176 179 178 181 180 183 182 185 184 188 187 190 189 192 191 194 193 196 195 198 197 200 199 202 201 204 203 206 205 208 207 210 209 212 211 214 213 216 215 218 217 220 219 224 223 226 225 228 227 230 229 232 231 234 233 236 235 238 237 240 239 242 241 244 243 246 245 248 247 250 249 252 251 254 253 256 255 258 257 261 260 263 262 265 264 267 266 269 268 271 270 273 272 275 274 277 276 279 278 281 280 283 282 285 284 287 286 289 288 291 290 293 292 296 295 298 297 300 299 302 301 304 303 306 305 308 307 310 309 312 311 314 313 316 315 318 317 320 319 322 321 324 323 326 325 330 329 332 331 334 333 336 335 338 337 340 339 342 341 344 343 346 345 348 347 350 349 352 351 354 353 356 355 359 358 361 360 363 362 365 364 367 366 369 368 371 370 373 372 375 374 377 376 379 378 381 380 383 382 387 386 389 388 391 390 393 392 395 394 397 396 399 398 401 400 403 402 405 404 407 406 410 409 412 411 414 413 416 415 418 417 420 419 422 421 424 423 426 425 428 427 432 431 434 433 436 435 438 437 440 439 442 441 444 443 446 445 449 448 451 450 453 452 455 454 457 456 459 458 461 460 465 464 467 466 469 468 471 470 473 472 476 475 478 477 480 479 482 481 486 485 488 487 491 490 +DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 51 50 53 52 55 54 59 58 61 60 63 62 65 64 67 66 69 68 71 70 73 72 75 74 78 77 80 79 82 81 84 83 86 85 88 87 90 89 92 91 94 93 96 95 98 97 102 101 104 103 106 105 108 107 110 109 112 111 114 113 116 115 118 117 120 119 122 121 124 123 127 126 129 128 131 130 133 132 135 134 137 136 139 138 141 140 143 142 145 144 147 146 149 148 151 150 153 152 157 156 159 158 161 160 163 162 165 164 167 166 169 168 171 170 173 172 175 174 177 176 179 178 181 180 183 182 185 184 188 187 190 189 192 191 194 193 196 195 198 197 200 199 202 201 204 203 206 205 208 207 210 209 212 211 214 213 216 215 218 217 220 219 224 223 226 225 228 227 230 229 232 231 234 233 236 235 238 237 240 239 242 241 244 243 246 245 248 247 250 249 252 251 254 253 256 255 258 257 261 260 263 262 265 264 267 266 269 268 271 270 273 272 275 274 277 276 279 278 281 280 283 282 285 284 287 286 289 288 291 290 293 292 296 295 298 297 300 299 302 301 304 303 306 305 308 307 310 309 312 311 314 313 316 315 318 317 320 319 322 321 324 323 326 325 330 329 332 331 334 333 336 335 338 337 340 339 342 341 344 343 346 345 348 347 350 349 352 351 354 353 356 355 359 358 361 360 363 362 365 364 367 366 369 368 371 370 373 372 375 374 377 376 379 378 381 380 383 382 387 386 389 388 391 390 393 392 395 394 397 396 399 398 401 400 403 402 405 404 407 406 410 409 412 411 414 413 416 415 418 417 420 419 422 421 424 423 426 425 428 427 432 431 434 433 436 435 438 437 440 439 442 441 444 443 446 445 449 448 451 450 453 452 455 454 457 456 459 458 461 460 465 464 467 466 469 468 471 470 473 472 476 475 478 477 480 479 482 481 486 485 488 487 491 490 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 +TICK +CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 50 49 52 51 54 53 56 55 58 57 60 59 62 61 64 63 66 65 68 67 70 69 72 71 74 73 77 76 79 78 81 80 83 82 85 84 87 86 89 88 91 90 93 92 95 94 97 96 99 98 101 100 103 102 105 104 107 106 109 108 111 110 113 112 115 114 117 116 119 118 121 120 123 122 126 125 128 127 130 129 132 131 134 133 136 135 138 137 140 139 142 141 144 143 146 145 148 147 150 149 152 151 154 153 156 155 158 157 160 159 162 161 164 163 166 165 168 167 170 169 172 171 174 173 176 175 178 177 180 179 182 181 184 183 187 186 189 188 191 190 193 192 195 194 197 196 199 198 201 200 203 202 205 204 207 206 209 208 211 210 213 212 215 214 217 216 219 218 221 220 223 222 225 224 227 226 229 228 231 230 233 232 235 234 237 236 239 238 241 240 243 242 245 244 247 246 249 248 251 250 253 252 255 254 257 256 260 259 262 261 264 263 266 265 268 267 270 269 272 271 274 273 276 275 278 277 280 279 282 281 284 283 286 285 288 287 290 289 292 291 295 294 297 296 299 298 301 300 303 302 305 304 307 306 309 308 311 310 313 312 315 314 317 316 319 318 321 320 323 322 325 324 327 326 329 328 331 330 333 332 335 334 337 336 339 338 341 340 343 342 345 344 347 346 349 348 351 350 353 352 355 354 358 357 360 359 362 361 364 363 366 365 368 367 370 369 372 371 374 373 376 375 378 377 380 379 382 381 384 383 386 385 388 387 390 389 392 391 394 393 396 395 398 397 400 399 402 401 404 403 406 405 409 408 411 410 413 412 415 414 417 416 419 418 421 420 423 422 425 424 427 426 429 428 431 430 433 432 435 434 437 436 439 438 441 440 443 442 445 444 448 447 450 449 452 451 454 453 456 455 458 457 460 459 462 461 464 463 466 465 468 467 470 469 472 471 475 474 477 476 479 478 481 480 483 482 485 484 487 486 490 489 492 491 +DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 50 49 52 51 54 53 56 55 58 57 60 59 62 61 64 63 66 65 68 67 70 69 72 71 74 73 77 76 79 78 81 80 83 82 85 84 87 86 89 88 91 90 93 92 95 94 97 96 99 98 101 100 103 102 105 104 107 106 109 108 111 110 113 112 115 114 117 116 119 118 121 120 123 122 126 125 128 127 130 129 132 131 134 133 136 135 138 137 140 139 142 141 144 143 146 145 148 147 150 149 152 151 154 153 156 155 158 157 160 159 162 161 164 163 166 165 168 167 170 169 172 171 174 173 176 175 178 177 180 179 182 181 184 183 187 186 189 188 191 190 193 192 195 194 197 196 199 198 201 200 203 202 205 204 207 206 209 208 211 210 213 212 215 214 217 216 219 218 221 220 223 222 225 224 227 226 229 228 231 230 233 232 235 234 237 236 239 238 241 240 243 242 245 244 247 246 249 248 251 250 253 252 255 254 257 256 260 259 262 261 264 263 266 265 268 267 270 269 272 271 274 273 276 275 278 277 280 279 282 281 284 283 286 285 288 287 290 289 292 291 295 294 297 296 299 298 301 300 303 302 305 304 307 306 309 308 311 310 313 312 315 314 317 316 319 318 321 320 323 322 325 324 327 326 329 328 331 330 333 332 335 334 337 336 339 338 341 340 343 342 345 344 347 346 349 348 351 350 353 352 355 354 358 357 360 359 362 361 364 363 366 365 368 367 370 369 372 371 374 373 376 375 378 377 380 379 382 381 384 383 386 385 388 387 390 389 392 391 394 393 396 395 398 397 400 399 402 401 404 403 406 405 409 408 411 410 413 412 415 414 417 416 419 418 421 420 423 422 425 424 427 426 429 428 431 430 433 432 435 434 437 436 439 438 441 440 443 442 445 444 448 447 450 449 452 451 454 453 456 455 458 457 460 459 462 461 464 463 466 465 468 467 470 469 472 471 475 474 477 476 479 478 481 480 483 482 485 484 487 486 490 489 492 491 +DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 +TICK +CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 38 51 40 58 42 60 44 62 46 64 48 66 50 68 52 70 54 72 56 74 57 76 59 78 61 80 63 82 65 84 67 86 69 88 71 90 73 92 75 94 77 101 79 103 81 105 83 107 85 109 87 111 89 113 91 115 93 117 95 119 97 121 99 123 100 125 102 127 104 129 106 131 108 133 110 135 112 137 114 139 116 141 118 143 120 145 122 147 124 149 126 156 128 158 130 160 132 162 134 164 136 166 138 168 140 170 142 172 144 174 146 176 148 178 150 180 152 182 154 184 155 186 157 188 159 190 161 192 163 194 165 196 167 198 169 200 171 202 173 204 175 206 177 208 179 210 181 212 183 214 185 216 187 223 189 225 191 227 193 229 195 231 197 233 199 235 201 237 203 239 205 241 207 243 209 245 211 247 213 249 215 251 217 253 219 255 221 257 222 259 224 261 226 263 228 265 230 267 232 269 234 271 236 273 238 275 240 277 242 279 244 281 246 283 248 285 250 287 252 289 254 291 256 293 260 295 262 297 264 299 266 301 268 303 270 305 272 307 274 309 276 311 278 313 280 315 282 317 284 319 286 321 288 323 290 325 292 327 294 328 296 330 298 332 300 334 302 336 304 338 306 340 308 342 310 344 312 346 314 348 316 350 318 352 320 354 322 356 329 358 331 360 333 362 335 364 337 366 339 368 341 370 343 372 345 374 347 376 349 378 351 380 353 382 355 384 357 385 359 387 361 389 363 391 365 393 367 395 369 397 371 399 373 401 375 403 377 405 379 407 386 409 388 411 390 413 392 415 394 417 396 419 398 421 400 423 402 425 404 427 406 429 408 430 410 432 412 434 414 436 416 438 418 440 420 442 422 444 424 446 431 448 433 450 435 452 437 454 439 456 441 458 443 460 445 462 447 463 449 465 451 467 453 469 455 471 457 473 464 475 466 477 468 479 470 481 472 483 474 484 476 486 478 488 485 490 487 492 +DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 38 51 40 58 42 60 44 62 46 64 48 66 50 68 52 70 54 72 56 74 57 76 59 78 61 80 63 82 65 84 67 86 69 88 71 90 73 92 75 94 77 101 79 103 81 105 83 107 85 109 87 111 89 113 91 115 93 117 95 119 97 121 99 123 100 125 102 127 104 129 106 131 108 133 110 135 112 137 114 139 116 141 118 143 120 145 122 147 124 149 126 156 128 158 130 160 132 162 134 164 136 166 138 168 140 170 142 172 144 174 146 176 148 178 150 180 152 182 154 184 155 186 157 188 159 190 161 192 163 194 165 196 167 198 169 200 171 202 173 204 175 206 177 208 179 210 181 212 183 214 185 216 187 223 189 225 191 227 193 229 195 231 197 233 199 235 201 237 203 239 205 241 207 243 209 245 211 247 213 249 215 251 217 253 219 255 221 257 222 259 224 261 226 263 228 265 230 267 232 269 234 271 236 273 238 275 240 277 242 279 244 281 246 283 248 285 250 287 252 289 254 291 256 293 260 295 262 297 264 299 266 301 268 303 270 305 272 307 274 309 276 311 278 313 280 315 282 317 284 319 286 321 288 323 290 325 292 327 294 328 296 330 298 332 300 334 302 336 304 338 306 340 308 342 310 344 312 346 314 348 316 350 318 352 320 354 322 356 329 358 331 360 333 362 335 364 337 366 339 368 341 370 343 372 345 374 347 376 349 378 351 380 353 382 355 384 357 385 359 387 361 389 363 391 365 393 367 395 369 397 371 399 373 401 375 403 377 405 379 407 386 409 388 411 390 413 392 415 394 417 396 419 398 421 400 423 402 425 404 427 406 429 408 430 410 432 412 434 414 436 416 438 418 440 420 442 422 444 424 446 431 448 433 450 435 452 437 454 439 456 441 458 443 460 445 462 447 463 449 465 451 467 453 469 455 471 457 473 464 475 466 477 468 479 470 481 472 483 474 484 476 486 478 488 485 490 487 492 +DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 +TICK +MX(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 +M(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 +TICK +RX 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 +R 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 +OBSERVABLE_INCLUDE(0) rec[-184] rec[-202] rec[-217] rec[-229] rec[-238] rec[-244] +X_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 +Z_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 +DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 +TICK +CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 38 51 40 58 42 60 44 62 46 64 48 66 50 68 52 70 54 72 56 74 57 76 59 78 61 80 63 82 65 84 67 86 69 88 71 90 73 92 75 94 77 101 79 103 81 105 83 107 85 109 87 111 89 113 91 115 93 117 95 119 97 121 99 123 100 125 102 127 104 129 106 131 108 133 110 135 112 137 114 139 116 141 118 143 120 145 122 147 124 149 126 156 128 158 130 160 132 162 134 164 136 166 138 168 140 170 142 172 144 174 146 176 148 178 150 180 152 182 154 184 155 186 157 188 159 190 161 192 163 194 165 196 167 198 169 200 171 202 173 204 175 206 177 208 179 210 181 212 183 214 185 216 187 223 189 225 191 227 193 229 195 231 197 233 199 235 201 237 203 239 205 241 207 243 209 245 211 247 213 249 215 251 217 253 219 255 221 257 222 259 224 261 226 263 228 265 230 267 232 269 234 271 236 273 238 275 240 277 242 279 244 281 246 283 248 285 250 287 252 289 254 291 256 293 260 295 262 297 264 299 266 301 268 303 270 305 272 307 274 309 276 311 278 313 280 315 282 317 284 319 286 321 288 323 290 325 292 327 294 328 296 330 298 332 300 334 302 336 304 338 306 340 308 342 310 344 312 346 314 348 316 350 318 352 320 354 322 356 329 358 331 360 333 362 335 364 337 366 339 368 341 370 343 372 345 374 347 376 349 378 351 380 353 382 355 384 357 385 359 387 361 389 363 391 365 393 367 395 369 397 371 399 373 401 375 403 377 405 379 407 386 409 388 411 390 413 392 415 394 417 396 419 398 421 400 423 402 425 404 427 406 429 408 430 410 432 412 434 414 436 416 438 418 440 420 442 422 444 424 446 431 448 433 450 435 452 437 454 439 456 441 458 443 460 445 462 447 463 449 465 451 467 453 469 455 471 457 473 464 475 466 477 468 479 470 481 472 483 474 484 476 486 478 488 485 490 487 492 +DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 38 51 40 58 42 60 44 62 46 64 48 66 50 68 52 70 54 72 56 74 57 76 59 78 61 80 63 82 65 84 67 86 69 88 71 90 73 92 75 94 77 101 79 103 81 105 83 107 85 109 87 111 89 113 91 115 93 117 95 119 97 121 99 123 100 125 102 127 104 129 106 131 108 133 110 135 112 137 114 139 116 141 118 143 120 145 122 147 124 149 126 156 128 158 130 160 132 162 134 164 136 166 138 168 140 170 142 172 144 174 146 176 148 178 150 180 152 182 154 184 155 186 157 188 159 190 161 192 163 194 165 196 167 198 169 200 171 202 173 204 175 206 177 208 179 210 181 212 183 214 185 216 187 223 189 225 191 227 193 229 195 231 197 233 199 235 201 237 203 239 205 241 207 243 209 245 211 247 213 249 215 251 217 253 219 255 221 257 222 259 224 261 226 263 228 265 230 267 232 269 234 271 236 273 238 275 240 277 242 279 244 281 246 283 248 285 250 287 252 289 254 291 256 293 260 295 262 297 264 299 266 301 268 303 270 305 272 307 274 309 276 311 278 313 280 315 282 317 284 319 286 321 288 323 290 325 292 327 294 328 296 330 298 332 300 334 302 336 304 338 306 340 308 342 310 344 312 346 314 348 316 350 318 352 320 354 322 356 329 358 331 360 333 362 335 364 337 366 339 368 341 370 343 372 345 374 347 376 349 378 351 380 353 382 355 384 357 385 359 387 361 389 363 391 365 393 367 395 369 397 371 399 373 401 375 403 377 405 379 407 386 409 388 411 390 413 392 415 394 417 396 419 398 421 400 423 402 425 404 427 406 429 408 430 410 432 412 434 414 436 416 438 418 440 420 442 422 444 424 446 431 448 433 450 435 452 437 454 439 456 441 458 443 460 445 462 447 463 449 465 451 467 453 469 455 471 457 473 464 475 466 477 468 479 470 481 472 483 474 484 476 486 478 488 485 490 487 492 +DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 +TICK +CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 50 49 52 51 54 53 56 55 58 57 60 59 62 61 64 63 66 65 68 67 70 69 72 71 74 73 77 76 79 78 81 80 83 82 85 84 87 86 89 88 91 90 93 92 95 94 97 96 99 98 101 100 103 102 105 104 107 106 109 108 111 110 113 112 115 114 117 116 119 118 121 120 123 122 126 125 128 127 130 129 132 131 134 133 136 135 138 137 140 139 142 141 144 143 146 145 148 147 150 149 152 151 154 153 156 155 158 157 160 159 162 161 164 163 166 165 168 167 170 169 172 171 174 173 176 175 178 177 180 179 182 181 184 183 187 186 189 188 191 190 193 192 195 194 197 196 199 198 201 200 203 202 205 204 207 206 209 208 211 210 213 212 215 214 217 216 219 218 221 220 223 222 225 224 227 226 229 228 231 230 233 232 235 234 237 236 239 238 241 240 243 242 245 244 247 246 249 248 251 250 253 252 255 254 257 256 260 259 262 261 264 263 266 265 268 267 270 269 272 271 274 273 276 275 278 277 280 279 282 281 284 283 286 285 288 287 290 289 292 291 295 294 297 296 299 298 301 300 303 302 305 304 307 306 309 308 311 310 313 312 315 314 317 316 319 318 321 320 323 322 325 324 327 326 329 328 331 330 333 332 335 334 337 336 339 338 341 340 343 342 345 344 347 346 349 348 351 350 353 352 355 354 358 357 360 359 362 361 364 363 366 365 368 367 370 369 372 371 374 373 376 375 378 377 380 379 382 381 384 383 386 385 388 387 390 389 392 391 394 393 396 395 398 397 400 399 402 401 404 403 406 405 409 408 411 410 413 412 415 414 417 416 419 418 421 420 423 422 425 424 427 426 429 428 431 430 433 432 435 434 437 436 439 438 441 440 443 442 445 444 448 447 450 449 452 451 454 453 456 455 458 457 460 459 462 461 464 463 466 465 468 467 470 469 472 471 475 474 477 476 479 478 481 480 483 482 485 484 487 486 490 489 492 491 +DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 50 49 52 51 54 53 56 55 58 57 60 59 62 61 64 63 66 65 68 67 70 69 72 71 74 73 77 76 79 78 81 80 83 82 85 84 87 86 89 88 91 90 93 92 95 94 97 96 99 98 101 100 103 102 105 104 107 106 109 108 111 110 113 112 115 114 117 116 119 118 121 120 123 122 126 125 128 127 130 129 132 131 134 133 136 135 138 137 140 139 142 141 144 143 146 145 148 147 150 149 152 151 154 153 156 155 158 157 160 159 162 161 164 163 166 165 168 167 170 169 172 171 174 173 176 175 178 177 180 179 182 181 184 183 187 186 189 188 191 190 193 192 195 194 197 196 199 198 201 200 203 202 205 204 207 206 209 208 211 210 213 212 215 214 217 216 219 218 221 220 223 222 225 224 227 226 229 228 231 230 233 232 235 234 237 236 239 238 241 240 243 242 245 244 247 246 249 248 251 250 253 252 255 254 257 256 260 259 262 261 264 263 266 265 268 267 270 269 272 271 274 273 276 275 278 277 280 279 282 281 284 283 286 285 288 287 290 289 292 291 295 294 297 296 299 298 301 300 303 302 305 304 307 306 309 308 311 310 313 312 315 314 317 316 319 318 321 320 323 322 325 324 327 326 329 328 331 330 333 332 335 334 337 336 339 338 341 340 343 342 345 344 347 346 349 348 351 350 353 352 355 354 358 357 360 359 362 361 364 363 366 365 368 367 370 369 372 371 374 373 376 375 378 377 380 379 382 381 384 383 386 385 388 387 390 389 392 391 394 393 396 395 398 397 400 399 402 401 404 403 406 405 409 408 411 410 413 412 415 414 417 416 419 418 421 420 423 422 425 424 427 426 429 428 431 430 433 432 435 434 437 436 439 438 441 440 443 442 445 444 448 447 450 449 452 451 454 453 456 455 458 457 460 459 462 461 464 463 466 465 468 467 470 469 472 471 475 474 477 476 479 478 481 480 483 482 485 484 487 486 490 489 492 491 +DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 +TICK +CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 51 50 53 52 55 54 59 58 61 60 63 62 65 64 67 66 69 68 71 70 73 72 75 74 78 77 80 79 82 81 84 83 86 85 88 87 90 89 92 91 94 93 96 95 98 97 102 101 104 103 106 105 108 107 110 109 112 111 114 113 116 115 118 117 120 119 122 121 124 123 127 126 129 128 131 130 133 132 135 134 137 136 139 138 141 140 143 142 145 144 147 146 149 148 151 150 153 152 157 156 159 158 161 160 163 162 165 164 167 166 169 168 171 170 173 172 175 174 177 176 179 178 181 180 183 182 185 184 188 187 190 189 192 191 194 193 196 195 198 197 200 199 202 201 204 203 206 205 208 207 210 209 212 211 214 213 216 215 218 217 220 219 224 223 226 225 228 227 230 229 232 231 234 233 236 235 238 237 240 239 242 241 244 243 246 245 248 247 250 249 252 251 254 253 256 255 258 257 261 260 263 262 265 264 267 266 269 268 271 270 273 272 275 274 277 276 279 278 281 280 283 282 285 284 287 286 289 288 291 290 293 292 296 295 298 297 300 299 302 301 304 303 306 305 308 307 310 309 312 311 314 313 316 315 318 317 320 319 322 321 324 323 326 325 330 329 332 331 334 333 336 335 338 337 340 339 342 341 344 343 346 345 348 347 350 349 352 351 354 353 356 355 359 358 361 360 363 362 365 364 367 366 369 368 371 370 373 372 375 374 377 376 379 378 381 380 383 382 387 386 389 388 391 390 393 392 395 394 397 396 399 398 401 400 403 402 405 404 407 406 410 409 412 411 414 413 416 415 418 417 420 419 422 421 424 423 426 425 428 427 432 431 434 433 436 435 438 437 440 439 442 441 444 443 446 445 449 448 451 450 453 452 455 454 457 456 459 458 461 460 465 464 467 466 469 468 471 470 473 472 476 475 478 477 480 479 482 481 486 485 488 487 491 490 +DETECTOR(1, 1, 0, 4) rec[-126] +DETECTOR(1, 2, 0, 2) rec[-492] rec[-246] +DETECTOR(1, 4, 0, 0) rec[-491] rec[-245] +DETECTOR(1, 5, 0, 3) rec[-365] rec[-364] rec[-125] +DETECTOR(1, 6, 0, 1) rec[-244] +DETECTOR(3, 1, 0, 4) rec[-124] +DETECTOR(3, 2, 0, 2) rec[-490] rec[-489] rec[-243] +DETECTOR(3, 3, 0, 5) rec[-363] rec[-123] +DETECTOR(3, 4, 0, 0) rec[-488] rec[-242] +DETECTOR(3, 5, 0, 3) rec[-362] rec[-122] +DETECTOR(3, 6, 0, 1) rec[-487] rec[-241] +DETECTOR(3, 7, 0, 4) rec[-361] rec[-121] +DETECTOR(3, 8, 0, 2) rec[-240] +DETECTOR(3, 10, 0, 0) rec[-486] rec[-239] +DETECTOR(3, 11, 0, 3) rec[-359] rec[-358] rec[-120] +DETECTOR(3, 12, 0, 1) rec[-238] +DETECTOR(5, 1, 0, 4) rec[-119] +DETECTOR(5, 2, 0, 2) rec[-485] rec[-484] rec[-237] +DETECTOR(5, 3, 0, 5) rec[-357] rec[-118] +DETECTOR(5, 4, 0, 0) rec[-483] rec[-236] +DETECTOR(5, 5, 0, 3) rec[-356] rec[-117] +DETECTOR(5, 6, 0, 1) rec[-482] rec[-235] +DETECTOR(5, 7, 0, 4) rec[-355] rec[-116] +DETECTOR(5, 8, 0, 2) rec[-481] rec[-234] +DETECTOR(5, 9, 0, 5) rec[-354] rec[-115] +DETECTOR(5, 10, 0, 0) rec[-480] rec[-233] +DETECTOR(5, 11, 0, 3) rec[-353] rec[-114] +DETECTOR(5, 12, 0, 1) rec[-479] rec[-232] +DETECTOR(5, 13, 0, 4) rec[-352] rec[-113] +DETECTOR(5, 14, 0, 2) rec[-231] +DETECTOR(5, 16, 0, 0) rec[-478] rec[-230] +DETECTOR(5, 17, 0, 3) rec[-350] rec[-349] rec[-112] +DETECTOR(5, 18, 0, 1) rec[-229] +DETECTOR(7, 1, 0, 4) rec[-111] +DETECTOR(7, 2, 0, 2) rec[-477] rec[-476] rec[-228] +DETECTOR(7, 3, 0, 5) rec[-348] rec[-110] +DETECTOR(7, 4, 0, 0) rec[-475] rec[-227] +DETECTOR(7, 5, 0, 3) rec[-347] rec[-109] +DETECTOR(7, 6, 0, 1) rec[-474] rec[-226] +DETECTOR(7, 7, 0, 4) rec[-346] rec[-108] +DETECTOR(7, 8, 0, 2) rec[-473] rec[-225] +DETECTOR(7, 9, 0, 5) rec[-345] rec[-107] +DETECTOR(7, 10, 0, 0) rec[-472] rec[-224] +DETECTOR(7, 11, 0, 3) rec[-344] rec[-106] +DETECTOR(7, 12, 0, 1) rec[-471] rec[-223] +DETECTOR(7, 13, 0, 4) rec[-343] rec[-105] +DETECTOR(7, 14, 0, 2) rec[-470] rec[-222] +DETECTOR(7, 15, 0, 5) rec[-342] rec[-104] +DETECTOR(7, 16, 0, 0) rec[-469] rec[-221] +DETECTOR(7, 17, 0, 3) rec[-341] rec[-103] +DETECTOR(7, 18, 0, 1) rec[-468] rec[-220] +DETECTOR(7, 19, 0, 4) rec[-340] rec[-102] +DETECTOR(7, 20, 0, 2) rec[-219] +DETECTOR(7, 22, 0, 0) rec[-467] rec[-218] +DETECTOR(7, 23, 0, 3) rec[-338] rec[-337] rec[-101] +DETECTOR(7, 24, 0, 1) rec[-217] +DETECTOR(9, 1, 0, 4) rec[-100] +DETECTOR(9, 2, 0, 2) rec[-466] rec[-465] rec[-216] +DETECTOR(9, 3, 0, 5) rec[-336] rec[-99] +DETECTOR(9, 4, 0, 0) rec[-464] rec[-215] +DETECTOR(9, 5, 0, 3) rec[-335] rec[-98] +DETECTOR(9, 6, 0, 1) rec[-463] rec[-214] +DETECTOR(9, 7, 0, 4) rec[-334] rec[-97] +DETECTOR(9, 8, 0, 2) rec[-462] rec[-213] +DETECTOR(9, 9, 0, 5) rec[-333] rec[-96] +DETECTOR(9, 10, 0, 0) rec[-461] rec[-212] +DETECTOR(9, 11, 0, 3) rec[-332] rec[-95] +DETECTOR(9, 12, 0, 1) rec[-460] rec[-211] +DETECTOR(9, 13, 0, 4) rec[-331] rec[-94] +DETECTOR(9, 14, 0, 2) rec[-459] rec[-210] +DETECTOR(9, 15, 0, 5) rec[-330] rec[-93] +DETECTOR(9, 16, 0, 0) rec[-458] rec[-209] +DETECTOR(9, 17, 0, 3) rec[-329] rec[-92] +DETECTOR(9, 18, 0, 1) rec[-457] rec[-208] +DETECTOR(9, 19, 0, 4) rec[-328] rec[-91] +DETECTOR(9, 20, 0, 2) rec[-456] rec[-207] +DETECTOR(9, 21, 0, 5) rec[-327] rec[-90] +DETECTOR(9, 22, 0, 0) rec[-455] rec[-206] +DETECTOR(9, 23, 0, 3) rec[-326] rec[-89] +DETECTOR(9, 24, 0, 1) rec[-454] rec[-205] +DETECTOR(9, 25, 0, 4) rec[-325] rec[-88] +DETECTOR(9, 26, 0, 2) rec[-204] +DETECTOR(9, 28, 0, 0) rec[-453] rec[-203] +DETECTOR(9, 29, 0, 3) rec[-323] rec[-322] rec[-87] +DETECTOR(9, 30, 0, 1) rec[-202] +DETECTOR(11, 1, 0, 4) rec[-86] +DETECTOR(11, 2, 0, 2) rec[-452] rec[-451] rec[-201] +DETECTOR(11, 3, 0, 5) rec[-321] rec[-85] +DETECTOR(11, 4, 0, 0) rec[-450] rec[-200] +DETECTOR(11, 5, 0, 3) rec[-320] rec[-84] +DETECTOR(11, 6, 0, 1) rec[-449] rec[-199] +DETECTOR(11, 7, 0, 4) rec[-319] rec[-83] +DETECTOR(11, 8, 0, 2) rec[-448] rec[-198] +DETECTOR(11, 9, 0, 5) rec[-318] rec[-82] +DETECTOR(11, 10, 0, 0) rec[-447] rec[-197] +DETECTOR(11, 11, 0, 3) rec[-317] rec[-81] +DETECTOR(11, 12, 0, 1) rec[-446] rec[-196] +DETECTOR(11, 13, 0, 4) rec[-316] rec[-80] +DETECTOR(11, 14, 0, 2) rec[-445] rec[-195] +DETECTOR(11, 15, 0, 5) rec[-315] rec[-79] +DETECTOR(11, 16, 0, 0) rec[-444] rec[-194] +DETECTOR(11, 17, 0, 3) rec[-314] rec[-78] +DETECTOR(11, 18, 0, 1) rec[-443] rec[-193] +DETECTOR(11, 19, 0, 4) rec[-313] rec[-77] +DETECTOR(11, 20, 0, 2) rec[-442] rec[-192] +DETECTOR(11, 21, 0, 5) rec[-312] rec[-76] +DETECTOR(11, 22, 0, 0) rec[-441] rec[-191] +DETECTOR(11, 23, 0, 3) rec[-311] rec[-75] +DETECTOR(11, 24, 0, 1) rec[-440] rec[-190] +DETECTOR(11, 25, 0, 4) rec[-310] rec[-74] +DETECTOR(11, 26, 0, 2) rec[-439] rec[-189] +DETECTOR(11, 27, 0, 5) rec[-309] rec[-73] +DETECTOR(11, 28, 0, 0) rec[-438] rec[-188] +DETECTOR(11, 29, 0, 3) rec[-308] rec[-72] +DETECTOR(11, 30, 0, 1) rec[-437] rec[-187] +DETECTOR(11, 31, 0, 4) rec[-307] rec[-71] +DETECTOR(11, 32, 0, 2) rec[-186] +DETECTOR(11, 34, 0, 0) rec[-436] rec[-185] +DETECTOR(11, 35, 0, 3) rec[-305] rec[-304] rec[-70] +DETECTOR(11, 36, 0, 1) rec[-184] +DETECTOR(13, 1, 0, 4) rec[-69] +DETECTOR(13, 2, 0, 2) rec[-435] rec[-434] rec[-183] +DETECTOR(13, 3, 0, 5) rec[-303] rec[-68] +DETECTOR(13, 4, 0, 0) rec[-433] rec[-182] +DETECTOR(13, 5, 0, 3) rec[-302] rec[-67] +DETECTOR(13, 6, 0, 1) rec[-432] rec[-181] +DETECTOR(13, 7, 0, 4) rec[-301] rec[-66] +DETECTOR(13, 8, 0, 2) rec[-431] rec[-180] +DETECTOR(13, 9, 0, 5) rec[-300] rec[-65] +DETECTOR(13, 10, 0, 0) rec[-430] rec[-179] +DETECTOR(13, 11, 0, 3) rec[-299] rec[-64] +DETECTOR(13, 12, 0, 1) rec[-429] rec[-178] +DETECTOR(13, 13, 0, 4) rec[-298] rec[-63] +DETECTOR(13, 14, 0, 2) rec[-428] rec[-177] +DETECTOR(13, 15, 0, 5) rec[-297] rec[-62] +DETECTOR(13, 16, 0, 0) rec[-427] rec[-176] +DETECTOR(13, 17, 0, 3) rec[-296] rec[-61] +DETECTOR(13, 18, 0, 1) rec[-426] rec[-175] +DETECTOR(13, 19, 0, 4) rec[-295] rec[-60] +DETECTOR(13, 20, 0, 2) rec[-425] rec[-174] +DETECTOR(13, 21, 0, 5) rec[-294] rec[-59] +DETECTOR(13, 22, 0, 0) rec[-424] rec[-173] +DETECTOR(13, 23, 0, 3) rec[-293] rec[-58] +DETECTOR(13, 24, 0, 1) rec[-423] rec[-172] +DETECTOR(13, 25, 0, 4) rec[-292] rec[-57] +DETECTOR(13, 26, 0, 2) rec[-422] rec[-171] +DETECTOR(13, 27, 0, 5) rec[-291] rec[-56] +DETECTOR(13, 28, 0, 0) rec[-421] rec[-170] +DETECTOR(13, 29, 0, 3) rec[-290] rec[-55] +DETECTOR(13, 30, 0, 1) rec[-420] rec[-169] +DETECTOR(13, 31, 0, 4) rec[-289] rec[-54] +DETECTOR(13, 32, 0, 2) rec[-419] rec[-417] rec[-168] +DETECTOR(13, 33, 0, 5) rec[-288] rec[-53] +DETECTOR(13, 34, 0, 0) rec[-418] rec[-167] +DETECTOR(13, 35, 0, 3) rec[-287] rec[-52] +DETECTOR(14, 33, 0, 5) rec[-51] +DETECTOR(15, 1, 0, 4) rec[-50] +DETECTOR(15, 2, 0, 2) rec[-416] rec[-415] rec[-166] +DETECTOR(15, 3, 0, 5) rec[-286] rec[-49] +DETECTOR(15, 4, 0, 0) rec[-414] rec[-165] +DETECTOR(15, 5, 0, 3) rec[-285] rec[-48] +DETECTOR(15, 6, 0, 1) rec[-413] rec[-164] +DETECTOR(15, 7, 0, 4) rec[-284] rec[-47] +DETECTOR(15, 8, 0, 2) rec[-412] rec[-163] +DETECTOR(15, 9, 0, 5) rec[-283] rec[-46] +DETECTOR(15, 10, 0, 0) rec[-411] rec[-162] +DETECTOR(15, 11, 0, 3) rec[-282] rec[-45] +DETECTOR(15, 12, 0, 1) rec[-410] rec[-161] +DETECTOR(15, 13, 0, 4) rec[-281] rec[-44] +DETECTOR(15, 14, 0, 2) rec[-409] rec[-160] +DETECTOR(15, 15, 0, 5) rec[-280] rec[-43] +DETECTOR(15, 16, 0, 0) rec[-408] rec[-159] +DETECTOR(15, 17, 0, 3) rec[-279] rec[-42] +DETECTOR(15, 18, 0, 1) rec[-407] rec[-158] +DETECTOR(15, 19, 0, 4) rec[-278] rec[-41] +DETECTOR(15, 20, 0, 2) rec[-406] rec[-157] +DETECTOR(15, 21, 0, 5) rec[-277] rec[-40] +DETECTOR(15, 22, 0, 0) rec[-405] rec[-156] +DETECTOR(15, 23, 0, 3) rec[-276] rec[-39] +DETECTOR(15, 24, 0, 1) rec[-404] rec[-155] +DETECTOR(15, 25, 0, 4) rec[-275] rec[-38] +DETECTOR(15, 26, 0, 2) rec[-403] rec[-401] rec[-154] +DETECTOR(15, 27, 0, 5) rec[-274] rec[-37] +DETECTOR(15, 28, 0, 0) rec[-402] rec[-153] +DETECTOR(15, 29, 0, 3) rec[-273] rec[-36] +DETECTOR(16, 27, 0, 5) rec[-35] +DETECTOR(17, 1, 0, 4) rec[-34] +DETECTOR(17, 2, 0, 2) rec[-400] rec[-399] rec[-152] +DETECTOR(17, 3, 0, 5) rec[-272] rec[-33] +DETECTOR(17, 4, 0, 0) rec[-398] rec[-151] +DETECTOR(17, 5, 0, 3) rec[-271] rec[-32] +DETECTOR(17, 6, 0, 1) rec[-397] rec[-150] +DETECTOR(17, 7, 0, 4) rec[-270] rec[-31] +DETECTOR(17, 8, 0, 2) rec[-396] rec[-149] +DETECTOR(17, 9, 0, 5) rec[-269] rec[-30] +DETECTOR(17, 10, 0, 0) rec[-395] rec[-148] +DETECTOR(17, 11, 0, 3) rec[-268] rec[-29] +DETECTOR(17, 12, 0, 1) rec[-394] rec[-147] +DETECTOR(17, 13, 0, 4) rec[-267] rec[-28] +DETECTOR(17, 14, 0, 2) rec[-393] rec[-146] +DETECTOR(17, 15, 0, 5) rec[-266] rec[-27] +DETECTOR(17, 16, 0, 0) rec[-392] rec[-145] +DETECTOR(17, 17, 0, 3) rec[-265] rec[-26] +DETECTOR(17, 18, 0, 1) rec[-391] rec[-144] +DETECTOR(17, 19, 0, 4) rec[-264] rec[-25] +DETECTOR(17, 20, 0, 2) rec[-390] rec[-388] rec[-143] +DETECTOR(17, 21, 0, 5) rec[-263] rec[-24] +DETECTOR(17, 22, 0, 0) rec[-389] rec[-142] +DETECTOR(17, 23, 0, 3) rec[-262] rec[-23] +DETECTOR(18, 21, 0, 5) rec[-22] +DETECTOR(19, 1, 0, 4) rec[-21] +DETECTOR(19, 2, 0, 2) rec[-387] rec[-386] rec[-141] +DETECTOR(19, 3, 0, 5) rec[-261] rec[-20] +DETECTOR(19, 4, 0, 0) rec[-385] rec[-140] +DETECTOR(19, 5, 0, 3) rec[-260] rec[-19] +DETECTOR(19, 6, 0, 1) rec[-384] rec[-139] +DETECTOR(19, 7, 0, 4) rec[-259] rec[-18] +DETECTOR(19, 8, 0, 2) rec[-383] rec[-138] +DETECTOR(19, 9, 0, 5) rec[-258] rec[-17] +DETECTOR(19, 10, 0, 0) rec[-382] rec[-137] +DETECTOR(19, 11, 0, 3) rec[-257] rec[-16] +DETECTOR(19, 12, 0, 1) rec[-381] rec[-136] +DETECTOR(19, 13, 0, 4) rec[-256] rec[-15] +DETECTOR(19, 14, 0, 2) rec[-380] rec[-378] rec[-135] +DETECTOR(19, 15, 0, 5) rec[-255] rec[-14] +DETECTOR(19, 16, 0, 0) rec[-379] rec[-134] +DETECTOR(19, 17, 0, 3) rec[-254] rec[-13] +DETECTOR(20, 15, 0, 5) rec[-12] +DETECTOR(21, 1, 0, 4) rec[-11] +DETECTOR(21, 2, 0, 2) rec[-377] rec[-376] rec[-133] +DETECTOR(21, 3, 0, 5) rec[-253] rec[-10] +DETECTOR(21, 4, 0, 0) rec[-375] rec[-132] +DETECTOR(21, 5, 0, 3) rec[-252] rec[-9] +DETECTOR(21, 6, 0, 1) rec[-374] rec[-131] +DETECTOR(21, 7, 0, 4) rec[-251] rec[-8] +DETECTOR(21, 8, 0, 2) rec[-373] rec[-371] rec[-130] +DETECTOR(21, 9, 0, 5) rec[-250] rec[-7] +DETECTOR(21, 10, 0, 0) rec[-372] rec[-129] +DETECTOR(21, 11, 0, 3) rec[-249] rec[-6] +DETECTOR(22, 9, 0, 5) rec[-5] +DETECTOR(23, 1, 0, 4) rec[-4] +DETECTOR(23, 2, 0, 2) rec[-370] rec[-369] rec[-367] rec[-128] +DETECTOR(23, 3, 0, 5) rec[-248] rec[-3] +DETECTOR(23, 4, 0, 0) rec[-368] rec[-127] +DETECTOR(23, 5, 0, 3) rec[-247] rec[-2] +DETECTOR(24, 3, 0, 5) rec[-1] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 51 50 53 52 55 54 59 58 61 60 63 62 65 64 67 66 69 68 71 70 73 72 75 74 78 77 80 79 82 81 84 83 86 85 88 87 90 89 92 91 94 93 96 95 98 97 102 101 104 103 106 105 108 107 110 109 112 111 114 113 116 115 118 117 120 119 122 121 124 123 127 126 129 128 131 130 133 132 135 134 137 136 139 138 141 140 143 142 145 144 147 146 149 148 151 150 153 152 157 156 159 158 161 160 163 162 165 164 167 166 169 168 171 170 173 172 175 174 177 176 179 178 181 180 183 182 185 184 188 187 190 189 192 191 194 193 196 195 198 197 200 199 202 201 204 203 206 205 208 207 210 209 212 211 214 213 216 215 218 217 220 219 224 223 226 225 228 227 230 229 232 231 234 233 236 235 238 237 240 239 242 241 244 243 246 245 248 247 250 249 252 251 254 253 256 255 258 257 261 260 263 262 265 264 267 266 269 268 271 270 273 272 275 274 277 276 279 278 281 280 283 282 285 284 287 286 289 288 291 290 293 292 296 295 298 297 300 299 302 301 304 303 306 305 308 307 310 309 312 311 314 313 316 315 318 317 320 319 322 321 324 323 326 325 330 329 332 331 334 333 336 335 338 337 340 339 342 341 344 343 346 345 348 347 350 349 352 351 354 353 356 355 359 358 361 360 363 362 365 364 367 366 369 368 371 370 373 372 375 374 377 376 379 378 381 380 383 382 387 386 389 388 391 390 393 392 395 394 397 396 399 398 401 400 403 402 405 404 407 406 410 409 412 411 414 413 416 415 418 417 420 419 422 421 424 423 426 425 428 427 432 431 434 433 436 435 438 437 440 439 442 441 444 443 446 445 449 448 451 450 453 452 455 454 457 456 459 458 461 460 465 464 467 466 469 468 471 470 473 472 476 475 478 477 480 479 482 481 486 485 488 487 491 490 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 +TICK +REPEAT 48 { + CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 + DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 + DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 + TICK + CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 + DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 + DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 + TICK + CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 + DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 + DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 + TICK + MX(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 + M(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 + TICK + RX 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 + R 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 + OBSERVABLE_INCLUDE(0) rec[-124] rec[-131] rec[-141] rec[-154] rec[-170] rec[-189] rec[-206] rec[-220] rec[-231] rec[-239] rec[-244] rec[-246] + X_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 + Z_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 + DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 + TICK + CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 + DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 + DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 + TICK + CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 + DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 + DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 + TICK + CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 + DETECTOR(1, 1, 0, 1) rec[-246] + DETECTOR(1, 2, 0, 5) rec[-372] rec[-120] + DETECTOR(1, 4, 0, 3) rec[-371] rec[-119] + DETECTOR(1, 5, 0, 0) rec[-491] rec[-490] rec[-245] + DETECTOR(1, 6, 0, 4) rec[-118] + DETECTOR(3, 1, 0, 1) rec[-244] + DETECTOR(3, 2, 0, 5) rec[-370] rec[-369] rec[-117] + DETECTOR(3, 3, 0, 2) rec[-489] rec[-243] + DETECTOR(3, 4, 0, 3) rec[-368] rec[-116] + DETECTOR(3, 5, 0, 0) rec[-488] rec[-242] + DETECTOR(3, 6, 0, 4) rec[-367] rec[-115] + DETECTOR(3, 7, 0, 1) rec[-487] rec[-241] + DETECTOR(3, 8, 0, 5) rec[-114] + DETECTOR(3, 10, 0, 3) rec[-366] rec[-113] + DETECTOR(3, 11, 0, 0) rec[-485] rec[-484] rec[-240] + DETECTOR(3, 12, 0, 4) rec[-112] + DETECTOR(5, 1, 0, 1) rec[-239] + DETECTOR(5, 2, 0, 5) rec[-365] rec[-364] rec[-111] + DETECTOR(5, 3, 0, 2) rec[-483] rec[-238] + DETECTOR(5, 4, 0, 3) rec[-363] rec[-110] + DETECTOR(5, 5, 0, 0) rec[-482] rec[-237] + DETECTOR(5, 6, 0, 4) rec[-362] rec[-109] + DETECTOR(5, 7, 0, 1) rec[-481] rec[-236] + DETECTOR(5, 8, 0, 5) rec[-361] rec[-108] + DETECTOR(5, 9, 0, 2) rec[-480] rec[-235] + DETECTOR(5, 10, 0, 3) rec[-360] rec[-107] + DETECTOR(5, 11, 0, 0) rec[-479] rec[-234] + DETECTOR(5, 12, 0, 4) rec[-359] rec[-106] + DETECTOR(5, 13, 0, 1) rec[-478] rec[-233] + DETECTOR(5, 14, 0, 5) rec[-105] + DETECTOR(5, 16, 0, 3) rec[-358] rec[-104] + DETECTOR(5, 17, 0, 0) rec[-476] rec[-475] rec[-232] + DETECTOR(5, 18, 0, 4) rec[-103] + DETECTOR(7, 1, 0, 1) rec[-231] + DETECTOR(7, 2, 0, 5) rec[-357] rec[-356] rec[-102] + DETECTOR(7, 3, 0, 2) rec[-474] rec[-230] + DETECTOR(7, 4, 0, 3) rec[-355] rec[-101] + DETECTOR(7, 5, 0, 0) rec[-473] rec[-229] + DETECTOR(7, 6, 0, 4) rec[-354] rec[-100] + DETECTOR(7, 7, 0, 1) rec[-472] rec[-228] + DETECTOR(7, 8, 0, 5) rec[-353] rec[-99] + DETECTOR(7, 9, 0, 2) rec[-471] rec[-227] + DETECTOR(7, 10, 0, 3) rec[-352] rec[-98] + DETECTOR(7, 11, 0, 0) rec[-470] rec[-226] + DETECTOR(7, 12, 0, 4) rec[-351] rec[-97] + DETECTOR(7, 13, 0, 1) rec[-469] rec[-225] + DETECTOR(7, 14, 0, 5) rec[-350] rec[-96] + DETECTOR(7, 15, 0, 2) rec[-468] rec[-224] + DETECTOR(7, 16, 0, 3) rec[-349] rec[-95] + DETECTOR(7, 17, 0, 0) rec[-467] rec[-223] + DETECTOR(7, 18, 0, 4) rec[-348] rec[-94] + DETECTOR(7, 19, 0, 1) rec[-466] rec[-222] + DETECTOR(7, 20, 0, 5) rec[-93] + DETECTOR(7, 22, 0, 3) rec[-347] rec[-92] + DETECTOR(7, 23, 0, 0) rec[-464] rec[-463] rec[-221] + DETECTOR(7, 24, 0, 4) rec[-91] + DETECTOR(9, 1, 0, 1) rec[-220] + DETECTOR(9, 2, 0, 5) rec[-346] rec[-345] rec[-90] + DETECTOR(9, 3, 0, 2) rec[-462] rec[-219] + DETECTOR(9, 4, 0, 3) rec[-344] rec[-89] + DETECTOR(9, 5, 0, 0) rec[-461] rec[-218] + DETECTOR(9, 6, 0, 4) rec[-343] rec[-88] + DETECTOR(9, 7, 0, 1) rec[-460] rec[-217] + DETECTOR(9, 8, 0, 5) rec[-342] rec[-87] + DETECTOR(9, 9, 0, 2) rec[-459] rec[-216] + DETECTOR(9, 10, 0, 3) rec[-341] rec[-86] + DETECTOR(9, 11, 0, 0) rec[-458] rec[-215] + DETECTOR(9, 12, 0, 4) rec[-340] rec[-85] + DETECTOR(9, 13, 0, 1) rec[-457] rec[-214] + DETECTOR(9, 14, 0, 5) rec[-339] rec[-84] + DETECTOR(9, 15, 0, 2) rec[-456] rec[-213] + DETECTOR(9, 16, 0, 3) rec[-338] rec[-83] + DETECTOR(9, 17, 0, 0) rec[-455] rec[-212] + DETECTOR(9, 18, 0, 4) rec[-337] rec[-82] + DETECTOR(9, 19, 0, 1) rec[-454] rec[-211] + DETECTOR(9, 20, 0, 5) rec[-336] rec[-81] + DETECTOR(9, 21, 0, 2) rec[-453] rec[-210] + DETECTOR(9, 22, 0, 3) rec[-335] rec[-80] + DETECTOR(9, 23, 0, 0) rec[-452] rec[-209] + DETECTOR(9, 24, 0, 4) rec[-334] rec[-79] + DETECTOR(9, 25, 0, 1) rec[-451] rec[-208] + DETECTOR(9, 26, 0, 5) rec[-78] + DETECTOR(9, 28, 0, 3) rec[-333] rec[-77] + DETECTOR(9, 29, 0, 0) rec[-449] rec[-448] rec[-207] + DETECTOR(9, 30, 0, 4) rec[-76] + DETECTOR(11, 1, 0, 1) rec[-206] + DETECTOR(11, 2, 0, 5) rec[-332] rec[-331] rec[-75] + DETECTOR(11, 3, 0, 2) rec[-447] rec[-205] + DETECTOR(11, 4, 0, 3) rec[-330] rec[-74] + DETECTOR(11, 5, 0, 0) rec[-446] rec[-204] + DETECTOR(11, 6, 0, 4) rec[-329] rec[-73] + DETECTOR(11, 7, 0, 1) rec[-445] rec[-203] + DETECTOR(11, 8, 0, 5) rec[-328] rec[-72] + DETECTOR(11, 9, 0, 2) rec[-444] rec[-202] + DETECTOR(11, 10, 0, 3) rec[-327] rec[-71] + DETECTOR(11, 11, 0, 0) rec[-443] rec[-201] + DETECTOR(11, 12, 0, 4) rec[-326] rec[-70] + DETECTOR(11, 13, 0, 1) rec[-442] rec[-200] + DETECTOR(11, 14, 0, 5) rec[-325] rec[-69] + DETECTOR(11, 15, 0, 2) rec[-441] rec[-199] + DETECTOR(11, 16, 0, 3) rec[-324] rec[-68] + DETECTOR(11, 17, 0, 0) rec[-440] rec[-198] + DETECTOR(11, 18, 0, 4) rec[-323] rec[-67] + DETECTOR(11, 19, 0, 1) rec[-439] rec[-197] + DETECTOR(11, 20, 0, 5) rec[-322] rec[-66] + DETECTOR(11, 21, 0, 2) rec[-438] rec[-196] + DETECTOR(11, 22, 0, 3) rec[-321] rec[-65] + DETECTOR(11, 23, 0, 0) rec[-437] rec[-195] + DETECTOR(11, 24, 0, 4) rec[-320] rec[-64] + DETECTOR(11, 25, 0, 1) rec[-436] rec[-194] + DETECTOR(11, 26, 0, 5) rec[-319] rec[-63] + DETECTOR(11, 27, 0, 2) rec[-435] rec[-193] + DETECTOR(11, 28, 0, 3) rec[-318] rec[-62] + DETECTOR(11, 29, 0, 0) rec[-434] rec[-192] + DETECTOR(11, 30, 0, 4) rec[-317] rec[-61] + DETECTOR(11, 31, 0, 1) rec[-433] rec[-191] + DETECTOR(11, 32, 0, 5) rec[-60] + DETECTOR(11, 34, 0, 3) rec[-316] rec[-59] + DETECTOR(11, 35, 0, 0) rec[-431] rec[-430] rec[-190] + DETECTOR(11, 36, 0, 4) rec[-58] + DETECTOR(13, 1, 0, 1) rec[-189] + DETECTOR(13, 2, 0, 5) rec[-315] rec[-314] rec[-57] + DETECTOR(13, 3, 0, 2) rec[-429] rec[-188] + DETECTOR(13, 4, 0, 3) rec[-313] rec[-56] + DETECTOR(13, 5, 0, 0) rec[-428] rec[-187] + DETECTOR(13, 6, 0, 4) rec[-312] rec[-55] + DETECTOR(13, 7, 0, 1) rec[-427] rec[-186] + DETECTOR(13, 8, 0, 5) rec[-311] rec[-54] + DETECTOR(13, 9, 0, 2) rec[-426] rec[-185] + DETECTOR(13, 10, 0, 3) rec[-310] rec[-53] + DETECTOR(13, 11, 0, 0) rec[-425] rec[-184] + DETECTOR(13, 12, 0, 4) rec[-309] rec[-52] + DETECTOR(13, 13, 0, 1) rec[-424] rec[-183] + DETECTOR(13, 14, 0, 5) rec[-308] rec[-51] + DETECTOR(13, 15, 0, 2) rec[-423] rec[-182] + DETECTOR(13, 16, 0, 3) rec[-307] rec[-50] + DETECTOR(13, 17, 0, 0) rec[-422] rec[-181] + DETECTOR(13, 18, 0, 4) rec[-306] rec[-49] + DETECTOR(13, 19, 0, 1) rec[-421] rec[-180] + DETECTOR(13, 20, 0, 5) rec[-305] rec[-48] + DETECTOR(13, 21, 0, 2) rec[-420] rec[-179] + DETECTOR(13, 22, 0, 3) rec[-304] rec[-47] + DETECTOR(13, 23, 0, 0) rec[-419] rec[-178] + DETECTOR(13, 24, 0, 4) rec[-303] rec[-46] + DETECTOR(13, 25, 0, 1) rec[-418] rec[-177] + DETECTOR(13, 26, 0, 5) rec[-302] rec[-45] + DETECTOR(13, 27, 0, 2) rec[-417] rec[-176] + DETECTOR(13, 28, 0, 3) rec[-301] rec[-44] + DETECTOR(13, 29, 0, 0) rec[-416] rec[-175] + DETECTOR(13, 30, 0, 4) rec[-300] rec[-43] + DETECTOR(13, 31, 0, 1) rec[-415] rec[-174] + DETECTOR(13, 32, 0, 5) rec[-299] rec[-297] rec[-42] + DETECTOR(13, 33, 0, 2) rec[-414] rec[-173] + DETECTOR(13, 34, 0, 3) rec[-298] rec[-41] + DETECTOR(13, 35, 0, 0) rec[-413] rec[-172] + DETECTOR(14, 33, 0, 2) rec[-171] + DETECTOR(15, 1, 0, 1) rec[-170] + DETECTOR(15, 2, 0, 5) rec[-296] rec[-295] rec[-40] + DETECTOR(15, 3, 0, 2) rec[-412] rec[-169] + DETECTOR(15, 4, 0, 3) rec[-294] rec[-39] + DETECTOR(15, 5, 0, 0) rec[-411] rec[-168] + DETECTOR(15, 6, 0, 4) rec[-293] rec[-38] + DETECTOR(15, 7, 0, 1) rec[-410] rec[-167] + DETECTOR(15, 8, 0, 5) rec[-292] rec[-37] + DETECTOR(15, 9, 0, 2) rec[-409] rec[-166] + DETECTOR(15, 10, 0, 3) rec[-291] rec[-36] + DETECTOR(15, 11, 0, 0) rec[-408] rec[-165] + DETECTOR(15, 12, 0, 4) rec[-290] rec[-35] + DETECTOR(15, 13, 0, 1) rec[-407] rec[-164] + DETECTOR(15, 14, 0, 5) rec[-289] rec[-34] + DETECTOR(15, 15, 0, 2) rec[-406] rec[-163] + DETECTOR(15, 16, 0, 3) rec[-288] rec[-33] + DETECTOR(15, 17, 0, 0) rec[-405] rec[-162] + DETECTOR(15, 18, 0, 4) rec[-287] rec[-32] + DETECTOR(15, 19, 0, 1) rec[-404] rec[-161] + DETECTOR(15, 20, 0, 5) rec[-286] rec[-31] + DETECTOR(15, 21, 0, 2) rec[-403] rec[-160] + DETECTOR(15, 22, 0, 3) rec[-285] rec[-30] + DETECTOR(15, 23, 0, 0) rec[-402] rec[-159] + DETECTOR(15, 24, 0, 4) rec[-284] rec[-29] + DETECTOR(15, 25, 0, 1) rec[-401] rec[-158] + DETECTOR(15, 26, 0, 5) rec[-283] rec[-281] rec[-28] + DETECTOR(15, 27, 0, 2) rec[-400] rec[-157] + DETECTOR(15, 28, 0, 3) rec[-282] rec[-27] + DETECTOR(15, 29, 0, 0) rec[-399] rec[-156] + DETECTOR(16, 27, 0, 2) rec[-155] + DETECTOR(17, 1, 0, 1) rec[-154] + DETECTOR(17, 2, 0, 5) rec[-280] rec[-279] rec[-26] + DETECTOR(17, 3, 0, 2) rec[-398] rec[-153] + DETECTOR(17, 4, 0, 3) rec[-278] rec[-25] + DETECTOR(17, 5, 0, 0) rec[-397] rec[-152] + DETECTOR(17, 6, 0, 4) rec[-277] rec[-24] + DETECTOR(17, 7, 0, 1) rec[-396] rec[-151] + DETECTOR(17, 8, 0, 5) rec[-276] rec[-23] + DETECTOR(17, 9, 0, 2) rec[-395] rec[-150] + DETECTOR(17, 10, 0, 3) rec[-275] rec[-22] + DETECTOR(17, 11, 0, 0) rec[-394] rec[-149] + DETECTOR(17, 12, 0, 4) rec[-274] rec[-21] + DETECTOR(17, 13, 0, 1) rec[-393] rec[-148] + DETECTOR(17, 14, 0, 5) rec[-273] rec[-20] + DETECTOR(17, 15, 0, 2) rec[-392] rec[-147] + DETECTOR(17, 16, 0, 3) rec[-272] rec[-19] + DETECTOR(17, 17, 0, 0) rec[-391] rec[-146] + DETECTOR(17, 18, 0, 4) rec[-271] rec[-18] + DETECTOR(17, 19, 0, 1) rec[-390] rec[-145] + DETECTOR(17, 20, 0, 5) rec[-270] rec[-268] rec[-17] + DETECTOR(17, 21, 0, 2) rec[-389] rec[-144] + DETECTOR(17, 22, 0, 3) rec[-269] rec[-16] + DETECTOR(17, 23, 0, 0) rec[-388] rec[-143] + DETECTOR(18, 21, 0, 2) rec[-142] + DETECTOR(19, 1, 0, 1) rec[-141] + DETECTOR(19, 2, 0, 5) rec[-267] rec[-266] rec[-15] + DETECTOR(19, 3, 0, 2) rec[-387] rec[-140] + DETECTOR(19, 4, 0, 3) rec[-265] rec[-14] + DETECTOR(19, 5, 0, 0) rec[-386] rec[-139] + DETECTOR(19, 6, 0, 4) rec[-264] rec[-13] + DETECTOR(19, 7, 0, 1) rec[-385] rec[-138] + DETECTOR(19, 8, 0, 5) rec[-263] rec[-12] + DETECTOR(19, 9, 0, 2) rec[-384] rec[-137] + DETECTOR(19, 10, 0, 3) rec[-262] rec[-11] + DETECTOR(19, 11, 0, 0) rec[-383] rec[-136] + DETECTOR(19, 12, 0, 4) rec[-261] rec[-10] + DETECTOR(19, 13, 0, 1) rec[-382] rec[-135] + DETECTOR(19, 14, 0, 5) rec[-260] rec[-258] rec[-9] + DETECTOR(19, 15, 0, 2) rec[-381] rec[-134] + DETECTOR(19, 16, 0, 3) rec[-259] rec[-8] + DETECTOR(19, 17, 0, 0) rec[-380] rec[-133] + DETECTOR(20, 15, 0, 2) rec[-132] + DETECTOR(21, 1, 0, 1) rec[-131] + DETECTOR(21, 2, 0, 5) rec[-257] rec[-256] rec[-7] + DETECTOR(21, 3, 0, 2) rec[-379] rec[-130] + DETECTOR(21, 4, 0, 3) rec[-255] rec[-6] + DETECTOR(21, 5, 0, 0) rec[-378] rec[-129] + DETECTOR(21, 6, 0, 4) rec[-254] rec[-5] + DETECTOR(21, 7, 0, 1) rec[-377] rec[-128] + DETECTOR(21, 8, 0, 5) rec[-253] rec[-251] rec[-4] + DETECTOR(21, 9, 0, 2) rec[-376] rec[-127] + DETECTOR(21, 10, 0, 3) rec[-252] rec[-3] + DETECTOR(21, 11, 0, 0) rec[-375] rec[-126] + DETECTOR(22, 9, 0, 2) rec[-125] + DETECTOR(23, 1, 0, 1) rec[-124] + DETECTOR(23, 2, 0, 5) rec[-250] rec[-249] rec[-247] rec[-2] + DETECTOR(23, 3, 0, 2) rec[-374] rec[-123] + DETECTOR(23, 4, 0, 3) rec[-248] rec[-1] + DETECTOR(23, 5, 0, 0) rec[-373] rec[-122] + DETECTOR(24, 3, 0, 2) rec[-121] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 + DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 + TICK + CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 51 50 53 52 55 54 59 58 61 60 63 62 65 64 67 66 69 68 71 70 73 72 75 74 78 77 80 79 82 81 84 83 86 85 88 87 90 89 92 91 94 93 96 95 98 97 102 101 104 103 106 105 108 107 110 109 112 111 114 113 116 115 118 117 120 119 122 121 124 123 127 126 129 128 131 130 133 132 135 134 137 136 139 138 141 140 143 142 145 144 147 146 149 148 151 150 153 152 157 156 159 158 161 160 163 162 165 164 167 166 169 168 171 170 173 172 175 174 177 176 179 178 181 180 183 182 185 184 188 187 190 189 192 191 194 193 196 195 198 197 200 199 202 201 204 203 206 205 208 207 210 209 212 211 214 213 216 215 218 217 220 219 224 223 226 225 228 227 230 229 232 231 234 233 236 235 238 237 240 239 242 241 244 243 246 245 248 247 250 249 252 251 254 253 256 255 258 257 261 260 263 262 265 264 267 266 269 268 271 270 273 272 275 274 277 276 279 278 281 280 283 282 285 284 287 286 289 288 291 290 293 292 296 295 298 297 300 299 302 301 304 303 306 305 308 307 310 309 312 311 314 313 316 315 318 317 320 319 322 321 324 323 326 325 330 329 332 331 334 333 336 335 338 337 340 339 342 341 344 343 346 345 348 347 350 349 352 351 354 353 356 355 359 358 361 360 363 362 365 364 367 366 369 368 371 370 373 372 375 374 377 376 379 378 381 380 383 382 387 386 389 388 391 390 393 392 395 394 397 396 399 398 401 400 403 402 405 404 407 406 410 409 412 411 414 413 416 415 418 417 420 419 422 421 424 423 426 425 428 427 432 431 434 433 436 435 438 437 440 439 442 441 444 443 446 445 449 448 451 450 453 452 455 454 457 456 459 458 461 460 465 464 467 466 469 468 471 470 473 472 476 475 478 477 480 479 482 481 486 485 488 487 491 490 + DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 51 50 53 52 55 54 59 58 61 60 63 62 65 64 67 66 69 68 71 70 73 72 75 74 78 77 80 79 82 81 84 83 86 85 88 87 90 89 92 91 94 93 96 95 98 97 102 101 104 103 106 105 108 107 110 109 112 111 114 113 116 115 118 117 120 119 122 121 124 123 127 126 129 128 131 130 133 132 135 134 137 136 139 138 141 140 143 142 145 144 147 146 149 148 151 150 153 152 157 156 159 158 161 160 163 162 165 164 167 166 169 168 171 170 173 172 175 174 177 176 179 178 181 180 183 182 185 184 188 187 190 189 192 191 194 193 196 195 198 197 200 199 202 201 204 203 206 205 208 207 210 209 212 211 214 213 216 215 218 217 220 219 224 223 226 225 228 227 230 229 232 231 234 233 236 235 238 237 240 239 242 241 244 243 246 245 248 247 250 249 252 251 254 253 256 255 258 257 261 260 263 262 265 264 267 266 269 268 271 270 273 272 275 274 277 276 279 278 281 280 283 282 285 284 287 286 289 288 291 290 293 292 296 295 298 297 300 299 302 301 304 303 306 305 308 307 310 309 312 311 314 313 316 315 318 317 320 319 322 321 324 323 326 325 330 329 332 331 334 333 336 335 338 337 340 339 342 341 344 343 346 345 348 347 350 349 352 351 354 353 356 355 359 358 361 360 363 362 365 364 367 366 369 368 371 370 373 372 375 374 377 376 379 378 381 380 383 382 387 386 389 388 391 390 393 392 395 394 397 396 399 398 401 400 403 402 405 404 407 406 410 409 412 411 414 413 416 415 418 417 420 419 422 421 424 423 426 425 428 427 432 431 434 433 436 435 438 437 440 439 442 441 444 443 446 445 449 448 451 450 453 452 455 454 457 456 459 458 461 460 465 464 467 466 469 468 471 470 473 472 476 475 478 477 480 479 482 481 486 485 488 487 491 490 + DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 + TICK + CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 50 49 52 51 54 53 56 55 58 57 60 59 62 61 64 63 66 65 68 67 70 69 72 71 74 73 77 76 79 78 81 80 83 82 85 84 87 86 89 88 91 90 93 92 95 94 97 96 99 98 101 100 103 102 105 104 107 106 109 108 111 110 113 112 115 114 117 116 119 118 121 120 123 122 126 125 128 127 130 129 132 131 134 133 136 135 138 137 140 139 142 141 144 143 146 145 148 147 150 149 152 151 154 153 156 155 158 157 160 159 162 161 164 163 166 165 168 167 170 169 172 171 174 173 176 175 178 177 180 179 182 181 184 183 187 186 189 188 191 190 193 192 195 194 197 196 199 198 201 200 203 202 205 204 207 206 209 208 211 210 213 212 215 214 217 216 219 218 221 220 223 222 225 224 227 226 229 228 231 230 233 232 235 234 237 236 239 238 241 240 243 242 245 244 247 246 249 248 251 250 253 252 255 254 257 256 260 259 262 261 264 263 266 265 268 267 270 269 272 271 274 273 276 275 278 277 280 279 282 281 284 283 286 285 288 287 290 289 292 291 295 294 297 296 299 298 301 300 303 302 305 304 307 306 309 308 311 310 313 312 315 314 317 316 319 318 321 320 323 322 325 324 327 326 329 328 331 330 333 332 335 334 337 336 339 338 341 340 343 342 345 344 347 346 349 348 351 350 353 352 355 354 358 357 360 359 362 361 364 363 366 365 368 367 370 369 372 371 374 373 376 375 378 377 380 379 382 381 384 383 386 385 388 387 390 389 392 391 394 393 396 395 398 397 400 399 402 401 404 403 406 405 409 408 411 410 413 412 415 414 417 416 419 418 421 420 423 422 425 424 427 426 429 428 431 430 433 432 435 434 437 436 439 438 441 440 443 442 445 444 448 447 450 449 452 451 454 453 456 455 458 457 460 459 462 461 464 463 466 465 468 467 470 469 472 471 475 474 477 476 479 478 481 480 483 482 485 484 487 486 490 489 492 491 + DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 50 49 52 51 54 53 56 55 58 57 60 59 62 61 64 63 66 65 68 67 70 69 72 71 74 73 77 76 79 78 81 80 83 82 85 84 87 86 89 88 91 90 93 92 95 94 97 96 99 98 101 100 103 102 105 104 107 106 109 108 111 110 113 112 115 114 117 116 119 118 121 120 123 122 126 125 128 127 130 129 132 131 134 133 136 135 138 137 140 139 142 141 144 143 146 145 148 147 150 149 152 151 154 153 156 155 158 157 160 159 162 161 164 163 166 165 168 167 170 169 172 171 174 173 176 175 178 177 180 179 182 181 184 183 187 186 189 188 191 190 193 192 195 194 197 196 199 198 201 200 203 202 205 204 207 206 209 208 211 210 213 212 215 214 217 216 219 218 221 220 223 222 225 224 227 226 229 228 231 230 233 232 235 234 237 236 239 238 241 240 243 242 245 244 247 246 249 248 251 250 253 252 255 254 257 256 260 259 262 261 264 263 266 265 268 267 270 269 272 271 274 273 276 275 278 277 280 279 282 281 284 283 286 285 288 287 290 289 292 291 295 294 297 296 299 298 301 300 303 302 305 304 307 306 309 308 311 310 313 312 315 314 317 316 319 318 321 320 323 322 325 324 327 326 329 328 331 330 333 332 335 334 337 336 339 338 341 340 343 342 345 344 347 346 349 348 351 350 353 352 355 354 358 357 360 359 362 361 364 363 366 365 368 367 370 369 372 371 374 373 376 375 378 377 380 379 382 381 384 383 386 385 388 387 390 389 392 391 394 393 396 395 398 397 400 399 402 401 404 403 406 405 409 408 411 410 413 412 415 414 417 416 419 418 421 420 423 422 425 424 427 426 429 428 431 430 433 432 435 434 437 436 439 438 441 440 443 442 445 444 448 447 450 449 452 451 454 453 456 455 458 457 460 459 462 461 464 463 466 465 468 467 470 469 472 471 475 474 477 476 479 478 481 480 483 482 485 484 487 486 490 489 492 491 + DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 + TICK + CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 38 51 40 58 42 60 44 62 46 64 48 66 50 68 52 70 54 72 56 74 57 76 59 78 61 80 63 82 65 84 67 86 69 88 71 90 73 92 75 94 77 101 79 103 81 105 83 107 85 109 87 111 89 113 91 115 93 117 95 119 97 121 99 123 100 125 102 127 104 129 106 131 108 133 110 135 112 137 114 139 116 141 118 143 120 145 122 147 124 149 126 156 128 158 130 160 132 162 134 164 136 166 138 168 140 170 142 172 144 174 146 176 148 178 150 180 152 182 154 184 155 186 157 188 159 190 161 192 163 194 165 196 167 198 169 200 171 202 173 204 175 206 177 208 179 210 181 212 183 214 185 216 187 223 189 225 191 227 193 229 195 231 197 233 199 235 201 237 203 239 205 241 207 243 209 245 211 247 213 249 215 251 217 253 219 255 221 257 222 259 224 261 226 263 228 265 230 267 232 269 234 271 236 273 238 275 240 277 242 279 244 281 246 283 248 285 250 287 252 289 254 291 256 293 260 295 262 297 264 299 266 301 268 303 270 305 272 307 274 309 276 311 278 313 280 315 282 317 284 319 286 321 288 323 290 325 292 327 294 328 296 330 298 332 300 334 302 336 304 338 306 340 308 342 310 344 312 346 314 348 316 350 318 352 320 354 322 356 329 358 331 360 333 362 335 364 337 366 339 368 341 370 343 372 345 374 347 376 349 378 351 380 353 382 355 384 357 385 359 387 361 389 363 391 365 393 367 395 369 397 371 399 373 401 375 403 377 405 379 407 386 409 388 411 390 413 392 415 394 417 396 419 398 421 400 423 402 425 404 427 406 429 408 430 410 432 412 434 414 436 416 438 418 440 420 442 422 444 424 446 431 448 433 450 435 452 437 454 439 456 441 458 443 460 445 462 447 463 449 465 451 467 453 469 455 471 457 473 464 475 466 477 468 479 470 481 472 483 474 484 476 486 478 488 485 490 487 492 + DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 38 51 40 58 42 60 44 62 46 64 48 66 50 68 52 70 54 72 56 74 57 76 59 78 61 80 63 82 65 84 67 86 69 88 71 90 73 92 75 94 77 101 79 103 81 105 83 107 85 109 87 111 89 113 91 115 93 117 95 119 97 121 99 123 100 125 102 127 104 129 106 131 108 133 110 135 112 137 114 139 116 141 118 143 120 145 122 147 124 149 126 156 128 158 130 160 132 162 134 164 136 166 138 168 140 170 142 172 144 174 146 176 148 178 150 180 152 182 154 184 155 186 157 188 159 190 161 192 163 194 165 196 167 198 169 200 171 202 173 204 175 206 177 208 179 210 181 212 183 214 185 216 187 223 189 225 191 227 193 229 195 231 197 233 199 235 201 237 203 239 205 241 207 243 209 245 211 247 213 249 215 251 217 253 219 255 221 257 222 259 224 261 226 263 228 265 230 267 232 269 234 271 236 273 238 275 240 277 242 279 244 281 246 283 248 285 250 287 252 289 254 291 256 293 260 295 262 297 264 299 266 301 268 303 270 305 272 307 274 309 276 311 278 313 280 315 282 317 284 319 286 321 288 323 290 325 292 327 294 328 296 330 298 332 300 334 302 336 304 338 306 340 308 342 310 344 312 346 314 348 316 350 318 352 320 354 322 356 329 358 331 360 333 362 335 364 337 366 339 368 341 370 343 372 345 374 347 376 349 378 351 380 353 382 355 384 357 385 359 387 361 389 363 391 365 393 367 395 369 397 371 399 373 401 375 403 377 405 379 407 386 409 388 411 390 413 392 415 394 417 396 419 398 421 400 423 402 425 404 427 406 429 408 430 410 432 412 434 414 436 416 438 418 440 420 442 422 444 424 446 431 448 433 450 435 452 437 454 439 456 441 458 443 460 445 462 447 463 449 465 451 467 453 469 455 471 457 473 464 475 466 477 468 479 470 481 472 483 474 484 476 486 478 488 485 490 487 492 + DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 + TICK + MX(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 + M(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 + TICK + RX 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 + R 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 + OBSERVABLE_INCLUDE(0) rec[-184] rec[-202] rec[-217] rec[-229] rec[-238] rec[-244] + X_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 + Z_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 + DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 + TICK + CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 38 51 40 58 42 60 44 62 46 64 48 66 50 68 52 70 54 72 56 74 57 76 59 78 61 80 63 82 65 84 67 86 69 88 71 90 73 92 75 94 77 101 79 103 81 105 83 107 85 109 87 111 89 113 91 115 93 117 95 119 97 121 99 123 100 125 102 127 104 129 106 131 108 133 110 135 112 137 114 139 116 141 118 143 120 145 122 147 124 149 126 156 128 158 130 160 132 162 134 164 136 166 138 168 140 170 142 172 144 174 146 176 148 178 150 180 152 182 154 184 155 186 157 188 159 190 161 192 163 194 165 196 167 198 169 200 171 202 173 204 175 206 177 208 179 210 181 212 183 214 185 216 187 223 189 225 191 227 193 229 195 231 197 233 199 235 201 237 203 239 205 241 207 243 209 245 211 247 213 249 215 251 217 253 219 255 221 257 222 259 224 261 226 263 228 265 230 267 232 269 234 271 236 273 238 275 240 277 242 279 244 281 246 283 248 285 250 287 252 289 254 291 256 293 260 295 262 297 264 299 266 301 268 303 270 305 272 307 274 309 276 311 278 313 280 315 282 317 284 319 286 321 288 323 290 325 292 327 294 328 296 330 298 332 300 334 302 336 304 338 306 340 308 342 310 344 312 346 314 348 316 350 318 352 320 354 322 356 329 358 331 360 333 362 335 364 337 366 339 368 341 370 343 372 345 374 347 376 349 378 351 380 353 382 355 384 357 385 359 387 361 389 363 391 365 393 367 395 369 397 371 399 373 401 375 403 377 405 379 407 386 409 388 411 390 413 392 415 394 417 396 419 398 421 400 423 402 425 404 427 406 429 408 430 410 432 412 434 414 436 416 438 418 440 420 442 422 444 424 446 431 448 433 450 435 452 437 454 439 456 441 458 443 460 445 462 447 463 449 465 451 467 453 469 455 471 457 473 464 475 466 477 468 479 470 481 472 483 474 484 476 486 478 488 485 490 487 492 + DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 38 51 40 58 42 60 44 62 46 64 48 66 50 68 52 70 54 72 56 74 57 76 59 78 61 80 63 82 65 84 67 86 69 88 71 90 73 92 75 94 77 101 79 103 81 105 83 107 85 109 87 111 89 113 91 115 93 117 95 119 97 121 99 123 100 125 102 127 104 129 106 131 108 133 110 135 112 137 114 139 116 141 118 143 120 145 122 147 124 149 126 156 128 158 130 160 132 162 134 164 136 166 138 168 140 170 142 172 144 174 146 176 148 178 150 180 152 182 154 184 155 186 157 188 159 190 161 192 163 194 165 196 167 198 169 200 171 202 173 204 175 206 177 208 179 210 181 212 183 214 185 216 187 223 189 225 191 227 193 229 195 231 197 233 199 235 201 237 203 239 205 241 207 243 209 245 211 247 213 249 215 251 217 253 219 255 221 257 222 259 224 261 226 263 228 265 230 267 232 269 234 271 236 273 238 275 240 277 242 279 244 281 246 283 248 285 250 287 252 289 254 291 256 293 260 295 262 297 264 299 266 301 268 303 270 305 272 307 274 309 276 311 278 313 280 315 282 317 284 319 286 321 288 323 290 325 292 327 294 328 296 330 298 332 300 334 302 336 304 338 306 340 308 342 310 344 312 346 314 348 316 350 318 352 320 354 322 356 329 358 331 360 333 362 335 364 337 366 339 368 341 370 343 372 345 374 347 376 349 378 351 380 353 382 355 384 357 385 359 387 361 389 363 391 365 393 367 395 369 397 371 399 373 401 375 403 377 405 379 407 386 409 388 411 390 413 392 415 394 417 396 419 398 421 400 423 402 425 404 427 406 429 408 430 410 432 412 434 414 436 416 438 418 440 420 442 422 444 424 446 431 448 433 450 435 452 437 454 439 456 441 458 443 460 445 462 447 463 449 465 451 467 453 469 455 471 457 473 464 475 466 477 468 479 470 481 472 483 474 484 476 486 478 488 485 490 487 492 + DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 + TICK + CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 50 49 52 51 54 53 56 55 58 57 60 59 62 61 64 63 66 65 68 67 70 69 72 71 74 73 77 76 79 78 81 80 83 82 85 84 87 86 89 88 91 90 93 92 95 94 97 96 99 98 101 100 103 102 105 104 107 106 109 108 111 110 113 112 115 114 117 116 119 118 121 120 123 122 126 125 128 127 130 129 132 131 134 133 136 135 138 137 140 139 142 141 144 143 146 145 148 147 150 149 152 151 154 153 156 155 158 157 160 159 162 161 164 163 166 165 168 167 170 169 172 171 174 173 176 175 178 177 180 179 182 181 184 183 187 186 189 188 191 190 193 192 195 194 197 196 199 198 201 200 203 202 205 204 207 206 209 208 211 210 213 212 215 214 217 216 219 218 221 220 223 222 225 224 227 226 229 228 231 230 233 232 235 234 237 236 239 238 241 240 243 242 245 244 247 246 249 248 251 250 253 252 255 254 257 256 260 259 262 261 264 263 266 265 268 267 270 269 272 271 274 273 276 275 278 277 280 279 282 281 284 283 286 285 288 287 290 289 292 291 295 294 297 296 299 298 301 300 303 302 305 304 307 306 309 308 311 310 313 312 315 314 317 316 319 318 321 320 323 322 325 324 327 326 329 328 331 330 333 332 335 334 337 336 339 338 341 340 343 342 345 344 347 346 349 348 351 350 353 352 355 354 358 357 360 359 362 361 364 363 366 365 368 367 370 369 372 371 374 373 376 375 378 377 380 379 382 381 384 383 386 385 388 387 390 389 392 391 394 393 396 395 398 397 400 399 402 401 404 403 406 405 409 408 411 410 413 412 415 414 417 416 419 418 421 420 423 422 425 424 427 426 429 428 431 430 433 432 435 434 437 436 439 438 441 440 443 442 445 444 448 447 450 449 452 451 454 453 456 455 458 457 460 459 462 461 464 463 466 465 468 467 470 469 472 471 475 474 477 476 479 478 481 480 483 482 485 484 487 486 490 489 492 491 + DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 50 49 52 51 54 53 56 55 58 57 60 59 62 61 64 63 66 65 68 67 70 69 72 71 74 73 77 76 79 78 81 80 83 82 85 84 87 86 89 88 91 90 93 92 95 94 97 96 99 98 101 100 103 102 105 104 107 106 109 108 111 110 113 112 115 114 117 116 119 118 121 120 123 122 126 125 128 127 130 129 132 131 134 133 136 135 138 137 140 139 142 141 144 143 146 145 148 147 150 149 152 151 154 153 156 155 158 157 160 159 162 161 164 163 166 165 168 167 170 169 172 171 174 173 176 175 178 177 180 179 182 181 184 183 187 186 189 188 191 190 193 192 195 194 197 196 199 198 201 200 203 202 205 204 207 206 209 208 211 210 213 212 215 214 217 216 219 218 221 220 223 222 225 224 227 226 229 228 231 230 233 232 235 234 237 236 239 238 241 240 243 242 245 244 247 246 249 248 251 250 253 252 255 254 257 256 260 259 262 261 264 263 266 265 268 267 270 269 272 271 274 273 276 275 278 277 280 279 282 281 284 283 286 285 288 287 290 289 292 291 295 294 297 296 299 298 301 300 303 302 305 304 307 306 309 308 311 310 313 312 315 314 317 316 319 318 321 320 323 322 325 324 327 326 329 328 331 330 333 332 335 334 337 336 339 338 341 340 343 342 345 344 347 346 349 348 351 350 353 352 355 354 358 357 360 359 362 361 364 363 366 365 368 367 370 369 372 371 374 373 376 375 378 377 380 379 382 381 384 383 386 385 388 387 390 389 392 391 394 393 396 395 398 397 400 399 402 401 404 403 406 405 409 408 411 410 413 412 415 414 417 416 419 418 421 420 423 422 425 424 427 426 429 428 431 430 433 432 435 434 437 436 439 438 441 440 443 442 445 444 448 447 450 449 452 451 454 453 456 455 458 457 460 459 462 461 464 463 466 465 468 467 470 469 472 471 475 474 477 476 479 478 481 480 483 482 485 484 487 486 490 489 492 491 + DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 + TICK + CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 51 50 53 52 55 54 59 58 61 60 63 62 65 64 67 66 69 68 71 70 73 72 75 74 78 77 80 79 82 81 84 83 86 85 88 87 90 89 92 91 94 93 96 95 98 97 102 101 104 103 106 105 108 107 110 109 112 111 114 113 116 115 118 117 120 119 122 121 124 123 127 126 129 128 131 130 133 132 135 134 137 136 139 138 141 140 143 142 145 144 147 146 149 148 151 150 153 152 157 156 159 158 161 160 163 162 165 164 167 166 169 168 171 170 173 172 175 174 177 176 179 178 181 180 183 182 185 184 188 187 190 189 192 191 194 193 196 195 198 197 200 199 202 201 204 203 206 205 208 207 210 209 212 211 214 213 216 215 218 217 220 219 224 223 226 225 228 227 230 229 232 231 234 233 236 235 238 237 240 239 242 241 244 243 246 245 248 247 250 249 252 251 254 253 256 255 258 257 261 260 263 262 265 264 267 266 269 268 271 270 273 272 275 274 277 276 279 278 281 280 283 282 285 284 287 286 289 288 291 290 293 292 296 295 298 297 300 299 302 301 304 303 306 305 308 307 310 309 312 311 314 313 316 315 318 317 320 319 322 321 324 323 326 325 330 329 332 331 334 333 336 335 338 337 340 339 342 341 344 343 346 345 348 347 350 349 352 351 354 353 356 355 359 358 361 360 363 362 365 364 367 366 369 368 371 370 373 372 375 374 377 376 379 378 381 380 383 382 387 386 389 388 391 390 393 392 395 394 397 396 399 398 401 400 403 402 405 404 407 406 410 409 412 411 414 413 416 415 418 417 420 419 422 421 424 423 426 425 428 427 432 431 434 433 436 435 438 437 440 439 442 441 444 443 446 445 449 448 451 450 453 452 455 454 457 456 459 458 461 460 465 464 467 466 469 468 471 470 473 472 476 475 478 477 480 479 482 481 486 485 488 487 491 490 + DETECTOR(1, 1, 0, 4) rec[-126] + DETECTOR(1, 2, 0, 2) rec[-492] rec[-246] + DETECTOR(1, 4, 0, 0) rec[-491] rec[-245] + DETECTOR(1, 5, 0, 3) rec[-365] rec[-364] rec[-125] + DETECTOR(1, 6, 0, 1) rec[-244] + DETECTOR(3, 1, 0, 4) rec[-124] + DETECTOR(3, 2, 0, 2) rec[-490] rec[-489] rec[-243] + DETECTOR(3, 3, 0, 5) rec[-363] rec[-123] + DETECTOR(3, 4, 0, 0) rec[-488] rec[-242] + DETECTOR(3, 5, 0, 3) rec[-362] rec[-122] + DETECTOR(3, 6, 0, 1) rec[-487] rec[-241] + DETECTOR(3, 7, 0, 4) rec[-361] rec[-121] + DETECTOR(3, 8, 0, 2) rec[-240] + DETECTOR(3, 10, 0, 0) rec[-486] rec[-239] + DETECTOR(3, 11, 0, 3) rec[-359] rec[-358] rec[-120] + DETECTOR(3, 12, 0, 1) rec[-238] + DETECTOR(5, 1, 0, 4) rec[-119] + DETECTOR(5, 2, 0, 2) rec[-485] rec[-484] rec[-237] + DETECTOR(5, 3, 0, 5) rec[-357] rec[-118] + DETECTOR(5, 4, 0, 0) rec[-483] rec[-236] + DETECTOR(5, 5, 0, 3) rec[-356] rec[-117] + DETECTOR(5, 6, 0, 1) rec[-482] rec[-235] + DETECTOR(5, 7, 0, 4) rec[-355] rec[-116] + DETECTOR(5, 8, 0, 2) rec[-481] rec[-234] + DETECTOR(5, 9, 0, 5) rec[-354] rec[-115] + DETECTOR(5, 10, 0, 0) rec[-480] rec[-233] + DETECTOR(5, 11, 0, 3) rec[-353] rec[-114] + DETECTOR(5, 12, 0, 1) rec[-479] rec[-232] + DETECTOR(5, 13, 0, 4) rec[-352] rec[-113] + DETECTOR(5, 14, 0, 2) rec[-231] + DETECTOR(5, 16, 0, 0) rec[-478] rec[-230] + DETECTOR(5, 17, 0, 3) rec[-350] rec[-349] rec[-112] + DETECTOR(5, 18, 0, 1) rec[-229] + DETECTOR(7, 1, 0, 4) rec[-111] + DETECTOR(7, 2, 0, 2) rec[-477] rec[-476] rec[-228] + DETECTOR(7, 3, 0, 5) rec[-348] rec[-110] + DETECTOR(7, 4, 0, 0) rec[-475] rec[-227] + DETECTOR(7, 5, 0, 3) rec[-347] rec[-109] + DETECTOR(7, 6, 0, 1) rec[-474] rec[-226] + DETECTOR(7, 7, 0, 4) rec[-346] rec[-108] + DETECTOR(7, 8, 0, 2) rec[-473] rec[-225] + DETECTOR(7, 9, 0, 5) rec[-345] rec[-107] + DETECTOR(7, 10, 0, 0) rec[-472] rec[-224] + DETECTOR(7, 11, 0, 3) rec[-344] rec[-106] + DETECTOR(7, 12, 0, 1) rec[-471] rec[-223] + DETECTOR(7, 13, 0, 4) rec[-343] rec[-105] + DETECTOR(7, 14, 0, 2) rec[-470] rec[-222] + DETECTOR(7, 15, 0, 5) rec[-342] rec[-104] + DETECTOR(7, 16, 0, 0) rec[-469] rec[-221] + DETECTOR(7, 17, 0, 3) rec[-341] rec[-103] + DETECTOR(7, 18, 0, 1) rec[-468] rec[-220] + DETECTOR(7, 19, 0, 4) rec[-340] rec[-102] + DETECTOR(7, 20, 0, 2) rec[-219] + DETECTOR(7, 22, 0, 0) rec[-467] rec[-218] + DETECTOR(7, 23, 0, 3) rec[-338] rec[-337] rec[-101] + DETECTOR(7, 24, 0, 1) rec[-217] + DETECTOR(9, 1, 0, 4) rec[-100] + DETECTOR(9, 2, 0, 2) rec[-466] rec[-465] rec[-216] + DETECTOR(9, 3, 0, 5) rec[-336] rec[-99] + DETECTOR(9, 4, 0, 0) rec[-464] rec[-215] + DETECTOR(9, 5, 0, 3) rec[-335] rec[-98] + DETECTOR(9, 6, 0, 1) rec[-463] rec[-214] + DETECTOR(9, 7, 0, 4) rec[-334] rec[-97] + DETECTOR(9, 8, 0, 2) rec[-462] rec[-213] + DETECTOR(9, 9, 0, 5) rec[-333] rec[-96] + DETECTOR(9, 10, 0, 0) rec[-461] rec[-212] + DETECTOR(9, 11, 0, 3) rec[-332] rec[-95] + DETECTOR(9, 12, 0, 1) rec[-460] rec[-211] + DETECTOR(9, 13, 0, 4) rec[-331] rec[-94] + DETECTOR(9, 14, 0, 2) rec[-459] rec[-210] + DETECTOR(9, 15, 0, 5) rec[-330] rec[-93] + DETECTOR(9, 16, 0, 0) rec[-458] rec[-209] + DETECTOR(9, 17, 0, 3) rec[-329] rec[-92] + DETECTOR(9, 18, 0, 1) rec[-457] rec[-208] + DETECTOR(9, 19, 0, 4) rec[-328] rec[-91] + DETECTOR(9, 20, 0, 2) rec[-456] rec[-207] + DETECTOR(9, 21, 0, 5) rec[-327] rec[-90] + DETECTOR(9, 22, 0, 0) rec[-455] rec[-206] + DETECTOR(9, 23, 0, 3) rec[-326] rec[-89] + DETECTOR(9, 24, 0, 1) rec[-454] rec[-205] + DETECTOR(9, 25, 0, 4) rec[-325] rec[-88] + DETECTOR(9, 26, 0, 2) rec[-204] + DETECTOR(9, 28, 0, 0) rec[-453] rec[-203] + DETECTOR(9, 29, 0, 3) rec[-323] rec[-322] rec[-87] + DETECTOR(9, 30, 0, 1) rec[-202] + DETECTOR(11, 1, 0, 4) rec[-86] + DETECTOR(11, 2, 0, 2) rec[-452] rec[-451] rec[-201] + DETECTOR(11, 3, 0, 5) rec[-321] rec[-85] + DETECTOR(11, 4, 0, 0) rec[-450] rec[-200] + DETECTOR(11, 5, 0, 3) rec[-320] rec[-84] + DETECTOR(11, 6, 0, 1) rec[-449] rec[-199] + DETECTOR(11, 7, 0, 4) rec[-319] rec[-83] + DETECTOR(11, 8, 0, 2) rec[-448] rec[-198] + DETECTOR(11, 9, 0, 5) rec[-318] rec[-82] + DETECTOR(11, 10, 0, 0) rec[-447] rec[-197] + DETECTOR(11, 11, 0, 3) rec[-317] rec[-81] + DETECTOR(11, 12, 0, 1) rec[-446] rec[-196] + DETECTOR(11, 13, 0, 4) rec[-316] rec[-80] + DETECTOR(11, 14, 0, 2) rec[-445] rec[-195] + DETECTOR(11, 15, 0, 5) rec[-315] rec[-79] + DETECTOR(11, 16, 0, 0) rec[-444] rec[-194] + DETECTOR(11, 17, 0, 3) rec[-314] rec[-78] + DETECTOR(11, 18, 0, 1) rec[-443] rec[-193] + DETECTOR(11, 19, 0, 4) rec[-313] rec[-77] + DETECTOR(11, 20, 0, 2) rec[-442] rec[-192] + DETECTOR(11, 21, 0, 5) rec[-312] rec[-76] + DETECTOR(11, 22, 0, 0) rec[-441] rec[-191] + DETECTOR(11, 23, 0, 3) rec[-311] rec[-75] + DETECTOR(11, 24, 0, 1) rec[-440] rec[-190] + DETECTOR(11, 25, 0, 4) rec[-310] rec[-74] + DETECTOR(11, 26, 0, 2) rec[-439] rec[-189] + DETECTOR(11, 27, 0, 5) rec[-309] rec[-73] + DETECTOR(11, 28, 0, 0) rec[-438] rec[-188] + DETECTOR(11, 29, 0, 3) rec[-308] rec[-72] + DETECTOR(11, 30, 0, 1) rec[-437] rec[-187] + DETECTOR(11, 31, 0, 4) rec[-307] rec[-71] + DETECTOR(11, 32, 0, 2) rec[-186] + DETECTOR(11, 34, 0, 0) rec[-436] rec[-185] + DETECTOR(11, 35, 0, 3) rec[-305] rec[-304] rec[-70] + DETECTOR(11, 36, 0, 1) rec[-184] + DETECTOR(13, 1, 0, 4) rec[-69] + DETECTOR(13, 2, 0, 2) rec[-435] rec[-434] rec[-183] + DETECTOR(13, 3, 0, 5) rec[-303] rec[-68] + DETECTOR(13, 4, 0, 0) rec[-433] rec[-182] + DETECTOR(13, 5, 0, 3) rec[-302] rec[-67] + DETECTOR(13, 6, 0, 1) rec[-432] rec[-181] + DETECTOR(13, 7, 0, 4) rec[-301] rec[-66] + DETECTOR(13, 8, 0, 2) rec[-431] rec[-180] + DETECTOR(13, 9, 0, 5) rec[-300] rec[-65] + DETECTOR(13, 10, 0, 0) rec[-430] rec[-179] + DETECTOR(13, 11, 0, 3) rec[-299] rec[-64] + DETECTOR(13, 12, 0, 1) rec[-429] rec[-178] + DETECTOR(13, 13, 0, 4) rec[-298] rec[-63] + DETECTOR(13, 14, 0, 2) rec[-428] rec[-177] + DETECTOR(13, 15, 0, 5) rec[-297] rec[-62] + DETECTOR(13, 16, 0, 0) rec[-427] rec[-176] + DETECTOR(13, 17, 0, 3) rec[-296] rec[-61] + DETECTOR(13, 18, 0, 1) rec[-426] rec[-175] + DETECTOR(13, 19, 0, 4) rec[-295] rec[-60] + DETECTOR(13, 20, 0, 2) rec[-425] rec[-174] + DETECTOR(13, 21, 0, 5) rec[-294] rec[-59] + DETECTOR(13, 22, 0, 0) rec[-424] rec[-173] + DETECTOR(13, 23, 0, 3) rec[-293] rec[-58] + DETECTOR(13, 24, 0, 1) rec[-423] rec[-172] + DETECTOR(13, 25, 0, 4) rec[-292] rec[-57] + DETECTOR(13, 26, 0, 2) rec[-422] rec[-171] + DETECTOR(13, 27, 0, 5) rec[-291] rec[-56] + DETECTOR(13, 28, 0, 0) rec[-421] rec[-170] + DETECTOR(13, 29, 0, 3) rec[-290] rec[-55] + DETECTOR(13, 30, 0, 1) rec[-420] rec[-169] + DETECTOR(13, 31, 0, 4) rec[-289] rec[-54] + DETECTOR(13, 32, 0, 2) rec[-419] rec[-417] rec[-168] + DETECTOR(13, 33, 0, 5) rec[-288] rec[-53] + DETECTOR(13, 34, 0, 0) rec[-418] rec[-167] + DETECTOR(13, 35, 0, 3) rec[-287] rec[-52] + DETECTOR(14, 33, 0, 5) rec[-51] + DETECTOR(15, 1, 0, 4) rec[-50] + DETECTOR(15, 2, 0, 2) rec[-416] rec[-415] rec[-166] + DETECTOR(15, 3, 0, 5) rec[-286] rec[-49] + DETECTOR(15, 4, 0, 0) rec[-414] rec[-165] + DETECTOR(15, 5, 0, 3) rec[-285] rec[-48] + DETECTOR(15, 6, 0, 1) rec[-413] rec[-164] + DETECTOR(15, 7, 0, 4) rec[-284] rec[-47] + DETECTOR(15, 8, 0, 2) rec[-412] rec[-163] + DETECTOR(15, 9, 0, 5) rec[-283] rec[-46] + DETECTOR(15, 10, 0, 0) rec[-411] rec[-162] + DETECTOR(15, 11, 0, 3) rec[-282] rec[-45] + DETECTOR(15, 12, 0, 1) rec[-410] rec[-161] + DETECTOR(15, 13, 0, 4) rec[-281] rec[-44] + DETECTOR(15, 14, 0, 2) rec[-409] rec[-160] + DETECTOR(15, 15, 0, 5) rec[-280] rec[-43] + DETECTOR(15, 16, 0, 0) rec[-408] rec[-159] + DETECTOR(15, 17, 0, 3) rec[-279] rec[-42] + DETECTOR(15, 18, 0, 1) rec[-407] rec[-158] + DETECTOR(15, 19, 0, 4) rec[-278] rec[-41] + DETECTOR(15, 20, 0, 2) rec[-406] rec[-157] + DETECTOR(15, 21, 0, 5) rec[-277] rec[-40] + DETECTOR(15, 22, 0, 0) rec[-405] rec[-156] + DETECTOR(15, 23, 0, 3) rec[-276] rec[-39] + DETECTOR(15, 24, 0, 1) rec[-404] rec[-155] + DETECTOR(15, 25, 0, 4) rec[-275] rec[-38] + DETECTOR(15, 26, 0, 2) rec[-403] rec[-401] rec[-154] + DETECTOR(15, 27, 0, 5) rec[-274] rec[-37] + DETECTOR(15, 28, 0, 0) rec[-402] rec[-153] + DETECTOR(15, 29, 0, 3) rec[-273] rec[-36] + DETECTOR(16, 27, 0, 5) rec[-35] + DETECTOR(17, 1, 0, 4) rec[-34] + DETECTOR(17, 2, 0, 2) rec[-400] rec[-399] rec[-152] + DETECTOR(17, 3, 0, 5) rec[-272] rec[-33] + DETECTOR(17, 4, 0, 0) rec[-398] rec[-151] + DETECTOR(17, 5, 0, 3) rec[-271] rec[-32] + DETECTOR(17, 6, 0, 1) rec[-397] rec[-150] + DETECTOR(17, 7, 0, 4) rec[-270] rec[-31] + DETECTOR(17, 8, 0, 2) rec[-396] rec[-149] + DETECTOR(17, 9, 0, 5) rec[-269] rec[-30] + DETECTOR(17, 10, 0, 0) rec[-395] rec[-148] + DETECTOR(17, 11, 0, 3) rec[-268] rec[-29] + DETECTOR(17, 12, 0, 1) rec[-394] rec[-147] + DETECTOR(17, 13, 0, 4) rec[-267] rec[-28] + DETECTOR(17, 14, 0, 2) rec[-393] rec[-146] + DETECTOR(17, 15, 0, 5) rec[-266] rec[-27] + DETECTOR(17, 16, 0, 0) rec[-392] rec[-145] + DETECTOR(17, 17, 0, 3) rec[-265] rec[-26] + DETECTOR(17, 18, 0, 1) rec[-391] rec[-144] + DETECTOR(17, 19, 0, 4) rec[-264] rec[-25] + DETECTOR(17, 20, 0, 2) rec[-390] rec[-388] rec[-143] + DETECTOR(17, 21, 0, 5) rec[-263] rec[-24] + DETECTOR(17, 22, 0, 0) rec[-389] rec[-142] + DETECTOR(17, 23, 0, 3) rec[-262] rec[-23] + DETECTOR(18, 21, 0, 5) rec[-22] + DETECTOR(19, 1, 0, 4) rec[-21] + DETECTOR(19, 2, 0, 2) rec[-387] rec[-386] rec[-141] + DETECTOR(19, 3, 0, 5) rec[-261] rec[-20] + DETECTOR(19, 4, 0, 0) rec[-385] rec[-140] + DETECTOR(19, 5, 0, 3) rec[-260] rec[-19] + DETECTOR(19, 6, 0, 1) rec[-384] rec[-139] + DETECTOR(19, 7, 0, 4) rec[-259] rec[-18] + DETECTOR(19, 8, 0, 2) rec[-383] rec[-138] + DETECTOR(19, 9, 0, 5) rec[-258] rec[-17] + DETECTOR(19, 10, 0, 0) rec[-382] rec[-137] + DETECTOR(19, 11, 0, 3) rec[-257] rec[-16] + DETECTOR(19, 12, 0, 1) rec[-381] rec[-136] + DETECTOR(19, 13, 0, 4) rec[-256] rec[-15] + DETECTOR(19, 14, 0, 2) rec[-380] rec[-378] rec[-135] + DETECTOR(19, 15, 0, 5) rec[-255] rec[-14] + DETECTOR(19, 16, 0, 0) rec[-379] rec[-134] + DETECTOR(19, 17, 0, 3) rec[-254] rec[-13] + DETECTOR(20, 15, 0, 5) rec[-12] + DETECTOR(21, 1, 0, 4) rec[-11] + DETECTOR(21, 2, 0, 2) rec[-377] rec[-376] rec[-133] + DETECTOR(21, 3, 0, 5) rec[-253] rec[-10] + DETECTOR(21, 4, 0, 0) rec[-375] rec[-132] + DETECTOR(21, 5, 0, 3) rec[-252] rec[-9] + DETECTOR(21, 6, 0, 1) rec[-374] rec[-131] + DETECTOR(21, 7, 0, 4) rec[-251] rec[-8] + DETECTOR(21, 8, 0, 2) rec[-373] rec[-371] rec[-130] + DETECTOR(21, 9, 0, 5) rec[-250] rec[-7] + DETECTOR(21, 10, 0, 0) rec[-372] rec[-129] + DETECTOR(21, 11, 0, 3) rec[-249] rec[-6] + DETECTOR(22, 9, 0, 5) rec[-5] + DETECTOR(23, 1, 0, 4) rec[-4] + DETECTOR(23, 2, 0, 2) rec[-370] rec[-369] rec[-367] rec[-128] + DETECTOR(23, 3, 0, 5) rec[-248] rec[-3] + DETECTOR(23, 4, 0, 0) rec[-368] rec[-127] + DETECTOR(23, 5, 0, 3) rec[-247] rec[-2] + DETECTOR(24, 3, 0, 5) rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 51 50 53 52 55 54 59 58 61 60 63 62 65 64 67 66 69 68 71 70 73 72 75 74 78 77 80 79 82 81 84 83 86 85 88 87 90 89 92 91 94 93 96 95 98 97 102 101 104 103 106 105 108 107 110 109 112 111 114 113 116 115 118 117 120 119 122 121 124 123 127 126 129 128 131 130 133 132 135 134 137 136 139 138 141 140 143 142 145 144 147 146 149 148 151 150 153 152 157 156 159 158 161 160 163 162 165 164 167 166 169 168 171 170 173 172 175 174 177 176 179 178 181 180 183 182 185 184 188 187 190 189 192 191 194 193 196 195 198 197 200 199 202 201 204 203 206 205 208 207 210 209 212 211 214 213 216 215 218 217 220 219 224 223 226 225 228 227 230 229 232 231 234 233 236 235 238 237 240 239 242 241 244 243 246 245 248 247 250 249 252 251 254 253 256 255 258 257 261 260 263 262 265 264 267 266 269 268 271 270 273 272 275 274 277 276 279 278 281 280 283 282 285 284 287 286 289 288 291 290 293 292 296 295 298 297 300 299 302 301 304 303 306 305 308 307 310 309 312 311 314 313 316 315 318 317 320 319 322 321 324 323 326 325 330 329 332 331 334 333 336 335 338 337 340 339 342 341 344 343 346 345 348 347 350 349 352 351 354 353 356 355 359 358 361 360 363 362 365 364 367 366 369 368 371 370 373 372 375 374 377 376 379 378 381 380 383 382 387 386 389 388 391 390 393 392 395 394 397 396 399 398 401 400 403 402 405 404 407 406 410 409 412 411 414 413 416 415 418 417 420 419 422 421 424 423 426 425 428 427 432 431 434 433 436 435 438 437 440 439 442 441 444 443 446 445 449 448 451 450 453 452 455 454 457 456 459 458 461 460 465 464 467 466 469 468 471 470 473 472 476 475 478 477 480 479 482 481 486 485 488 487 491 490 + DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 + TICK +} +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 +DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 +DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 +TICK +MX(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 +M(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 +TICK +RX 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 +R 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 +OBSERVABLE_INCLUDE(0) rec[-124] rec[-131] rec[-141] rec[-154] rec[-170] rec[-189] rec[-206] rec[-220] rec[-231] rec[-239] rec[-244] rec[-246] +X_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 50 52 54 56 77 79 81 83 85 87 89 91 93 95 97 99 126 128 130 132 134 136 138 140 142 144 146 148 150 152 154 187 189 191 193 195 197 199 201 203 205 207 209 211 213 215 217 219 221 260 262 264 266 268 270 272 274 276 278 280 282 284 286 288 290 292 329 331 333 335 337 339 341 343 345 347 349 351 353 355 386 388 390 392 394 396 398 400 402 404 406 431 433 435 437 439 441 443 445 464 466 468 470 472 485 487 +Z_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 51 55 76 78 80 82 84 86 88 90 92 94 98 125 127 129 131 133 135 137 139 141 143 145 147 149 153 186 188 190 192 194 196 198 200 202 204 206 208 210 212 214 216 220 259 261 263 265 267 269 271 273 275 277 279 281 283 285 287 289 291 293 326 328 330 332 334 336 338 340 342 344 346 348 350 352 354 356 383 385 387 389 391 393 395 397 399 401 403 405 407 428 430 432 434 436 438 440 442 444 446 461 463 465 467 469 471 473 482 484 486 488 491 +DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 53 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 96 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 151 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 218 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 248 249 250 251 252 253 254 255 256 257 258 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 327 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 384 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 429 447 448 449 450 451 452 453 454 455 456 457 458 459 460 462 474 475 476 477 478 479 480 481 483 489 490 492 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 38 58 40 60 42 62 44 64 46 66 48 68 50 70 52 72 54 74 56 76 57 78 59 80 61 82 63 84 65 86 67 88 69 90 71 92 73 94 75 101 77 103 79 105 81 107 83 109 85 111 87 113 89 115 91 117 93 119 95 121 97 123 99 125 100 127 102 129 104 131 106 133 108 135 110 137 112 139 114 141 116 143 118 145 120 147 122 149 124 156 126 158 128 160 130 162 132 164 134 166 136 168 138 170 140 172 142 174 144 176 146 178 148 180 150 182 152 184 154 186 155 188 157 190 159 192 161 194 163 196 165 198 167 200 169 202 171 204 173 206 175 208 177 210 179 212 181 214 183 216 185 223 187 225 189 227 191 229 193 231 195 233 197 235 199 237 201 239 203 241 205 243 207 245 209 247 211 249 213 251 215 253 217 255 219 257 221 259 222 261 224 263 226 265 228 267 230 269 232 271 234 273 236 275 238 277 240 279 242 281 244 283 246 285 248 287 250 289 252 291 254 293 256 295 260 297 262 299 264 301 266 303 268 305 270 307 272 309 274 311 276 313 278 315 280 317 282 319 284 321 286 323 288 325 290 327 292 328 294 330 296 332 298 334 300 336 302 338 304 340 306 342 308 344 310 346 312 348 314 350 316 352 318 354 320 356 322 358 329 360 331 362 333 364 335 366 337 368 339 370 341 372 343 374 345 376 347 378 349 380 351 382 353 384 355 385 357 387 359 389 361 391 363 393 365 395 367 397 369 399 371 401 373 403 375 405 377 407 379 409 386 411 388 413 390 415 392 417 394 419 396 421 398 423 400 425 402 427 404 429 406 430 408 432 410 434 412 436 414 438 416 440 418 442 420 444 422 446 424 448 431 450 433 452 435 454 437 456 439 458 441 460 443 462 445 463 447 465 449 467 451 469 453 471 455 473 457 475 464 477 466 479 468 481 470 483 472 484 474 486 476 488 478 490 485 492 487 +DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 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 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 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 248 249 250 251 252 253 254 255 256 257 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 474 475 476 477 478 479 480 481 482 483 484 485 486 487 489 490 491 492 +DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 +TICK +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 +DETECTOR(1, 1, 0, 1) rec[-246] +DETECTOR(1, 2, 0, 5) rec[-372] rec[-120] +DETECTOR(1, 4, 0, 3) rec[-371] rec[-119] +DETECTOR(1, 5, 0, 0) rec[-491] rec[-490] rec[-245] +DETECTOR(1, 6, 0, 4) rec[-118] +DETECTOR(3, 1, 0, 1) rec[-244] +DETECTOR(3, 2, 0, 5) rec[-370] rec[-369] rec[-117] +DETECTOR(3, 3, 0, 2) rec[-489] rec[-243] +DETECTOR(3, 4, 0, 3) rec[-368] rec[-116] +DETECTOR(3, 5, 0, 0) rec[-488] rec[-242] +DETECTOR(3, 6, 0, 4) rec[-367] rec[-115] +DETECTOR(3, 7, 0, 1) rec[-487] rec[-241] +DETECTOR(3, 8, 0, 5) rec[-114] +DETECTOR(3, 10, 0, 3) rec[-366] rec[-113] +DETECTOR(3, 11, 0, 0) rec[-485] rec[-484] rec[-240] +DETECTOR(3, 12, 0, 4) rec[-112] +DETECTOR(5, 1, 0, 1) rec[-239] +DETECTOR(5, 2, 0, 5) rec[-365] rec[-364] rec[-111] +DETECTOR(5, 3, 0, 2) rec[-483] rec[-238] +DETECTOR(5, 4, 0, 3) rec[-363] rec[-110] +DETECTOR(5, 5, 0, 0) rec[-482] rec[-237] +DETECTOR(5, 6, 0, 4) rec[-362] rec[-109] +DETECTOR(5, 7, 0, 1) rec[-481] rec[-236] +DETECTOR(5, 8, 0, 5) rec[-361] rec[-108] +DETECTOR(5, 9, 0, 2) rec[-480] rec[-235] +DETECTOR(5, 10, 0, 3) rec[-360] rec[-107] +DETECTOR(5, 11, 0, 0) rec[-479] rec[-234] +DETECTOR(5, 12, 0, 4) rec[-359] rec[-106] +DETECTOR(5, 13, 0, 1) rec[-478] rec[-233] +DETECTOR(5, 14, 0, 5) rec[-105] +DETECTOR(5, 16, 0, 3) rec[-358] rec[-104] +DETECTOR(5, 17, 0, 0) rec[-476] rec[-475] rec[-232] +DETECTOR(5, 18, 0, 4) rec[-103] +DETECTOR(7, 1, 0, 1) rec[-231] +DETECTOR(7, 2, 0, 5) rec[-357] rec[-356] rec[-102] +DETECTOR(7, 3, 0, 2) rec[-474] rec[-230] +DETECTOR(7, 4, 0, 3) rec[-355] rec[-101] +DETECTOR(7, 5, 0, 0) rec[-473] rec[-229] +DETECTOR(7, 6, 0, 4) rec[-354] rec[-100] +DETECTOR(7, 7, 0, 1) rec[-472] rec[-228] +DETECTOR(7, 8, 0, 5) rec[-353] rec[-99] +DETECTOR(7, 9, 0, 2) rec[-471] rec[-227] +DETECTOR(7, 10, 0, 3) rec[-352] rec[-98] +DETECTOR(7, 11, 0, 0) rec[-470] rec[-226] +DETECTOR(7, 12, 0, 4) rec[-351] rec[-97] +DETECTOR(7, 13, 0, 1) rec[-469] rec[-225] +DETECTOR(7, 14, 0, 5) rec[-350] rec[-96] +DETECTOR(7, 15, 0, 2) rec[-468] rec[-224] +DETECTOR(7, 16, 0, 3) rec[-349] rec[-95] +DETECTOR(7, 17, 0, 0) rec[-467] rec[-223] +DETECTOR(7, 18, 0, 4) rec[-348] rec[-94] +DETECTOR(7, 19, 0, 1) rec[-466] rec[-222] +DETECTOR(7, 20, 0, 5) rec[-93] +DETECTOR(7, 22, 0, 3) rec[-347] rec[-92] +DETECTOR(7, 23, 0, 0) rec[-464] rec[-463] rec[-221] +DETECTOR(7, 24, 0, 4) rec[-91] +DETECTOR(9, 1, 0, 1) rec[-220] +DETECTOR(9, 2, 0, 5) rec[-346] rec[-345] rec[-90] +DETECTOR(9, 3, 0, 2) rec[-462] rec[-219] +DETECTOR(9, 4, 0, 3) rec[-344] rec[-89] +DETECTOR(9, 5, 0, 0) rec[-461] rec[-218] +DETECTOR(9, 6, 0, 4) rec[-343] rec[-88] +DETECTOR(9, 7, 0, 1) rec[-460] rec[-217] +DETECTOR(9, 8, 0, 5) rec[-342] rec[-87] +DETECTOR(9, 9, 0, 2) rec[-459] rec[-216] +DETECTOR(9, 10, 0, 3) rec[-341] rec[-86] +DETECTOR(9, 11, 0, 0) rec[-458] rec[-215] +DETECTOR(9, 12, 0, 4) rec[-340] rec[-85] +DETECTOR(9, 13, 0, 1) rec[-457] rec[-214] +DETECTOR(9, 14, 0, 5) rec[-339] rec[-84] +DETECTOR(9, 15, 0, 2) rec[-456] rec[-213] +DETECTOR(9, 16, 0, 3) rec[-338] rec[-83] +DETECTOR(9, 17, 0, 0) rec[-455] rec[-212] +DETECTOR(9, 18, 0, 4) rec[-337] rec[-82] +DETECTOR(9, 19, 0, 1) rec[-454] rec[-211] +DETECTOR(9, 20, 0, 5) rec[-336] rec[-81] +DETECTOR(9, 21, 0, 2) rec[-453] rec[-210] +DETECTOR(9, 22, 0, 3) rec[-335] rec[-80] +DETECTOR(9, 23, 0, 0) rec[-452] rec[-209] +DETECTOR(9, 24, 0, 4) rec[-334] rec[-79] +DETECTOR(9, 25, 0, 1) rec[-451] rec[-208] +DETECTOR(9, 26, 0, 5) rec[-78] +DETECTOR(9, 28, 0, 3) rec[-333] rec[-77] +DETECTOR(9, 29, 0, 0) rec[-449] rec[-448] rec[-207] +DETECTOR(9, 30, 0, 4) rec[-76] +DETECTOR(11, 1, 0, 1) rec[-206] +DETECTOR(11, 2, 0, 5) rec[-332] rec[-331] rec[-75] +DETECTOR(11, 3, 0, 2) rec[-447] rec[-205] +DETECTOR(11, 4, 0, 3) rec[-330] rec[-74] +DETECTOR(11, 5, 0, 0) rec[-446] rec[-204] +DETECTOR(11, 6, 0, 4) rec[-329] rec[-73] +DETECTOR(11, 7, 0, 1) rec[-445] rec[-203] +DETECTOR(11, 8, 0, 5) rec[-328] rec[-72] +DETECTOR(11, 9, 0, 2) rec[-444] rec[-202] +DETECTOR(11, 10, 0, 3) rec[-327] rec[-71] +DETECTOR(11, 11, 0, 0) rec[-443] rec[-201] +DETECTOR(11, 12, 0, 4) rec[-326] rec[-70] +DETECTOR(11, 13, 0, 1) rec[-442] rec[-200] +DETECTOR(11, 14, 0, 5) rec[-325] rec[-69] +DETECTOR(11, 15, 0, 2) rec[-441] rec[-199] +DETECTOR(11, 16, 0, 3) rec[-324] rec[-68] +DETECTOR(11, 17, 0, 0) rec[-440] rec[-198] +DETECTOR(11, 18, 0, 4) rec[-323] rec[-67] +DETECTOR(11, 19, 0, 1) rec[-439] rec[-197] +DETECTOR(11, 20, 0, 5) rec[-322] rec[-66] +DETECTOR(11, 21, 0, 2) rec[-438] rec[-196] +DETECTOR(11, 22, 0, 3) rec[-321] rec[-65] +DETECTOR(11, 23, 0, 0) rec[-437] rec[-195] +DETECTOR(11, 24, 0, 4) rec[-320] rec[-64] +DETECTOR(11, 25, 0, 1) rec[-436] rec[-194] +DETECTOR(11, 26, 0, 5) rec[-319] rec[-63] +DETECTOR(11, 27, 0, 2) rec[-435] rec[-193] +DETECTOR(11, 28, 0, 3) rec[-318] rec[-62] +DETECTOR(11, 29, 0, 0) rec[-434] rec[-192] +DETECTOR(11, 30, 0, 4) rec[-317] rec[-61] +DETECTOR(11, 31, 0, 1) rec[-433] rec[-191] +DETECTOR(11, 32, 0, 5) rec[-60] +DETECTOR(11, 34, 0, 3) rec[-316] rec[-59] +DETECTOR(11, 35, 0, 0) rec[-431] rec[-430] rec[-190] +DETECTOR(11, 36, 0, 4) rec[-58] +DETECTOR(13, 1, 0, 1) rec[-189] +DETECTOR(13, 2, 0, 5) rec[-315] rec[-314] rec[-57] +DETECTOR(13, 3, 0, 2) rec[-429] rec[-188] +DETECTOR(13, 4, 0, 3) rec[-313] rec[-56] +DETECTOR(13, 5, 0, 0) rec[-428] rec[-187] +DETECTOR(13, 6, 0, 4) rec[-312] rec[-55] +DETECTOR(13, 7, 0, 1) rec[-427] rec[-186] +DETECTOR(13, 8, 0, 5) rec[-311] rec[-54] +DETECTOR(13, 9, 0, 2) rec[-426] rec[-185] +DETECTOR(13, 10, 0, 3) rec[-310] rec[-53] +DETECTOR(13, 11, 0, 0) rec[-425] rec[-184] +DETECTOR(13, 12, 0, 4) rec[-309] rec[-52] +DETECTOR(13, 13, 0, 1) rec[-424] rec[-183] +DETECTOR(13, 14, 0, 5) rec[-308] rec[-51] +DETECTOR(13, 15, 0, 2) rec[-423] rec[-182] +DETECTOR(13, 16, 0, 3) rec[-307] rec[-50] +DETECTOR(13, 17, 0, 0) rec[-422] rec[-181] +DETECTOR(13, 18, 0, 4) rec[-306] rec[-49] +DETECTOR(13, 19, 0, 1) rec[-421] rec[-180] +DETECTOR(13, 20, 0, 5) rec[-305] rec[-48] +DETECTOR(13, 21, 0, 2) rec[-420] rec[-179] +DETECTOR(13, 22, 0, 3) rec[-304] rec[-47] +DETECTOR(13, 23, 0, 0) rec[-419] rec[-178] +DETECTOR(13, 24, 0, 4) rec[-303] rec[-46] +DETECTOR(13, 25, 0, 1) rec[-418] rec[-177] +DETECTOR(13, 26, 0, 5) rec[-302] rec[-45] +DETECTOR(13, 27, 0, 2) rec[-417] rec[-176] +DETECTOR(13, 28, 0, 3) rec[-301] rec[-44] +DETECTOR(13, 29, 0, 0) rec[-416] rec[-175] +DETECTOR(13, 30, 0, 4) rec[-300] rec[-43] +DETECTOR(13, 31, 0, 1) rec[-415] rec[-174] +DETECTOR(13, 32, 0, 5) rec[-299] rec[-297] rec[-42] +DETECTOR(13, 33, 0, 2) rec[-414] rec[-173] +DETECTOR(13, 34, 0, 3) rec[-298] rec[-41] +DETECTOR(13, 35, 0, 0) rec[-413] rec[-172] +DETECTOR(14, 33, 0, 2) rec[-171] +DETECTOR(15, 1, 0, 1) rec[-170] +DETECTOR(15, 2, 0, 5) rec[-296] rec[-295] rec[-40] +DETECTOR(15, 3, 0, 2) rec[-412] rec[-169] +DETECTOR(15, 4, 0, 3) rec[-294] rec[-39] +DETECTOR(15, 5, 0, 0) rec[-411] rec[-168] +DETECTOR(15, 6, 0, 4) rec[-293] rec[-38] +DETECTOR(15, 7, 0, 1) rec[-410] rec[-167] +DETECTOR(15, 8, 0, 5) rec[-292] rec[-37] +DETECTOR(15, 9, 0, 2) rec[-409] rec[-166] +DETECTOR(15, 10, 0, 3) rec[-291] rec[-36] +DETECTOR(15, 11, 0, 0) rec[-408] rec[-165] +DETECTOR(15, 12, 0, 4) rec[-290] rec[-35] +DETECTOR(15, 13, 0, 1) rec[-407] rec[-164] +DETECTOR(15, 14, 0, 5) rec[-289] rec[-34] +DETECTOR(15, 15, 0, 2) rec[-406] rec[-163] +DETECTOR(15, 16, 0, 3) rec[-288] rec[-33] +DETECTOR(15, 17, 0, 0) rec[-405] rec[-162] +DETECTOR(15, 18, 0, 4) rec[-287] rec[-32] +DETECTOR(15, 19, 0, 1) rec[-404] rec[-161] +DETECTOR(15, 20, 0, 5) rec[-286] rec[-31] +DETECTOR(15, 21, 0, 2) rec[-403] rec[-160] +DETECTOR(15, 22, 0, 3) rec[-285] rec[-30] +DETECTOR(15, 23, 0, 0) rec[-402] rec[-159] +DETECTOR(15, 24, 0, 4) rec[-284] rec[-29] +DETECTOR(15, 25, 0, 1) rec[-401] rec[-158] +DETECTOR(15, 26, 0, 5) rec[-283] rec[-281] rec[-28] +DETECTOR(15, 27, 0, 2) rec[-400] rec[-157] +DETECTOR(15, 28, 0, 3) rec[-282] rec[-27] +DETECTOR(15, 29, 0, 0) rec[-399] rec[-156] +DETECTOR(16, 27, 0, 2) rec[-155] +DETECTOR(17, 1, 0, 1) rec[-154] +DETECTOR(17, 2, 0, 5) rec[-280] rec[-279] rec[-26] +DETECTOR(17, 3, 0, 2) rec[-398] rec[-153] +DETECTOR(17, 4, 0, 3) rec[-278] rec[-25] +DETECTOR(17, 5, 0, 0) rec[-397] rec[-152] +DETECTOR(17, 6, 0, 4) rec[-277] rec[-24] +DETECTOR(17, 7, 0, 1) rec[-396] rec[-151] +DETECTOR(17, 8, 0, 5) rec[-276] rec[-23] +DETECTOR(17, 9, 0, 2) rec[-395] rec[-150] +DETECTOR(17, 10, 0, 3) rec[-275] rec[-22] +DETECTOR(17, 11, 0, 0) rec[-394] rec[-149] +DETECTOR(17, 12, 0, 4) rec[-274] rec[-21] +DETECTOR(17, 13, 0, 1) rec[-393] rec[-148] +DETECTOR(17, 14, 0, 5) rec[-273] rec[-20] +DETECTOR(17, 15, 0, 2) rec[-392] rec[-147] +DETECTOR(17, 16, 0, 3) rec[-272] rec[-19] +DETECTOR(17, 17, 0, 0) rec[-391] rec[-146] +DETECTOR(17, 18, 0, 4) rec[-271] rec[-18] +DETECTOR(17, 19, 0, 1) rec[-390] rec[-145] +DETECTOR(17, 20, 0, 5) rec[-270] rec[-268] rec[-17] +DETECTOR(17, 21, 0, 2) rec[-389] rec[-144] +DETECTOR(17, 22, 0, 3) rec[-269] rec[-16] +DETECTOR(17, 23, 0, 0) rec[-388] rec[-143] +DETECTOR(18, 21, 0, 2) rec[-142] +DETECTOR(19, 1, 0, 1) rec[-141] +DETECTOR(19, 2, 0, 5) rec[-267] rec[-266] rec[-15] +DETECTOR(19, 3, 0, 2) rec[-387] rec[-140] +DETECTOR(19, 4, 0, 3) rec[-265] rec[-14] +DETECTOR(19, 5, 0, 0) rec[-386] rec[-139] +DETECTOR(19, 6, 0, 4) rec[-264] rec[-13] +DETECTOR(19, 7, 0, 1) rec[-385] rec[-138] +DETECTOR(19, 8, 0, 5) rec[-263] rec[-12] +DETECTOR(19, 9, 0, 2) rec[-384] rec[-137] +DETECTOR(19, 10, 0, 3) rec[-262] rec[-11] +DETECTOR(19, 11, 0, 0) rec[-383] rec[-136] +DETECTOR(19, 12, 0, 4) rec[-261] rec[-10] +DETECTOR(19, 13, 0, 1) rec[-382] rec[-135] +DETECTOR(19, 14, 0, 5) rec[-260] rec[-258] rec[-9] +DETECTOR(19, 15, 0, 2) rec[-381] rec[-134] +DETECTOR(19, 16, 0, 3) rec[-259] rec[-8] +DETECTOR(19, 17, 0, 0) rec[-380] rec[-133] +DETECTOR(20, 15, 0, 2) rec[-132] +DETECTOR(21, 1, 0, 1) rec[-131] +DETECTOR(21, 2, 0, 5) rec[-257] rec[-256] rec[-7] +DETECTOR(21, 3, 0, 2) rec[-379] rec[-130] +DETECTOR(21, 4, 0, 3) rec[-255] rec[-6] +DETECTOR(21, 5, 0, 0) rec[-378] rec[-129] +DETECTOR(21, 6, 0, 4) rec[-254] rec[-5] +DETECTOR(21, 7, 0, 1) rec[-377] rec[-128] +DETECTOR(21, 8, 0, 5) rec[-253] rec[-251] rec[-4] +DETECTOR(21, 9, 0, 2) rec[-376] rec[-127] +DETECTOR(21, 10, 0, 3) rec[-252] rec[-3] +DETECTOR(21, 11, 0, 0) rec[-375] rec[-126] +DETECTOR(22, 9, 0, 2) rec[-125] +DETECTOR(23, 1, 0, 1) rec[-124] +DETECTOR(23, 2, 0, 5) rec[-250] rec[-249] rec[-247] rec[-2] +DETECTOR(23, 3, 0, 2) rec[-374] rec[-123] +DETECTOR(23, 4, 0, 3) rec[-248] rec[-1] +DETECTOR(23, 5, 0, 0) rec[-373] rec[-122] +DETECTOR(24, 3, 0, 2) rec[-121] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 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 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 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 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 248 249 250 251 252 253 254 255 256 257 258 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 448 449 450 451 452 453 454 455 456 457 458 459 460 461 464 465 466 467 468 469 470 471 472 473 475 476 477 478 479 480 481 482 485 486 487 488 490 491 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 +TICK +CX 491 490 488 487 486 485 482 481 480 479 478 477 476 475 473 472 471 470 469 468 467 466 465 464 461 460 459 458 457 456 455 454 453 452 451 450 449 448 446 445 444 443 442 441 440 439 438 437 436 435 434 433 432 431 428 427 426 425 424 423 422 421 420 419 418 417 416 415 414 413 412 411 410 409 407 406 405 404 403 402 401 400 399 398 397 396 395 394 393 392 391 390 389 388 387 386 383 382 381 380 379 378 377 376 375 374 373 372 371 370 369 368 367 366 365 364 363 362 361 360 359 358 356 355 354 353 352 351 350 349 348 347 346 345 344 343 342 341 340 339 338 337 336 335 334 333 332 331 330 329 326 325 324 323 322 321 320 319 318 317 316 315 314 313 312 311 310 309 308 307 306 305 304 303 302 301 300 299 298 297 296 295 293 292 291 290 289 288 287 286 285 284 283 282 281 280 279 278 277 276 275 274 273 272 271 270 269 268 267 266 265 264 263 262 261 260 258 257 256 255 254 253 252 251 250 249 248 247 246 245 244 243 242 241 240 239 238 237 236 235 234 233 232 231 230 229 228 227 226 225 224 223 220 219 218 217 216 215 214 213 212 211 210 209 208 207 206 205 204 203 202 201 200 199 198 197 196 195 194 193 192 191 190 189 188 187 185 184 183 182 181 180 179 178 177 176 175 174 173 172 171 170 169 168 167 166 165 164 163 162 161 160 159 158 157 156 153 152 151 150 149 148 147 146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 38 37 36 35 34 33 32 31 30 29 28 27 24 23 22 21 20 19 18 17 16 15 13 12 11 10 9 8 5 4 3 2 +DEPOLARIZE2(0.001) 491 490 488 487 486 485 482 481 480 479 478 477 476 475 473 472 471 470 469 468 467 466 465 464 461 460 459 458 457 456 455 454 453 452 451 450 449 448 446 445 444 443 442 441 440 439 438 437 436 435 434 433 432 431 428 427 426 425 424 423 422 421 420 419 418 417 416 415 414 413 412 411 410 409 407 406 405 404 403 402 401 400 399 398 397 396 395 394 393 392 391 390 389 388 387 386 383 382 381 380 379 378 377 376 375 374 373 372 371 370 369 368 367 366 365 364 363 362 361 360 359 358 356 355 354 353 352 351 350 349 348 347 346 345 344 343 342 341 340 339 338 337 336 335 334 333 332 331 330 329 326 325 324 323 322 321 320 319 318 317 316 315 314 313 312 311 310 309 308 307 306 305 304 303 302 301 300 299 298 297 296 295 293 292 291 290 289 288 287 286 285 284 283 282 281 280 279 278 277 276 275 274 273 272 271 270 269 268 267 266 265 264 263 262 261 260 258 257 256 255 254 253 252 251 250 249 248 247 246 245 244 243 242 241 240 239 238 237 236 235 234 233 232 231 230 229 228 227 226 225 224 223 220 219 218 217 216 215 214 213 212 211 210 209 208 207 206 205 204 203 202 201 200 199 198 197 196 195 194 193 192 191 190 189 188 187 185 184 183 182 181 180 179 178 177 176 175 174 173 172 171 170 169 168 167 166 165 164 163 162 161 160 159 158 157 156 153 152 151 150 149 148 147 146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 38 37 36 35 34 33 32 31 30 29 28 27 24 23 22 21 20 19 18 17 16 15 13 12 11 10 9 8 5 4 3 2 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 56 57 76 99 100 125 154 155 186 221 222 259 294 327 328 357 384 385 408 429 430 447 462 463 474 483 484 489 492 +TICK +CX 492 491 490 489 487 486 485 484 483 482 481 480 479 478 477 476 475 474 472 471 470 469 468 467 466 465 464 463 462 461 460 459 458 457 456 455 454 453 452 451 450 449 448 447 445 444 443 442 441 440 439 438 437 436 435 434 433 432 431 430 429 428 427 426 425 424 423 422 421 420 419 418 417 416 415 414 413 412 411 410 409 408 406 405 404 403 402 401 400 399 398 397 396 395 394 393 392 391 390 389 388 387 386 385 384 383 382 381 380 379 378 377 376 375 374 373 372 371 370 369 368 367 366 365 364 363 362 361 360 359 358 357 355 354 353 352 351 350 349 348 347 346 345 344 343 342 341 340 339 338 337 336 335 334 333 332 331 330 329 328 327 326 325 324 323 322 321 320 319 318 317 316 315 314 313 312 311 310 309 308 307 306 305 304 303 302 301 300 299 298 297 296 295 294 292 291 290 289 288 287 286 285 284 283 282 281 280 279 278 277 276 275 274 273 272 271 270 269 268 267 266 265 264 263 262 261 260 259 257 256 255 254 253 252 251 250 249 248 247 246 245 244 243 242 241 240 239 238 237 236 235 234 233 232 231 230 229 228 227 226 225 224 223 222 221 220 219 218 217 216 215 214 213 212 211 210 209 208 207 206 205 204 203 202 201 200 199 198 197 196 195 194 193 192 191 190 189 188 187 186 184 183 182 181 180 179 178 177 176 175 174 173 172 171 170 169 168 167 166 165 164 163 162 161 160 159 158 157 156 155 154 153 152 151 150 149 148 147 146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 12 11 10 9 8 7 6 5 4 3 2 1 +DEPOLARIZE2(0.001) 492 491 490 489 487 486 485 484 483 482 481 480 479 478 477 476 475 474 472 471 470 469 468 467 466 465 464 463 462 461 460 459 458 457 456 455 454 453 452 451 450 449 448 447 445 444 443 442 441 440 439 438 437 436 435 434 433 432 431 430 429 428 427 426 425 424 423 422 421 420 419 418 417 416 415 414 413 412 411 410 409 408 406 405 404 403 402 401 400 399 398 397 396 395 394 393 392 391 390 389 388 387 386 385 384 383 382 381 380 379 378 377 376 375 374 373 372 371 370 369 368 367 366 365 364 363 362 361 360 359 358 357 355 354 353 352 351 350 349 348 347 346 345 344 343 342 341 340 339 338 337 336 335 334 333 332 331 330 329 328 327 326 325 324 323 322 321 320 319 318 317 316 315 314 313 312 311 310 309 308 307 306 305 304 303 302 301 300 299 298 297 296 295 294 292 291 290 289 288 287 286 285 284 283 282 281 280 279 278 277 276 275 274 273 272 271 270 269 268 267 266 265 264 263 262 261 260 259 257 256 255 254 253 252 251 250 249 248 247 246 245 244 243 242 241 240 239 238 237 236 235 234 233 232 231 230 229 228 227 226 225 224 223 222 221 220 219 218 217 216 215 214 213 212 211 210 209 208 207 206 205 204 203 202 201 200 199 198 197 196 195 194 193 192 191 190 189 188 187 186 184 183 182 181 180 179 178 177 176 175 174 173 172 171 170 169 168 167 166 165 164 163 162 161 160 159 158 157 156 155 154 153 152 151 150 149 148 147 146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 12 11 10 9 8 7 6 5 4 3 2 1 +DEPOLARIZE1(0.001) 0 13 38 75 124 185 258 293 356 407 446 473 488 +TICK +CX 487 492 485 490 478 488 476 486 474 484 472 483 470 481 468 479 466 477 464 475 457 473 455 471 453 469 451 467 449 465 447 463 445 462 443 460 441 458 439 456 437 454 435 452 433 450 431 448 424 446 422 444 420 442 418 440 416 438 414 436 412 434 410 432 408 430 406 429 404 427 402 425 400 423 398 421 396 419 394 417 392 415 390 413 388 411 386 409 379 407 377 405 375 403 373 401 371 399 369 397 367 395 365 393 363 391 361 389 359 387 357 385 355 384 353 382 351 380 349 378 347 376 345 374 343 372 341 370 339 368 337 366 335 364 333 362 331 360 329 358 322 356 320 354 318 352 316 350 314 348 312 346 310 344 308 342 306 340 304 338 302 336 300 334 298 332 296 330 294 328 292 327 290 325 288 323 286 321 284 319 282 317 280 315 278 313 276 311 274 309 272 307 270 305 268 303 266 301 264 299 262 297 260 295 256 293 254 291 252 289 250 287 248 285 246 283 244 281 242 279 240 277 238 275 236 273 234 271 232 269 230 267 228 265 226 263 224 261 222 259 221 257 219 255 217 253 215 251 213 249 211 247 209 245 207 243 205 241 203 239 201 237 199 235 197 233 195 231 193 229 191 227 189 225 187 223 185 216 183 214 181 212 179 210 177 208 175 206 173 204 171 202 169 200 167 198 165 196 163 194 161 192 159 190 157 188 155 186 154 184 152 182 150 180 148 178 146 176 144 174 142 172 140 170 138 168 136 166 134 164 132 162 130 160 128 158 126 156 124 149 122 147 120 145 118 143 116 141 114 139 112 137 110 135 108 133 106 131 104 129 102 127 100 125 99 123 97 121 95 119 93 117 91 115 89 113 87 111 85 109 83 107 81 105 79 103 77 101 75 94 73 92 71 90 69 88 67 86 65 84 63 82 61 80 59 78 57 76 56 74 54 72 52 70 50 68 48 66 46 64 44 62 42 60 40 58 38 51 36 49 34 47 32 45 30 43 28 41 26 39 25 37 23 35 21 33 19 31 17 29 15 27 13 20 11 18 9 16 7 14 6 12 4 10 2 8 0 1 +DEPOLARIZE2(0.001) 487 492 485 490 478 488 476 486 474 484 472 483 470 481 468 479 466 477 464 475 457 473 455 471 453 469 451 467 449 465 447 463 445 462 443 460 441 458 439 456 437 454 435 452 433 450 431 448 424 446 422 444 420 442 418 440 416 438 414 436 412 434 410 432 408 430 406 429 404 427 402 425 400 423 398 421 396 419 394 417 392 415 390 413 388 411 386 409 379 407 377 405 375 403 373 401 371 399 369 397 367 395 365 393 363 391 361 389 359 387 357 385 355 384 353 382 351 380 349 378 347 376 345 374 343 372 341 370 339 368 337 366 335 364 333 362 331 360 329 358 322 356 320 354 318 352 316 350 314 348 312 346 310 344 308 342 306 340 304 338 302 336 300 334 298 332 296 330 294 328 292 327 290 325 288 323 286 321 284 319 282 317 280 315 278 313 276 311 274 309 272 307 270 305 268 303 266 301 264 299 262 297 260 295 256 293 254 291 252 289 250 287 248 285 246 283 244 281 242 279 240 277 238 275 236 273 234 271 232 269 230 267 228 265 226 263 224 261 222 259 221 257 219 255 217 253 215 251 213 249 211 247 209 245 207 243 205 241 203 239 201 237 199 235 197 233 195 231 193 229 191 227 189 225 187 223 185 216 183 214 181 212 179 210 177 208 175 206 173 204 171 202 169 200 167 198 165 196 163 194 161 192 159 190 157 188 155 186 154 184 152 182 150 180 148 178 146 176 144 174 142 172 140 170 138 168 136 166 134 164 132 162 130 160 128 158 126 156 124 149 122 147 120 145 118 143 116 141 114 139 112 137 110 135 108 133 106 131 104 129 102 127 100 125 99 123 97 121 95 119 93 117 91 115 89 113 87 111 85 109 83 107 81 105 79 103 77 101 75 94 73 92 71 90 69 88 67 86 65 84 63 82 61 80 59 78 57 76 56 74 54 72 52 70 50 68 48 66 46 64 44 62 42 60 40 58 38 51 36 49 34 47 32 45 30 43 28 41 26 39 25 37 23 35 21 33 19 31 17 29 15 27 13 20 11 18 9 16 7 14 6 12 4 10 2 8 0 1 +DEPOLARIZE1(0.001) 3 5 22 24 53 55 96 98 151 153 218 220 258 324 326 381 383 426 428 459 461 480 482 489 491 +TICK +M(0.001) 491 488 486 484 482 473 471 469 467 465 463 461 446 444 442 440 438 436 434 432 430 428 407 405 403 401 399 397 395 393 391 389 387 385 383 356 354 352 350 348 346 344 342 340 338 336 334 332 330 328 326 293 291 289 287 285 283 281 279 277 275 273 271 269 267 265 263 261 259 220 216 214 212 210 208 206 204 202 200 198 196 194 192 190 188 186 153 149 147 145 143 141 139 137 135 133 131 129 127 125 98 94 92 90 88 86 84 82 80 78 76 55 51 49 47 45 43 41 39 24 20 18 16 14 5 1 +MX(0.001) 492 490 489 483 481 480 479 478 477 476 475 474 462 460 459 458 457 456 455 454 453 452 451 450 449 448 447 429 427 426 425 424 423 422 421 420 419 418 417 416 415 414 413 412 411 410 409 408 384 382 381 380 379 378 377 376 375 374 373 372 371 370 369 368 367 366 365 364 363 362 361 360 359 358 357 327 325 324 323 322 321 320 319 318 317 316 315 314 313 312 311 310 309 308 307 306 305 304 303 302 301 300 299 298 297 296 295 294 258 257 256 255 254 253 252 251 250 249 248 247 246 245 244 243 242 241 240 239 238 237 236 235 234 233 232 231 230 229 228 227 226 225 224 223 222 218 185 184 183 182 181 180 179 178 177 176 175 174 173 172 171 170 169 168 167 166 165 164 163 162 161 160 159 158 157 156 155 151 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 96 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 53 38 37 36 35 34 33 32 31 30 29 28 27 26 22 13 12 11 10 9 8 7 3 0 487 485 472 470 468 466 464 445 443 441 439 437 435 433 431 406 404 402 400 398 396 394 392 390 388 386 355 353 351 349 347 345 343 341 339 337 335 333 331 329 292 290 288 286 284 282 280 278 276 274 272 270 268 266 264 262 260 221 219 217 215 213 211 209 207 205 203 201 199 197 195 193 191 189 187 154 152 150 148 146 144 142 140 138 136 134 132 130 128 126 99 97 95 93 91 89 87 85 83 81 79 77 56 54 52 50 48 46 44 42 40 25 23 21 19 17 15 6 4 2 +DETECTOR(1, 1, 0, 1) rec[-122] rec[-121] +DETECTOR(1, 1, 0, 4) rec[-368] +DETECTOR(1, 2, 0, 2) rec[-739] rec[-1] +DETECTOR(1, 4, 0, 0) rec[-738] rec[-2] +DETECTOR(1, 5, 0, 0) rec[-128] rec[-126] rec[-122] rec[-3] rec[-2] +DETECTOR(1, 5, 0, 3) rec[-612] rec[-611] rec[-369] +DETECTOR(1, 6, 0, 1) rec[-3] +DETECTOR(3, 1, 0, 1) rec[-125] rec[-123] +DETECTOR(3, 1, 0, 4) rec[-370] +DETECTOR(3, 2, 0, 2) rec[-737] rec[-736] rec[-4] +DETECTOR(3, 3, 0, 2) rec[-132] rec[-127] rec[-125] rec[-124] rec[-123] rec[-4] +DETECTOR(3, 3, 0, 5) rec[-610] rec[-371] +DETECTOR(3, 4, 0, 0) rec[-735] rec[-5] +DETECTOR(3, 5, 0, 0) rec[-134] rec[-129] rec[-127] rec[-126] rec[-125] rec[-5] +DETECTOR(3, 5, 0, 3) rec[-609] rec[-372] +DETECTOR(3, 6, 0, 1) rec[-734] rec[-6] +DETECTOR(3, 7, 0, 1) rec[-136] rec[-130] rec[-129] rec[-128] rec[-127] rec[-6] +DETECTOR(3, 7, 0, 4) rec[-608] rec[-373] +DETECTOR(3, 8, 0, 2) rec[-7] +DETECTOR(3, 10, 0, 0) rec[-733] rec[-8] +DETECTOR(3, 11, 0, 0) rec[-142] rec[-140] rec[-130] rec[-9] rec[-8] +DETECTOR(3, 11, 0, 3) rec[-606] rec[-605] rec[-374] +DETECTOR(3, 12, 0, 1) rec[-9] +DETECTOR(5, 1, 0, 1) rec[-133] rec[-131] +DETECTOR(5, 1, 0, 4) rec[-375] +DETECTOR(5, 2, 0, 2) rec[-732] rec[-731] rec[-10] +DETECTOR(5, 3, 0, 2) rec[-146] rec[-135] rec[-133] rec[-132] rec[-131] rec[-10] +DETECTOR(5, 3, 0, 5) rec[-604] rec[-376] +DETECTOR(5, 4, 0, 0) rec[-730] rec[-11] +DETECTOR(5, 5, 0, 0) rec[-148] rec[-137] rec[-135] rec[-134] rec[-133] rec[-11] +DETECTOR(5, 5, 0, 3) rec[-603] rec[-377] +DETECTOR(5, 6, 0, 1) rec[-729] rec[-12] +DETECTOR(5, 7, 0, 1) rec[-150] rec[-139] rec[-137] rec[-136] rec[-135] rec[-12] +DETECTOR(5, 7, 0, 4) rec[-602] rec[-378] +DETECTOR(5, 8, 0, 2) rec[-728] rec[-13] +DETECTOR(5, 9, 0, 2) rec[-152] rec[-141] rec[-139] rec[-138] rec[-137] rec[-13] +DETECTOR(5, 9, 0, 5) rec[-601] rec[-379] +DETECTOR(5, 10, 0, 0) rec[-727] rec[-14] +DETECTOR(5, 11, 0, 0) rec[-154] rec[-143] rec[-141] rec[-140] rec[-139] rec[-14] +DETECTOR(5, 11, 0, 3) rec[-600] rec[-380] +DETECTOR(5, 12, 0, 1) rec[-726] rec[-15] +DETECTOR(5, 13, 0, 1) rec[-156] rec[-144] rec[-143] rec[-142] rec[-141] rec[-15] +DETECTOR(5, 13, 0, 4) rec[-599] rec[-381] +DETECTOR(5, 14, 0, 2) rec[-16] +DETECTOR(5, 16, 0, 0) rec[-725] rec[-17] +DETECTOR(5, 17, 0, 0) rec[-162] rec[-160] rec[-144] rec[-18] rec[-17] +DETECTOR(5, 17, 0, 3) rec[-597] rec[-596] rec[-382] +DETECTOR(5, 18, 0, 1) rec[-18] +DETECTOR(7, 1, 0, 1) rec[-147] rec[-145] +DETECTOR(7, 1, 0, 4) rec[-383] +DETECTOR(7, 2, 0, 2) rec[-724] rec[-723] rec[-19] +DETECTOR(7, 3, 0, 2) rec[-166] rec[-149] rec[-147] rec[-146] rec[-145] rec[-19] +DETECTOR(7, 3, 0, 5) rec[-595] rec[-384] +DETECTOR(7, 4, 0, 0) rec[-722] rec[-20] +DETECTOR(7, 5, 0, 0) rec[-168] rec[-151] rec[-149] rec[-148] rec[-147] rec[-20] +DETECTOR(7, 5, 0, 3) rec[-594] rec[-385] +DETECTOR(7, 6, 0, 1) rec[-721] rec[-21] +DETECTOR(7, 7, 0, 1) rec[-170] rec[-153] rec[-151] rec[-150] rec[-149] rec[-21] +DETECTOR(7, 7, 0, 4) rec[-593] rec[-386] +DETECTOR(7, 8, 0, 2) rec[-720] rec[-22] +DETECTOR(7, 9, 0, 2) rec[-172] rec[-155] rec[-153] rec[-152] rec[-151] rec[-22] +DETECTOR(7, 9, 0, 5) rec[-592] rec[-387] +DETECTOR(7, 10, 0, 0) rec[-719] rec[-23] +DETECTOR(7, 11, 0, 0) rec[-174] rec[-157] rec[-155] rec[-154] rec[-153] rec[-23] +DETECTOR(7, 11, 0, 3) rec[-591] rec[-388] +DETECTOR(7, 12, 0, 1) rec[-718] rec[-24] +DETECTOR(7, 13, 0, 1) rec[-176] rec[-159] rec[-157] rec[-156] rec[-155] rec[-24] +DETECTOR(7, 13, 0, 4) rec[-590] rec[-389] +DETECTOR(7, 14, 0, 2) rec[-717] rec[-25] +DETECTOR(7, 15, 0, 2) rec[-178] rec[-161] rec[-159] rec[-158] rec[-157] rec[-25] +DETECTOR(7, 15, 0, 5) rec[-589] rec[-390] +DETECTOR(7, 16, 0, 0) rec[-716] rec[-26] +DETECTOR(7, 17, 0, 0) rec[-180] rec[-163] rec[-161] rec[-160] rec[-159] rec[-26] +DETECTOR(7, 17, 0, 3) rec[-588] rec[-391] +DETECTOR(7, 18, 0, 1) rec[-715] rec[-27] +DETECTOR(7, 19, 0, 1) rec[-182] rec[-164] rec[-163] rec[-162] rec[-161] rec[-27] +DETECTOR(7, 19, 0, 4) rec[-587] rec[-392] +DETECTOR(7, 20, 0, 2) rec[-28] +DETECTOR(7, 22, 0, 0) rec[-714] rec[-29] +DETECTOR(7, 23, 0, 0) rec[-188] rec[-186] rec[-164] rec[-30] rec[-29] +DETECTOR(7, 23, 0, 3) rec[-585] rec[-584] rec[-393] +DETECTOR(7, 24, 0, 1) rec[-30] +DETECTOR(9, 1, 0, 1) rec[-167] rec[-165] +DETECTOR(9, 1, 0, 4) rec[-394] +DETECTOR(9, 2, 0, 2) rec[-713] rec[-712] rec[-31] +DETECTOR(9, 3, 0, 2) rec[-192] rec[-169] rec[-167] rec[-166] rec[-165] rec[-31] +DETECTOR(9, 3, 0, 5) rec[-583] rec[-395] +DETECTOR(9, 4, 0, 0) rec[-711] rec[-32] +DETECTOR(9, 5, 0, 0) rec[-194] rec[-171] rec[-169] rec[-168] rec[-167] rec[-32] +DETECTOR(9, 5, 0, 3) rec[-582] rec[-396] +DETECTOR(9, 6, 0, 1) rec[-710] rec[-33] +DETECTOR(9, 7, 0, 1) rec[-196] rec[-173] rec[-171] rec[-170] rec[-169] rec[-33] +DETECTOR(9, 7, 0, 4) rec[-581] rec[-397] +DETECTOR(9, 8, 0, 2) rec[-709] rec[-34] +DETECTOR(9, 9, 0, 2) rec[-198] rec[-175] rec[-173] rec[-172] rec[-171] rec[-34] +DETECTOR(9, 9, 0, 5) rec[-580] rec[-398] +DETECTOR(9, 10, 0, 0) rec[-708] rec[-35] +DETECTOR(9, 11, 0, 0) rec[-200] rec[-177] rec[-175] rec[-174] rec[-173] rec[-35] +DETECTOR(9, 11, 0, 3) rec[-579] rec[-399] +DETECTOR(9, 12, 0, 1) rec[-707] rec[-36] +DETECTOR(9, 13, 0, 1) rec[-202] rec[-179] rec[-177] rec[-176] rec[-175] rec[-36] +DETECTOR(9, 13, 0, 4) rec[-578] rec[-400] +DETECTOR(9, 14, 0, 2) rec[-706] rec[-37] +DETECTOR(9, 15, 0, 2) rec[-204] rec[-181] rec[-179] rec[-178] rec[-177] rec[-37] +DETECTOR(9, 15, 0, 5) rec[-577] rec[-401] +DETECTOR(9, 16, 0, 0) rec[-705] rec[-38] +DETECTOR(9, 17, 0, 0) rec[-206] rec[-183] rec[-181] rec[-180] rec[-179] rec[-38] +DETECTOR(9, 17, 0, 3) rec[-576] rec[-402] +DETECTOR(9, 18, 0, 1) rec[-704] rec[-39] +DETECTOR(9, 19, 0, 1) rec[-208] rec[-185] rec[-183] rec[-182] rec[-181] rec[-39] +DETECTOR(9, 19, 0, 4) rec[-575] rec[-403] +DETECTOR(9, 20, 0, 2) rec[-703] rec[-40] +DETECTOR(9, 21, 0, 2) rec[-210] rec[-187] rec[-185] rec[-184] rec[-183] rec[-40] +DETECTOR(9, 21, 0, 5) rec[-574] rec[-404] +DETECTOR(9, 22, 0, 0) rec[-702] rec[-41] +DETECTOR(9, 23, 0, 0) rec[-212] rec[-189] rec[-187] rec[-186] rec[-185] rec[-41] +DETECTOR(9, 23, 0, 3) rec[-573] rec[-405] +DETECTOR(9, 24, 0, 1) rec[-701] rec[-42] +DETECTOR(9, 25, 0, 1) rec[-214] rec[-190] rec[-189] rec[-188] rec[-187] rec[-42] +DETECTOR(9, 25, 0, 4) rec[-572] rec[-406] +DETECTOR(9, 26, 0, 2) rec[-43] +DETECTOR(9, 28, 0, 0) rec[-700] rec[-44] +DETECTOR(9, 29, 0, 0) rec[-220] rec[-218] rec[-190] rec[-45] rec[-44] +DETECTOR(9, 29, 0, 3) rec[-570] rec[-569] rec[-407] +DETECTOR(9, 30, 0, 1) rec[-45] +DETECTOR(11, 1, 0, 1) rec[-193] rec[-191] +DETECTOR(11, 1, 0, 4) rec[-408] +DETECTOR(11, 2, 0, 2) rec[-699] rec[-698] rec[-46] +DETECTOR(11, 3, 0, 2) rec[-224] rec[-195] rec[-193] rec[-192] rec[-191] rec[-46] +DETECTOR(11, 3, 0, 5) rec[-568] rec[-409] +DETECTOR(11, 4, 0, 0) rec[-697] rec[-47] +DETECTOR(11, 5, 0, 0) rec[-226] rec[-197] rec[-195] rec[-194] rec[-193] rec[-47] +DETECTOR(11, 5, 0, 3) rec[-567] rec[-410] +DETECTOR(11, 6, 0, 1) rec[-696] rec[-48] +DETECTOR(11, 7, 0, 1) rec[-228] rec[-199] rec[-197] rec[-196] rec[-195] rec[-48] +DETECTOR(11, 7, 0, 4) rec[-566] rec[-411] +DETECTOR(11, 8, 0, 2) rec[-695] rec[-49] +DETECTOR(11, 9, 0, 2) rec[-230] rec[-201] rec[-199] rec[-198] rec[-197] rec[-49] +DETECTOR(11, 9, 0, 5) rec[-565] rec[-412] +DETECTOR(11, 10, 0, 0) rec[-694] rec[-50] +DETECTOR(11, 11, 0, 0) rec[-232] rec[-203] rec[-201] rec[-200] rec[-199] rec[-50] +DETECTOR(11, 11, 0, 3) rec[-564] rec[-413] +DETECTOR(11, 12, 0, 1) rec[-693] rec[-51] +DETECTOR(11, 13, 0, 1) rec[-234] rec[-205] rec[-203] rec[-202] rec[-201] rec[-51] +DETECTOR(11, 13, 0, 4) rec[-563] rec[-414] +DETECTOR(11, 14, 0, 2) rec[-692] rec[-52] +DETECTOR(11, 15, 0, 2) rec[-236] rec[-207] rec[-205] rec[-204] rec[-203] rec[-52] +DETECTOR(11, 15, 0, 5) rec[-562] rec[-415] +DETECTOR(11, 16, 0, 0) rec[-691] rec[-53] +DETECTOR(11, 17, 0, 0) rec[-238] rec[-209] rec[-207] rec[-206] rec[-205] rec[-53] +DETECTOR(11, 17, 0, 3) rec[-561] rec[-416] +DETECTOR(11, 18, 0, 1) rec[-690] rec[-54] +DETECTOR(11, 19, 0, 1) rec[-240] rec[-211] rec[-209] rec[-208] rec[-207] rec[-54] +DETECTOR(11, 19, 0, 4) rec[-560] rec[-417] +DETECTOR(11, 20, 0, 2) rec[-689] rec[-55] +DETECTOR(11, 21, 0, 2) rec[-242] rec[-213] rec[-211] rec[-210] rec[-209] rec[-55] +DETECTOR(11, 21, 0, 5) rec[-559] rec[-418] +DETECTOR(11, 22, 0, 0) rec[-688] rec[-56] +DETECTOR(11, 23, 0, 0) rec[-244] rec[-215] rec[-213] rec[-212] rec[-211] rec[-56] +DETECTOR(11, 23, 0, 3) rec[-558] rec[-419] +DETECTOR(11, 24, 0, 1) rec[-687] rec[-57] +DETECTOR(11, 25, 0, 1) rec[-246] rec[-217] rec[-215] rec[-214] rec[-213] rec[-57] +DETECTOR(11, 25, 0, 4) rec[-557] rec[-420] +DETECTOR(11, 26, 0, 2) rec[-686] rec[-58] +DETECTOR(11, 27, 0, 2) rec[-248] rec[-219] rec[-217] rec[-216] rec[-215] rec[-58] +DETECTOR(11, 27, 0, 5) rec[-556] rec[-421] +DETECTOR(11, 28, 0, 0) rec[-685] rec[-59] +DETECTOR(11, 29, 0, 0) rec[-250] rec[-221] rec[-219] rec[-218] rec[-217] rec[-59] +DETECTOR(11, 29, 0, 3) rec[-555] rec[-422] +DETECTOR(11, 30, 0, 1) rec[-684] rec[-60] +DETECTOR(11, 31, 0, 1) rec[-252] rec[-222] rec[-221] rec[-220] rec[-219] rec[-60] +DETECTOR(11, 31, 0, 4) rec[-554] rec[-423] +DETECTOR(11, 32, 0, 2) rec[-61] +DETECTOR(11, 34, 0, 0) rec[-683] rec[-62] +DETECTOR(11, 35, 0, 0) rec[-258] rec[-256] rec[-222] rec[-63] rec[-62] +DETECTOR(11, 35, 0, 3) rec[-552] rec[-551] rec[-424] +DETECTOR(11, 36, 0, 1) rec[-63] +DETECTOR(13, 1, 0, 1) rec[-225] rec[-223] +DETECTOR(13, 1, 0, 4) rec[-425] +DETECTOR(13, 2, 0, 2) rec[-682] rec[-681] rec[-64] +DETECTOR(13, 3, 0, 2) rec[-261] rec[-227] rec[-225] rec[-224] rec[-223] rec[-64] +DETECTOR(13, 3, 0, 5) rec[-550] rec[-426] +DETECTOR(13, 4, 0, 0) rec[-680] rec[-65] +DETECTOR(13, 5, 0, 0) rec[-263] rec[-229] rec[-227] rec[-226] rec[-225] rec[-65] +DETECTOR(13, 5, 0, 3) rec[-549] rec[-427] +DETECTOR(13, 6, 0, 1) rec[-679] rec[-66] +DETECTOR(13, 7, 0, 1) rec[-265] rec[-231] rec[-229] rec[-228] rec[-227] rec[-66] +DETECTOR(13, 7, 0, 4) rec[-548] rec[-428] +DETECTOR(13, 8, 0, 2) rec[-678] rec[-67] +DETECTOR(13, 9, 0, 2) rec[-267] rec[-233] rec[-231] rec[-230] rec[-229] rec[-67] +DETECTOR(13, 9, 0, 5) rec[-547] rec[-429] +DETECTOR(13, 10, 0, 0) rec[-677] rec[-68] +DETECTOR(13, 11, 0, 0) rec[-269] rec[-235] rec[-233] rec[-232] rec[-231] rec[-68] +DETECTOR(13, 11, 0, 3) rec[-546] rec[-430] +DETECTOR(13, 12, 0, 1) rec[-676] rec[-69] +DETECTOR(13, 13, 0, 1) rec[-271] rec[-237] rec[-235] rec[-234] rec[-233] rec[-69] +DETECTOR(13, 13, 0, 4) rec[-545] rec[-431] +DETECTOR(13, 14, 0, 2) rec[-675] rec[-70] +DETECTOR(13, 15, 0, 2) rec[-273] rec[-239] rec[-237] rec[-236] rec[-235] rec[-70] +DETECTOR(13, 15, 0, 5) rec[-544] rec[-432] +DETECTOR(13, 16, 0, 0) rec[-674] rec[-71] +DETECTOR(13, 17, 0, 0) rec[-275] rec[-241] rec[-239] rec[-238] rec[-237] rec[-71] +DETECTOR(13, 17, 0, 3) rec[-543] rec[-433] +DETECTOR(13, 18, 0, 1) rec[-673] rec[-72] +DETECTOR(13, 19, 0, 1) rec[-277] rec[-243] rec[-241] rec[-240] rec[-239] rec[-72] +DETECTOR(13, 19, 0, 4) rec[-542] rec[-434] +DETECTOR(13, 20, 0, 2) rec[-672] rec[-73] +DETECTOR(13, 21, 0, 2) rec[-279] rec[-245] rec[-243] rec[-242] rec[-241] rec[-73] +DETECTOR(13, 21, 0, 5) rec[-541] rec[-435] +DETECTOR(13, 22, 0, 0) rec[-671] rec[-74] +DETECTOR(13, 23, 0, 0) rec[-281] rec[-247] rec[-245] rec[-244] rec[-243] rec[-74] +DETECTOR(13, 23, 0, 3) rec[-540] rec[-436] +DETECTOR(13, 24, 0, 1) rec[-670] rec[-75] +DETECTOR(13, 25, 0, 1) rec[-283] rec[-249] rec[-247] rec[-246] rec[-245] rec[-75] +DETECTOR(13, 25, 0, 4) rec[-539] rec[-437] +DETECTOR(13, 26, 0, 2) rec[-669] rec[-76] +DETECTOR(13, 27, 0, 2) rec[-285] rec[-251] rec[-249] rec[-248] rec[-247] rec[-76] +DETECTOR(13, 27, 0, 5) rec[-538] rec[-438] +DETECTOR(13, 28, 0, 0) rec[-668] rec[-77] +DETECTOR(13, 29, 0, 0) rec[-287] rec[-253] rec[-251] rec[-250] rec[-249] rec[-77] +DETECTOR(13, 29, 0, 3) rec[-537] rec[-439] +DETECTOR(13, 30, 0, 1) rec[-667] rec[-78] +DETECTOR(13, 31, 0, 1) rec[-289] rec[-255] rec[-253] rec[-252] rec[-251] rec[-78] +DETECTOR(13, 31, 0, 4) rec[-536] rec[-440] +DETECTOR(13, 32, 0, 2) rec[-666] rec[-664] rec[-79] +DETECTOR(13, 33, 0, 2) rec[-291] rec[-257] rec[-255] rec[-254] rec[-253] rec[-79] +DETECTOR(13, 33, 0, 5) rec[-535] rec[-441] +DETECTOR(13, 34, 0, 0) rec[-665] rec[-80] +DETECTOR(13, 35, 0, 0) rec[-292] rec[-259] rec[-257] rec[-256] rec[-255] rec[-80] +DETECTOR(13, 35, 0, 3) rec[-534] rec[-442] +DETECTOR(14, 33, 0, 2) rec[-292] rec[-291] rec[-290] +DETECTOR(14, 33, 0, 5) rec[-443] +DETECTOR(15, 1, 0, 1) rec[-262] rec[-260] +DETECTOR(15, 1, 0, 4) rec[-444] +DETECTOR(15, 2, 0, 2) rec[-663] rec[-662] rec[-81] +DETECTOR(15, 3, 0, 2) rec[-294] rec[-264] rec[-262] rec[-261] rec[-260] rec[-81] +DETECTOR(15, 3, 0, 5) rec[-533] rec[-445] +DETECTOR(15, 4, 0, 0) rec[-661] rec[-82] +DETECTOR(15, 5, 0, 0) rec[-296] rec[-266] rec[-264] rec[-263] rec[-262] rec[-82] +DETECTOR(15, 5, 0, 3) rec[-532] rec[-446] +DETECTOR(15, 6, 0, 1) rec[-660] rec[-83] +DETECTOR(15, 7, 0, 1) rec[-298] rec[-268] rec[-266] rec[-265] rec[-264] rec[-83] +DETECTOR(15, 7, 0, 4) rec[-531] rec[-447] +DETECTOR(15, 8, 0, 2) rec[-659] rec[-84] +DETECTOR(15, 9, 0, 2) rec[-300] rec[-270] rec[-268] rec[-267] rec[-266] rec[-84] +DETECTOR(15, 9, 0, 5) rec[-530] rec[-448] +DETECTOR(15, 10, 0, 0) rec[-658] rec[-85] +DETECTOR(15, 11, 0, 0) rec[-302] rec[-272] rec[-270] rec[-269] rec[-268] rec[-85] +DETECTOR(15, 11, 0, 3) rec[-529] rec[-449] +DETECTOR(15, 12, 0, 1) rec[-657] rec[-86] +DETECTOR(15, 13, 0, 1) rec[-304] rec[-274] rec[-272] rec[-271] rec[-270] rec[-86] +DETECTOR(15, 13, 0, 4) rec[-528] rec[-450] +DETECTOR(15, 14, 0, 2) rec[-656] rec[-87] +DETECTOR(15, 15, 0, 2) rec[-306] rec[-276] rec[-274] rec[-273] rec[-272] rec[-87] +DETECTOR(15, 15, 0, 5) rec[-527] rec[-451] +DETECTOR(15, 16, 0, 0) rec[-655] rec[-88] +DETECTOR(15, 17, 0, 0) rec[-308] rec[-278] rec[-276] rec[-275] rec[-274] rec[-88] +DETECTOR(15, 17, 0, 3) rec[-526] rec[-452] +DETECTOR(15, 18, 0, 1) rec[-654] rec[-89] +DETECTOR(15, 19, 0, 1) rec[-310] rec[-280] rec[-278] rec[-277] rec[-276] rec[-89] +DETECTOR(15, 19, 0, 4) rec[-525] rec[-453] +DETECTOR(15, 20, 0, 2) rec[-653] rec[-90] +DETECTOR(15, 21, 0, 2) rec[-312] rec[-282] rec[-280] rec[-279] rec[-278] rec[-90] +DETECTOR(15, 21, 0, 5) rec[-524] rec[-454] +DETECTOR(15, 22, 0, 0) rec[-652] rec[-91] +DETECTOR(15, 23, 0, 0) rec[-314] rec[-284] rec[-282] rec[-281] rec[-280] rec[-91] +DETECTOR(15, 23, 0, 3) rec[-523] rec[-455] +DETECTOR(15, 24, 0, 1) rec[-651] rec[-92] +DETECTOR(15, 25, 0, 1) rec[-316] rec[-286] rec[-284] rec[-283] rec[-282] rec[-92] +DETECTOR(15, 25, 0, 4) rec[-522] rec[-456] +DETECTOR(15, 26, 0, 2) rec[-650] rec[-648] rec[-93] +DETECTOR(15, 27, 0, 2) rec[-318] rec[-288] rec[-286] rec[-285] rec[-284] rec[-93] +DETECTOR(15, 27, 0, 5) rec[-521] rec[-457] +DETECTOR(15, 28, 0, 0) rec[-649] rec[-94] +DETECTOR(15, 29, 0, 0) rec[-319] rec[-290] rec[-288] rec[-287] rec[-286] rec[-94] +DETECTOR(15, 29, 0, 3) rec[-520] rec[-458] +DETECTOR(16, 27, 0, 2) rec[-319] rec[-318] rec[-317] +DETECTOR(16, 27, 0, 5) rec[-459] +DETECTOR(17, 1, 0, 1) rec[-295] rec[-293] +DETECTOR(17, 1, 0, 4) rec[-460] +DETECTOR(17, 2, 0, 2) rec[-647] rec[-646] rec[-95] +DETECTOR(17, 3, 0, 2) rec[-321] rec[-297] rec[-295] rec[-294] rec[-293] rec[-95] +DETECTOR(17, 3, 0, 5) rec[-519] rec[-461] +DETECTOR(17, 4, 0, 0) rec[-645] rec[-96] +DETECTOR(17, 5, 0, 0) rec[-323] rec[-299] rec[-297] rec[-296] rec[-295] rec[-96] +DETECTOR(17, 5, 0, 3) rec[-518] rec[-462] +DETECTOR(17, 6, 0, 1) rec[-644] rec[-97] +DETECTOR(17, 7, 0, 1) rec[-325] rec[-301] rec[-299] rec[-298] rec[-297] rec[-97] +DETECTOR(17, 7, 0, 4) rec[-517] rec[-463] +DETECTOR(17, 8, 0, 2) rec[-643] rec[-98] +DETECTOR(17, 9, 0, 2) rec[-327] rec[-303] rec[-301] rec[-300] rec[-299] rec[-98] +DETECTOR(17, 9, 0, 5) rec[-516] rec[-464] +DETECTOR(17, 10, 0, 0) rec[-642] rec[-99] +DETECTOR(17, 11, 0, 0) rec[-329] rec[-305] rec[-303] rec[-302] rec[-301] rec[-99] +DETECTOR(17, 11, 0, 3) rec[-515] rec[-465] +DETECTOR(17, 12, 0, 1) rec[-641] rec[-100] +DETECTOR(17, 13, 0, 1) rec[-331] rec[-307] rec[-305] rec[-304] rec[-303] rec[-100] +DETECTOR(17, 13, 0, 4) rec[-514] rec[-466] +DETECTOR(17, 14, 0, 2) rec[-640] rec[-101] +DETECTOR(17, 15, 0, 2) rec[-333] rec[-309] rec[-307] rec[-306] rec[-305] rec[-101] +DETECTOR(17, 15, 0, 5) rec[-513] rec[-467] +DETECTOR(17, 16, 0, 0) rec[-639] rec[-102] +DETECTOR(17, 17, 0, 0) rec[-335] rec[-311] rec[-309] rec[-308] rec[-307] rec[-102] +DETECTOR(17, 17, 0, 3) rec[-512] rec[-468] +DETECTOR(17, 18, 0, 1) rec[-638] rec[-103] +DETECTOR(17, 19, 0, 1) rec[-337] rec[-313] rec[-311] rec[-310] rec[-309] rec[-103] +DETECTOR(17, 19, 0, 4) rec[-511] rec[-469] +DETECTOR(17, 20, 0, 2) rec[-637] rec[-635] rec[-104] +DETECTOR(17, 21, 0, 2) rec[-339] rec[-315] rec[-313] rec[-312] rec[-311] rec[-104] +DETECTOR(17, 21, 0, 5) rec[-510] rec[-470] +DETECTOR(17, 22, 0, 0) rec[-636] rec[-105] +DETECTOR(17, 23, 0, 0) rec[-340] rec[-317] rec[-315] rec[-314] rec[-313] rec[-105] +DETECTOR(17, 23, 0, 3) rec[-509] rec[-471] +DETECTOR(18, 21, 0, 2) rec[-340] rec[-339] rec[-338] +DETECTOR(18, 21, 0, 5) rec[-472] +DETECTOR(19, 1, 0, 1) rec[-322] rec[-320] +DETECTOR(19, 1, 0, 4) rec[-473] +DETECTOR(19, 2, 0, 2) rec[-634] rec[-633] rec[-106] +DETECTOR(19, 3, 0, 2) rec[-342] rec[-324] rec[-322] rec[-321] rec[-320] rec[-106] +DETECTOR(19, 3, 0, 5) rec[-508] rec[-474] +DETECTOR(19, 4, 0, 0) rec[-632] rec[-107] +DETECTOR(19, 5, 0, 0) rec[-344] rec[-326] rec[-324] rec[-323] rec[-322] rec[-107] +DETECTOR(19, 5, 0, 3) rec[-507] rec[-475] +DETECTOR(19, 6, 0, 1) rec[-631] rec[-108] +DETECTOR(19, 7, 0, 1) rec[-346] rec[-328] rec[-326] rec[-325] rec[-324] rec[-108] +DETECTOR(19, 7, 0, 4) rec[-506] rec[-476] +DETECTOR(19, 8, 0, 2) rec[-630] rec[-109] +DETECTOR(19, 9, 0, 2) rec[-348] rec[-330] rec[-328] rec[-327] rec[-326] rec[-109] +DETECTOR(19, 9, 0, 5) rec[-505] rec[-477] +DETECTOR(19, 10, 0, 0) rec[-629] rec[-110] +DETECTOR(19, 11, 0, 0) rec[-350] rec[-332] rec[-330] rec[-329] rec[-328] rec[-110] +DETECTOR(19, 11, 0, 3) rec[-504] rec[-478] +DETECTOR(19, 12, 0, 1) rec[-628] rec[-111] +DETECTOR(19, 13, 0, 1) rec[-352] rec[-334] rec[-332] rec[-331] rec[-330] rec[-111] +DETECTOR(19, 13, 0, 4) rec[-503] rec[-479] +DETECTOR(19, 14, 0, 2) rec[-627] rec[-625] rec[-112] +DETECTOR(19, 15, 0, 2) rec[-354] rec[-336] rec[-334] rec[-333] rec[-332] rec[-112] +DETECTOR(19, 15, 0, 5) rec[-502] rec[-480] +DETECTOR(19, 16, 0, 0) rec[-626] rec[-113] +DETECTOR(19, 17, 0, 0) rec[-355] rec[-338] rec[-336] rec[-335] rec[-334] rec[-113] +DETECTOR(19, 17, 0, 3) rec[-501] rec[-481] +DETECTOR(20, 15, 0, 2) rec[-355] rec[-354] rec[-353] +DETECTOR(20, 15, 0, 5) rec[-482] +DETECTOR(21, 1, 0, 1) rec[-343] rec[-341] +DETECTOR(21, 1, 0, 4) rec[-483] +DETECTOR(21, 2, 0, 2) rec[-624] rec[-623] rec[-114] +DETECTOR(21, 3, 0, 2) rec[-357] rec[-345] rec[-343] rec[-342] rec[-341] rec[-114] +DETECTOR(21, 3, 0, 5) rec[-500] rec[-484] +DETECTOR(21, 4, 0, 0) rec[-622] rec[-115] +DETECTOR(21, 5, 0, 0) rec[-359] rec[-347] rec[-345] rec[-344] rec[-343] rec[-115] +DETECTOR(21, 5, 0, 3) rec[-499] rec[-485] +DETECTOR(21, 6, 0, 1) rec[-621] rec[-116] +DETECTOR(21, 7, 0, 1) rec[-361] rec[-349] rec[-347] rec[-346] rec[-345] rec[-116] +DETECTOR(21, 7, 0, 4) rec[-498] rec[-486] +DETECTOR(21, 8, 0, 2) rec[-620] rec[-618] rec[-117] +DETECTOR(21, 9, 0, 2) rec[-363] rec[-351] rec[-349] rec[-348] rec[-347] rec[-117] +DETECTOR(21, 9, 0, 5) rec[-497] rec[-487] +DETECTOR(21, 10, 0, 0) rec[-619] rec[-118] +DETECTOR(21, 11, 0, 0) rec[-364] rec[-353] rec[-351] rec[-350] rec[-349] rec[-118] +DETECTOR(21, 11, 0, 3) rec[-496] rec[-488] +DETECTOR(22, 9, 0, 2) rec[-364] rec[-363] rec[-362] +DETECTOR(22, 9, 0, 5) rec[-489] +DETECTOR(23, 1, 0, 1) rec[-358] rec[-356] +DETECTOR(23, 1, 0, 4) rec[-490] +DETECTOR(23, 2, 0, 2) rec[-617] rec[-616] rec[-614] rec[-119] +DETECTOR(23, 3, 0, 2) rec[-366] rec[-360] rec[-358] rec[-357] rec[-356] rec[-119] +DETECTOR(23, 3, 0, 5) rec[-495] rec[-491] +DETECTOR(23, 4, 0, 0) rec[-615] rec[-120] +DETECTOR(23, 5, 0, 0) rec[-367] rec[-362] rec[-360] rec[-359] rec[-358] rec[-120] +DETECTOR(23, 5, 0, 3) rec[-494] rec[-492] +DETECTOR(24, 3, 0, 2) rec[-367] rec[-366] rec[-365] +DETECTOR(24, 3, 0, 5) rec[-493] +OBSERVABLE_INCLUDE(0) rec[-367] rec[-365] rec[-364] rec[-362] rec[-360] rec[-358] rec[-356] rec[-355] rec[-353] rec[-351] rec[-349] rec[-347] rec[-345] rec[-343] rec[-341] rec[-340] rec[-338] rec[-336] rec[-334] rec[-332] rec[-330] rec[-328] rec[-326] rec[-324] rec[-322] rec[-320] rec[-319] rec[-317] rec[-315] rec[-313] rec[-311] rec[-309] rec[-307] rec[-305] rec[-303] rec[-301] rec[-299] rec[-297] rec[-295] rec[-293] rec[-292] rec[-290] rec[-288] rec[-286] rec[-284] rec[-282] rec[-280] rec[-278] rec[-276] rec[-274] rec[-272] rec[-270] rec[-268] rec[-266] rec[-264] rec[-262] rec[-260] rec[-259] rec[-258] rec[-257] rec[-255] rec[-253] rec[-251] rec[-249] rec[-247] rec[-245] rec[-243] rec[-241] rec[-239] rec[-237] rec[-235] rec[-233] rec[-231] rec[-229] rec[-227] rec[-225] rec[-223] rec[-222] rec[-221] rec[-220] rec[-219] rec[-217] rec[-215] rec[-213] rec[-211] rec[-209] rec[-207] rec[-205] rec[-203] rec[-201] rec[-199] rec[-197] rec[-195] rec[-193] rec[-191] rec[-190] rec[-189] rec[-188] rec[-187] rec[-185] rec[-183] rec[-181] rec[-179] rec[-177] rec[-175] rec[-173] rec[-171] rec[-169] rec[-167] rec[-165] rec[-164] rec[-163] rec[-162] rec[-161] rec[-159] rec[-157] rec[-155] rec[-153] rec[-151] rec[-149] rec[-147] rec[-145] rec[-144] rec[-143] rec[-142] rec[-141] rec[-139] rec[-137] rec[-135] rec[-133] rec[-131] rec[-130] rec[-129] rec[-128] rec[-127] rec[-125] rec[-123] rec[-122] rec[-121] rec[-63] rec[-45] rec[-30] rec[-18] rec[-9] rec[-3] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 491 488 486 484 482 473 471 469 467 465 463 461 446 444 442 440 438 436 434 432 430 428 407 405 403 401 399 397 395 393 391 389 387 385 383 356 354 352 350 348 346 344 342 340 338 336 334 332 330 328 326 293 291 289 287 285 283 281 279 277 275 273 271 269 267 265 263 261 259 220 216 214 212 210 208 206 204 202 200 198 196 194 192 190 188 186 153 149 147 145 143 141 139 137 135 133 131 129 127 125 98 94 92 90 88 86 84 82 80 78 76 55 51 49 47 45 43 41 39 24 20 18 16 14 5 1 492 490 489 483 481 480 479 478 477 476 475 474 462 460 459 458 457 456 455 454 453 452 451 450 449 448 447 429 427 426 425 424 423 422 421 420 419 418 417 416 415 414 413 412 411 410 409 408 384 382 381 380 379 378 377 376 375 374 373 372 371 370 369 368 367 366 365 364 363 362 361 360 359 358 357 327 325 324 323 322 321 320 319 318 317 316 315 314 313 312 311 310 309 308 307 306 305 304 303 302 301 300 299 298 297 296 295 294 258 257 256 255 254 253 252 251 250 249 248 247 246 245 244 243 242 241 240 239 238 237 236 235 234 233 232 231 230 229 228 227 226 225 224 223 222 218 185 184 183 182 181 180 179 178 177 176 175 174 173 172 171 170 169 168 167 166 165 164 163 162 161 160 159 158 157 156 155 151 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 96 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 53 38 37 36 35 34 33 32 31 30 29 28 27 26 22 13 12 11 10 9 8 7 3 0 487 485 472 470 468 466 464 445 443 441 439 437 435 433 431 406 404 402 400 398 396 394 392 390 388 386 355 353 351 349 347 345 343 341 339 337 335 333 331 329 292 290 288 286 284 282 280 278 276 274 272 270 268 266 264 262 260 221 219 217 215 213 211 209 207 205 203 201 199 197 195 193 191 189 187 154 152 150 148 146 144 142 140 138 136 134 132 130 128 126 99 97 95 93 91 89 87 85 83 81 79 77 56 54 52 50 48 46 44 42 40 25 23 21 19 17 15 6 4 2 diff --git a/test_data/midout_color_code_d5_r10_p1000.stim b/test_data/midout_color_code_d5_r10_p1000.stim new file mode 100644 index 0000000..a6dc63a --- /dev/null +++ b/test_data/midout_color_code_d5_r10_p1000.stim @@ -0,0 +1,311 @@ +QUBIT_COORDS(0, 1) 0 +QUBIT_COORDS(1, 1) 1 +QUBIT_COORDS(1, 2) 2 +QUBIT_COORDS(1, 3) 3 +QUBIT_COORDS(1, 4) 4 +QUBIT_COORDS(1, 5) 5 +QUBIT_COORDS(1, 6) 6 +QUBIT_COORDS(2, 1) 7 +QUBIT_COORDS(2, 2) 8 +QUBIT_COORDS(2, 3) 9 +QUBIT_COORDS(2, 4) 10 +QUBIT_COORDS(2, 5) 11 +QUBIT_COORDS(2, 6) 12 +QUBIT_COORDS(2, 7) 13 +QUBIT_COORDS(3, 1) 14 +QUBIT_COORDS(3, 2) 15 +QUBIT_COORDS(3, 3) 16 +QUBIT_COORDS(3, 4) 17 +QUBIT_COORDS(3, 5) 18 +QUBIT_COORDS(4, 1) 19 +QUBIT_COORDS(4, 2) 20 +QUBIT_COORDS(4, 3) 21 +QUBIT_COORDS(4, 4) 22 +RX 2 4 6 15 17 0 3 7 8 9 10 11 12 13 19 20 22 +R 1 5 14 16 18 21 +X_ERROR(0.001) 1 5 14 16 18 21 +Z_ERROR(0.001) 2 4 6 15 17 0 3 7 8 9 10 11 12 13 19 20 22 +TICK +CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 15 20 17 22 +DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 15 20 17 22 +DEPOLARIZE1(0.001) 3 5 13 19 21 +TICK +CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 20 19 22 21 +DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 20 19 22 21 +DEPOLARIZE1(0.001) 0 13 18 +TICK +CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 21 20 +DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 21 20 +DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 +TICK +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 +DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 +DEPOLARIZE1(0.001) 0 13 18 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 +DEPOLARIZE1(0.001) 3 5 13 19 21 +TICK +MX(0.001) 1 5 14 16 18 21 +M(0.001) 2 4 6 15 17 +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 1 5 14 16 18 21 2 4 6 15 17 0 3 7 8 9 10 11 12 13 19 20 22 +TICK +RX 1 5 14 16 18 21 +R 2 4 6 15 17 +OBSERVABLE_INCLUDE(0) rec[-9] rec[-11] +X_ERROR(0.001) 2 4 6 15 17 +Z_ERROR(0.001) 1 5 14 16 18 21 +DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 19 20 22 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 +DEPOLARIZE1(0.001) 3 5 13 19 21 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 +DEPOLARIZE1(0.001) 0 13 18 +TICK +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 +DETECTOR(1, 1, 0, 1) rec[-11] +DETECTOR(1, 5, 0, 0) rec[-10] +DETECTOR(3, 1, 0, 1) rec[-9] +DETECTOR(3, 3, 0, 2) rec[-8] +DETECTOR(3, 5, 0, 0) rec[-7] +DETECTOR(4, 3, 0, 2) rec[-6] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 +DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 +TICK +CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 21 20 +DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 21 20 +DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 +TICK +CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 20 19 22 21 +DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 20 19 22 21 +DEPOLARIZE1(0.001) 0 13 18 +TICK +CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 15 20 17 22 +DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 15 20 17 22 +DEPOLARIZE1(0.001) 3 5 13 19 21 +TICK +MX(0.001) 2 4 6 15 17 +M(0.001) 1 5 14 16 18 21 +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 2 4 6 15 17 1 5 14 16 18 21 0 3 7 8 9 10 11 12 13 19 20 22 +TICK +RX 2 4 6 15 17 +R 1 5 14 16 18 21 +OBSERVABLE_INCLUDE(0) rec[-9] +X_ERROR(0.001) 1 5 14 16 18 21 +Z_ERROR(0.001) 2 4 6 15 17 +DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 19 20 22 +TICK +CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 15 20 17 22 +DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 15 20 17 22 +DEPOLARIZE1(0.001) 3 5 13 19 21 +TICK +CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 20 19 22 21 +DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 20 19 22 21 +DEPOLARIZE1(0.001) 0 13 18 +TICK +CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 21 20 +DETECTOR(1, 1, 0, 4) rec[-6] +DETECTOR(1, 2, 0, 2) rec[-22] rec[-11] +DETECTOR(1, 4, 0, 0) rec[-21] rec[-10] +DETECTOR(1, 5, 0, 3) rec[-15] rec[-14] rec[-5] +DETECTOR(1, 6, 0, 1) rec[-9] +DETECTOR(3, 1, 0, 4) rec[-4] +DETECTOR(3, 2, 0, 2) rec[-20] rec[-19] rec[-17] rec[-8] +DETECTOR(3, 3, 0, 5) rec[-13] rec[-3] +DETECTOR(3, 4, 0, 0) rec[-18] rec[-7] +DETECTOR(3, 5, 0, 3) rec[-12] rec[-2] +DETECTOR(4, 3, 0, 5) rec[-1] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 21 20 +DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 +TICK +REPEAT 3 { + CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 + DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 + DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 + TICK + CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 + DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 + DEPOLARIZE1(0.001) 0 13 18 + TICK + CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 + DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 + DEPOLARIZE1(0.001) 3 5 13 19 21 + TICK + MX(0.001) 1 5 14 16 18 21 + M(0.001) 2 4 6 15 17 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 1 5 14 16 18 21 2 4 6 15 17 0 3 7 8 9 10 11 12 13 19 20 22 + TICK + RX 1 5 14 16 18 21 + R 2 4 6 15 17 + OBSERVABLE_INCLUDE(0) rec[-9] rec[-11] + X_ERROR(0.001) 2 4 6 15 17 + Z_ERROR(0.001) 1 5 14 16 18 21 + DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 19 20 22 + TICK + CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 + DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 + DEPOLARIZE1(0.001) 3 5 13 19 21 + TICK + CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 + DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 + DEPOLARIZE1(0.001) 0 13 18 + TICK + CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 + DETECTOR(1, 1, 0, 1) rec[-11] + DETECTOR(1, 2, 0, 5) rec[-17] rec[-5] + DETECTOR(1, 4, 0, 3) rec[-16] rec[-4] + DETECTOR(1, 5, 0, 0) rec[-21] rec[-20] rec[-10] + DETECTOR(1, 6, 0, 4) rec[-3] + DETECTOR(3, 1, 0, 1) rec[-9] + DETECTOR(3, 2, 0, 5) rec[-15] rec[-14] rec[-12] rec[-2] + DETECTOR(3, 3, 0, 2) rec[-19] rec[-8] + DETECTOR(3, 4, 0, 3) rec[-13] rec[-1] + DETECTOR(3, 5, 0, 0) rec[-18] rec[-7] + DETECTOR(4, 3, 0, 2) rec[-6] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 + DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 + TICK + CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 21 20 + DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 21 20 + DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 + TICK + CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 20 19 22 21 + DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 20 19 22 21 + DEPOLARIZE1(0.001) 0 13 18 + TICK + CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 15 20 17 22 + DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 15 20 17 22 + DEPOLARIZE1(0.001) 3 5 13 19 21 + TICK + MX(0.001) 2 4 6 15 17 + M(0.001) 1 5 14 16 18 21 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 2 4 6 15 17 1 5 14 16 18 21 0 3 7 8 9 10 11 12 13 19 20 22 + TICK + RX 2 4 6 15 17 + R 1 5 14 16 18 21 + OBSERVABLE_INCLUDE(0) rec[-9] + X_ERROR(0.001) 1 5 14 16 18 21 + Z_ERROR(0.001) 2 4 6 15 17 + DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 19 20 22 + TICK + CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 15 20 17 22 + DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 15 20 17 22 + DEPOLARIZE1(0.001) 3 5 13 19 21 + TICK + CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 20 19 22 21 + DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 20 19 22 21 + DEPOLARIZE1(0.001) 0 13 18 + TICK + CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 21 20 + DETECTOR(1, 1, 0, 4) rec[-6] + DETECTOR(1, 2, 0, 2) rec[-22] rec[-11] + DETECTOR(1, 4, 0, 0) rec[-21] rec[-10] + DETECTOR(1, 5, 0, 3) rec[-15] rec[-14] rec[-5] + DETECTOR(1, 6, 0, 1) rec[-9] + DETECTOR(3, 1, 0, 4) rec[-4] + DETECTOR(3, 2, 0, 2) rec[-20] rec[-19] rec[-17] rec[-8] + DETECTOR(3, 3, 0, 5) rec[-13] rec[-3] + DETECTOR(3, 4, 0, 0) rec[-18] rec[-7] + DETECTOR(3, 5, 0, 3) rec[-12] rec[-2] + DETECTOR(4, 3, 0, 5) rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 21 20 + DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 + TICK +} +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 +DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 +DEPOLARIZE1(0.001) 0 13 18 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 +DEPOLARIZE1(0.001) 3 5 13 19 21 +TICK +MX(0.001) 1 5 14 16 18 21 +M(0.001) 2 4 6 15 17 +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 1 5 14 16 18 21 2 4 6 15 17 0 3 7 8 9 10 11 12 13 19 20 22 +TICK +RX 1 5 14 16 18 21 +R 2 4 6 15 17 +OBSERVABLE_INCLUDE(0) rec[-9] rec[-11] +X_ERROR(0.001) 2 4 6 15 17 +Z_ERROR(0.001) 1 5 14 16 18 21 +DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 19 20 22 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 15 22 17 +DEPOLARIZE1(0.001) 3 5 13 19 21 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 19 20 21 22 +DEPOLARIZE1(0.001) 0 13 18 +TICK +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 +DETECTOR(1, 1, 0, 1) rec[-11] +DETECTOR(1, 2, 0, 5) rec[-17] rec[-5] +DETECTOR(1, 4, 0, 3) rec[-16] rec[-4] +DETECTOR(1, 5, 0, 0) rec[-21] rec[-20] rec[-10] +DETECTOR(1, 6, 0, 4) rec[-3] +DETECTOR(3, 1, 0, 1) rec[-9] +DETECTOR(3, 2, 0, 5) rec[-15] rec[-14] rec[-12] rec[-2] +DETECTOR(3, 3, 0, 2) rec[-19] rec[-8] +DETECTOR(3, 4, 0, 3) rec[-13] rec[-1] +DETECTOR(3, 5, 0, 0) rec[-18] rec[-7] +DETECTOR(4, 3, 0, 2) rec[-6] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 20 21 +DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 +TICK +CX 21 20 18 17 16 15 13 12 11 10 9 8 5 4 3 2 +DEPOLARIZE2(0.001) 21 20 18 17 16 15 13 12 11 10 9 8 5 4 3 2 +DEPOLARIZE1(0.001) 0 1 6 7 14 19 22 +TICK +CX 22 21 20 19 17 16 15 14 12 11 10 9 8 7 6 5 4 3 2 1 +DEPOLARIZE2(0.001) 22 21 20 19 17 16 15 14 12 11 10 9 8 7 6 5 4 3 2 1 +DEPOLARIZE1(0.001) 0 13 18 +TICK +CX 17 22 15 20 11 18 9 16 7 14 6 12 4 10 2 8 0 1 +DEPOLARIZE2(0.001) 17 22 15 20 11 18 9 16 7 14 6 12 4 10 2 8 0 1 +DEPOLARIZE1(0.001) 3 5 13 19 21 +TICK +M(0.001) 21 18 16 14 5 1 +MX(0.001) 22 20 19 13 12 11 10 9 8 7 3 0 17 15 6 4 2 +DETECTOR(1, 1, 0, 1) rec[-7] rec[-6] +DETECTOR(1, 1, 0, 4) rec[-18] +DETECTOR(1, 2, 0, 2) rec[-34] rec[-1] +DETECTOR(1, 4, 0, 0) rec[-33] rec[-2] +DETECTOR(1, 5, 0, 0) rec[-13] rec[-11] rec[-7] rec[-3] rec[-2] +DETECTOR(1, 5, 0, 3) rec[-27] rec[-26] rec[-19] +DETECTOR(1, 6, 0, 1) rec[-3] +DETECTOR(3, 1, 0, 1) rec[-10] rec[-8] +DETECTOR(3, 1, 0, 4) rec[-20] +DETECTOR(3, 2, 0, 2) rec[-32] rec[-31] rec[-29] rec[-4] +DETECTOR(3, 3, 0, 2) rec[-16] rec[-12] rec[-10] rec[-9] rec[-8] rec[-4] +DETECTOR(3, 3, 0, 5) rec[-25] rec[-21] +DETECTOR(3, 4, 0, 0) rec[-30] rec[-5] +DETECTOR(3, 5, 0, 0) rec[-17] rec[-14] rec[-12] rec[-11] rec[-10] rec[-5] +DETECTOR(3, 5, 0, 3) rec[-24] rec[-22] +DETECTOR(4, 3, 0, 2) rec[-17] rec[-16] rec[-15] +DETECTOR(4, 3, 0, 5) rec[-23] +OBSERVABLE_INCLUDE(0) rec[-17] rec[-15] rec[-14] rec[-13] rec[-12] rec[-10] rec[-8] rec[-7] rec[-6] rec[-3] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 21 18 16 14 5 1 22 20 19 13 12 11 10 9 8 7 3 0 17 15 6 4 2 diff --git a/test_data/midout_color_code_d9_r36_p1000.stim b/test_data/midout_color_code_d9_r36_p1000.stim new file mode 100644 index 0000000..dcd511d --- /dev/null +++ b/test_data/midout_color_code_d9_r36_p1000.stim @@ -0,0 +1,496 @@ +QUBIT_COORDS(0, 1) 0 +QUBIT_COORDS(1, 1) 1 +QUBIT_COORDS(1, 2) 2 +QUBIT_COORDS(1, 3) 3 +QUBIT_COORDS(1, 4) 4 +QUBIT_COORDS(1, 5) 5 +QUBIT_COORDS(1, 6) 6 +QUBIT_COORDS(2, 1) 7 +QUBIT_COORDS(2, 2) 8 +QUBIT_COORDS(2, 3) 9 +QUBIT_COORDS(2, 4) 10 +QUBIT_COORDS(2, 5) 11 +QUBIT_COORDS(2, 6) 12 +QUBIT_COORDS(2, 7) 13 +QUBIT_COORDS(3, 1) 14 +QUBIT_COORDS(3, 2) 15 +QUBIT_COORDS(3, 3) 16 +QUBIT_COORDS(3, 4) 17 +QUBIT_COORDS(3, 5) 18 +QUBIT_COORDS(3, 6) 19 +QUBIT_COORDS(3, 7) 20 +QUBIT_COORDS(3, 8) 21 +QUBIT_COORDS(3, 9) 22 +QUBIT_COORDS(3, 10) 23 +QUBIT_COORDS(3, 11) 24 +QUBIT_COORDS(3, 12) 25 +QUBIT_COORDS(4, 1) 26 +QUBIT_COORDS(4, 2) 27 +QUBIT_COORDS(4, 3) 28 +QUBIT_COORDS(4, 4) 29 +QUBIT_COORDS(4, 5) 30 +QUBIT_COORDS(4, 6) 31 +QUBIT_COORDS(4, 7) 32 +QUBIT_COORDS(4, 8) 33 +QUBIT_COORDS(4, 9) 34 +QUBIT_COORDS(4, 10) 35 +QUBIT_COORDS(4, 11) 36 +QUBIT_COORDS(4, 12) 37 +QUBIT_COORDS(4, 13) 38 +QUBIT_COORDS(5, 1) 39 +QUBIT_COORDS(5, 2) 40 +QUBIT_COORDS(5, 3) 41 +QUBIT_COORDS(5, 4) 42 +QUBIT_COORDS(5, 5) 43 +QUBIT_COORDS(5, 6) 44 +QUBIT_COORDS(5, 7) 45 +QUBIT_COORDS(5, 8) 46 +QUBIT_COORDS(5, 9) 47 +QUBIT_COORDS(5, 10) 48 +QUBIT_COORDS(5, 11) 49 +QUBIT_COORDS(6, 1) 50 +QUBIT_COORDS(6, 2) 51 +QUBIT_COORDS(6, 3) 52 +QUBIT_COORDS(6, 4) 53 +QUBIT_COORDS(6, 5) 54 +QUBIT_COORDS(6, 6) 55 +QUBIT_COORDS(6, 7) 56 +QUBIT_COORDS(6, 8) 57 +QUBIT_COORDS(6, 9) 58 +QUBIT_COORDS(6, 10) 59 +QUBIT_COORDS(7, 1) 60 +QUBIT_COORDS(7, 2) 61 +QUBIT_COORDS(7, 3) 62 +QUBIT_COORDS(7, 4) 63 +QUBIT_COORDS(7, 5) 64 +QUBIT_COORDS(8, 1) 65 +QUBIT_COORDS(8, 2) 66 +QUBIT_COORDS(8, 3) 67 +QUBIT_COORDS(8, 4) 68 +RX 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 +R 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 +X_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 +Z_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 +TICK +CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 40 51 42 53 44 55 46 57 48 59 50 60 52 62 54 64 61 66 63 68 +DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 40 51 42 53 44 55 46 57 48 59 50 60 52 62 54 64 61 66 63 68 +DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 +TICK +CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 51 50 53 52 55 54 57 56 59 58 61 60 63 62 66 65 68 67 +DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 51 50 53 52 55 54 57 56 59 58 61 60 63 62 66 65 68 67 +DEPOLARIZE1(0.001) 0 13 38 49 64 +TICK +CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 52 51 54 53 56 55 58 57 62 61 64 63 67 66 +DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 52 51 54 53 56 55 58 57 62 61 64 63 67 66 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 +TICK +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 +DEPOLARIZE1(0.001) 0 13 38 49 64 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 +DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 +TICK +MX(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 +M(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 +TICK +RX 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 +R 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 +OBSERVABLE_INCLUDE(0) rec[-20] rec[-27] rec[-32] rec[-34] +X_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 +Z_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 +DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 +DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 +DEPOLARIZE1(0.001) 0 13 38 49 64 +TICK +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 +DETECTOR(1, 1, 0, 1) rec[-34] +DETECTOR(1, 5, 0, 0) rec[-33] +DETECTOR(3, 1, 0, 1) rec[-32] +DETECTOR(3, 3, 0, 2) rec[-31] +DETECTOR(3, 5, 0, 0) rec[-30] +DETECTOR(3, 7, 0, 1) rec[-29] +DETECTOR(3, 11, 0, 0) rec[-28] +DETECTOR(5, 1, 0, 1) rec[-27] +DETECTOR(5, 3, 0, 2) rec[-26] +DETECTOR(5, 5, 0, 0) rec[-25] +DETECTOR(5, 7, 0, 1) rec[-24] +DETECTOR(5, 9, 0, 2) rec[-23] +DETECTOR(5, 11, 0, 0) rec[-22] +DETECTOR(6, 9, 0, 2) rec[-21] +DETECTOR(7, 1, 0, 1) rec[-20] +DETECTOR(7, 3, 0, 2) rec[-19] +DETECTOR(7, 5, 0, 0) rec[-18] +DETECTOR(8, 3, 0, 2) rec[-17] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 +TICK +CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 52 51 54 53 56 55 58 57 62 61 64 63 67 66 +DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 52 51 54 53 56 55 58 57 62 61 64 63 67 66 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 +TICK +CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 51 50 53 52 55 54 57 56 59 58 61 60 63 62 66 65 68 67 +DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 51 50 53 52 55 54 57 56 59 58 61 60 63 62 66 65 68 67 +DEPOLARIZE1(0.001) 0 13 38 49 64 +TICK +CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 40 51 42 53 44 55 46 57 48 59 50 60 52 62 54 64 61 66 63 68 +DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 40 51 42 53 44 55 46 57 48 59 50 60 52 62 54 64 61 66 63 68 +DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 +TICK +MX(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 +M(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 +TICK +RX 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 +R 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 +OBSERVABLE_INCLUDE(0) rec[-26] rec[-32] +X_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 +Z_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 +DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 +TICK +CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 40 51 42 53 44 55 46 57 48 59 50 60 52 62 54 64 61 66 63 68 +DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 40 51 42 53 44 55 46 57 48 59 50 60 52 62 54 64 61 66 63 68 +DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 +TICK +CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 51 50 53 52 55 54 57 56 59 58 61 60 63 62 66 65 68 67 +DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 51 50 53 52 55 54 57 56 59 58 61 60 63 62 66 65 68 67 +DEPOLARIZE1(0.001) 0 13 38 49 64 +TICK +CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 52 51 54 53 56 55 58 57 62 61 64 63 67 66 +DETECTOR(1, 1, 0, 4) rec[-18] +DETECTOR(1, 2, 0, 2) rec[-68] rec[-34] +DETECTOR(1, 4, 0, 0) rec[-67] rec[-33] +DETECTOR(1, 5, 0, 3) rec[-49] rec[-48] rec[-17] +DETECTOR(1, 6, 0, 1) rec[-32] +DETECTOR(3, 1, 0, 4) rec[-16] +DETECTOR(3, 2, 0, 2) rec[-66] rec[-65] rec[-31] +DETECTOR(3, 3, 0, 5) rec[-47] rec[-15] +DETECTOR(3, 4, 0, 0) rec[-64] rec[-30] +DETECTOR(3, 5, 0, 3) rec[-46] rec[-14] +DETECTOR(3, 6, 0, 1) rec[-63] rec[-29] +DETECTOR(3, 7, 0, 4) rec[-45] rec[-13] +DETECTOR(3, 8, 0, 2) rec[-28] +DETECTOR(3, 10, 0, 0) rec[-62] rec[-27] +DETECTOR(3, 11, 0, 3) rec[-43] rec[-42] rec[-12] +DETECTOR(3, 12, 0, 1) rec[-26] +DETECTOR(5, 1, 0, 4) rec[-11] +DETECTOR(5, 2, 0, 2) rec[-61] rec[-60] rec[-25] +DETECTOR(5, 3, 0, 5) rec[-41] rec[-10] +DETECTOR(5, 4, 0, 0) rec[-59] rec[-24] +DETECTOR(5, 5, 0, 3) rec[-40] rec[-9] +DETECTOR(5, 6, 0, 1) rec[-58] rec[-23] +DETECTOR(5, 7, 0, 4) rec[-39] rec[-8] +DETECTOR(5, 8, 0, 2) rec[-57] rec[-55] rec[-22] +DETECTOR(5, 9, 0, 5) rec[-38] rec[-7] +DETECTOR(5, 10, 0, 0) rec[-56] rec[-21] +DETECTOR(5, 11, 0, 3) rec[-37] rec[-6] +DETECTOR(6, 9, 0, 5) rec[-5] +DETECTOR(7, 1, 0, 4) rec[-4] +DETECTOR(7, 2, 0, 2) rec[-54] rec[-53] rec[-51] rec[-20] +DETECTOR(7, 3, 0, 5) rec[-36] rec[-3] +DETECTOR(7, 4, 0, 0) rec[-52] rec[-19] +DETECTOR(7, 5, 0, 3) rec[-35] rec[-2] +DETECTOR(8, 3, 0, 5) rec[-1] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 52 51 54 53 56 55 58 57 62 61 64 63 67 66 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 +TICK +REPEAT 16 { + CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 + DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 + DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 + TICK + CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 + DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 + DEPOLARIZE1(0.001) 0 13 38 49 64 + TICK + CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 + DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 + DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 + TICK + MX(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 + M(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 + TICK + RX 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 + R 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 + OBSERVABLE_INCLUDE(0) rec[-20] rec[-27] rec[-32] rec[-34] + X_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 + Z_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 + DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 + TICK + CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 + DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 + DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 + TICK + CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 + DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 + DEPOLARIZE1(0.001) 0 13 38 49 64 + TICK + CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 + DETECTOR(1, 1, 0, 1) rec[-34] + DETECTOR(1, 2, 0, 5) rec[-52] rec[-16] + DETECTOR(1, 4, 0, 3) rec[-51] rec[-15] + DETECTOR(1, 5, 0, 0) rec[-67] rec[-66] rec[-33] + DETECTOR(1, 6, 0, 4) rec[-14] + DETECTOR(3, 1, 0, 1) rec[-32] + DETECTOR(3, 2, 0, 5) rec[-50] rec[-49] rec[-13] + DETECTOR(3, 3, 0, 2) rec[-65] rec[-31] + DETECTOR(3, 4, 0, 3) rec[-48] rec[-12] + DETECTOR(3, 5, 0, 0) rec[-64] rec[-30] + DETECTOR(3, 6, 0, 4) rec[-47] rec[-11] + DETECTOR(3, 7, 0, 1) rec[-63] rec[-29] + DETECTOR(3, 8, 0, 5) rec[-10] + DETECTOR(3, 10, 0, 3) rec[-46] rec[-9] + DETECTOR(3, 11, 0, 0) rec[-61] rec[-60] rec[-28] + DETECTOR(3, 12, 0, 4) rec[-8] + DETECTOR(5, 1, 0, 1) rec[-27] + DETECTOR(5, 2, 0, 5) rec[-45] rec[-44] rec[-7] + DETECTOR(5, 3, 0, 2) rec[-59] rec[-26] + DETECTOR(5, 4, 0, 3) rec[-43] rec[-6] + DETECTOR(5, 5, 0, 0) rec[-58] rec[-25] + DETECTOR(5, 6, 0, 4) rec[-42] rec[-5] + DETECTOR(5, 7, 0, 1) rec[-57] rec[-24] + DETECTOR(5, 8, 0, 5) rec[-41] rec[-39] rec[-4] + DETECTOR(5, 9, 0, 2) rec[-56] rec[-23] + DETECTOR(5, 10, 0, 3) rec[-40] rec[-3] + DETECTOR(5, 11, 0, 0) rec[-55] rec[-22] + DETECTOR(6, 9, 0, 2) rec[-21] + DETECTOR(7, 1, 0, 1) rec[-20] + DETECTOR(7, 2, 0, 5) rec[-38] rec[-37] rec[-35] rec[-2] + DETECTOR(7, 3, 0, 2) rec[-54] rec[-19] + DETECTOR(7, 4, 0, 3) rec[-36] rec[-1] + DETECTOR(7, 5, 0, 0) rec[-53] rec[-18] + DETECTOR(8, 3, 0, 2) rec[-17] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 + DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 + TICK + CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 52 51 54 53 56 55 58 57 62 61 64 63 67 66 + DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 52 51 54 53 56 55 58 57 62 61 64 63 67 66 + DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 + TICK + CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 51 50 53 52 55 54 57 56 59 58 61 60 63 62 66 65 68 67 + DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 51 50 53 52 55 54 57 56 59 58 61 60 63 62 66 65 68 67 + DEPOLARIZE1(0.001) 0 13 38 49 64 + TICK + CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 40 51 42 53 44 55 46 57 48 59 50 60 52 62 54 64 61 66 63 68 + DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 40 51 42 53 44 55 46 57 48 59 50 60 52 62 54 64 61 66 63 68 + DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 + TICK + MX(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 + M(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 + TICK + RX 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 + R 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 + OBSERVABLE_INCLUDE(0) rec[-26] rec[-32] + X_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 + Z_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 + DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 + TICK + CX 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 40 51 42 53 44 55 46 57 48 59 50 60 52 62 54 64 61 66 63 68 + DEPOLARIZE2(0.001) 0 1 2 8 4 10 6 12 7 14 9 16 11 18 13 20 15 27 17 29 19 31 21 33 23 35 25 37 26 39 28 41 30 43 32 45 34 47 36 49 40 51 42 53 44 55 46 57 48 59 50 60 52 62 54 64 61 66 63 68 + DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 + TICK + CX 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 51 50 53 52 55 54 57 56 59 58 61 60 63 62 66 65 68 67 + DEPOLARIZE2(0.001) 2 1 4 3 6 5 8 7 10 9 12 11 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 33 32 35 34 37 36 40 39 42 41 44 43 46 45 48 47 51 50 53 52 55 54 57 56 59 58 61 60 63 62 66 65 68 67 + DEPOLARIZE1(0.001) 0 13 38 49 64 + TICK + CX 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 52 51 54 53 56 55 58 57 62 61 64 63 67 66 + DETECTOR(1, 1, 0, 4) rec[-18] + DETECTOR(1, 2, 0, 2) rec[-68] rec[-34] + DETECTOR(1, 4, 0, 0) rec[-67] rec[-33] + DETECTOR(1, 5, 0, 3) rec[-49] rec[-48] rec[-17] + DETECTOR(1, 6, 0, 1) rec[-32] + DETECTOR(3, 1, 0, 4) rec[-16] + DETECTOR(3, 2, 0, 2) rec[-66] rec[-65] rec[-31] + DETECTOR(3, 3, 0, 5) rec[-47] rec[-15] + DETECTOR(3, 4, 0, 0) rec[-64] rec[-30] + DETECTOR(3, 5, 0, 3) rec[-46] rec[-14] + DETECTOR(3, 6, 0, 1) rec[-63] rec[-29] + DETECTOR(3, 7, 0, 4) rec[-45] rec[-13] + DETECTOR(3, 8, 0, 2) rec[-28] + DETECTOR(3, 10, 0, 0) rec[-62] rec[-27] + DETECTOR(3, 11, 0, 3) rec[-43] rec[-42] rec[-12] + DETECTOR(3, 12, 0, 1) rec[-26] + DETECTOR(5, 1, 0, 4) rec[-11] + DETECTOR(5, 2, 0, 2) rec[-61] rec[-60] rec[-25] + DETECTOR(5, 3, 0, 5) rec[-41] rec[-10] + DETECTOR(5, 4, 0, 0) rec[-59] rec[-24] + DETECTOR(5, 5, 0, 3) rec[-40] rec[-9] + DETECTOR(5, 6, 0, 1) rec[-58] rec[-23] + DETECTOR(5, 7, 0, 4) rec[-39] rec[-8] + DETECTOR(5, 8, 0, 2) rec[-57] rec[-55] rec[-22] + DETECTOR(5, 9, 0, 5) rec[-38] rec[-7] + DETECTOR(5, 10, 0, 0) rec[-56] rec[-21] + DETECTOR(5, 11, 0, 3) rec[-37] rec[-6] + DETECTOR(6, 9, 0, 5) rec[-5] + DETECTOR(7, 1, 0, 4) rec[-4] + DETECTOR(7, 2, 0, 2) rec[-54] rec[-53] rec[-51] rec[-20] + DETECTOR(7, 3, 0, 5) rec[-36] rec[-3] + DETECTOR(7, 4, 0, 0) rec[-52] rec[-19] + DETECTOR(7, 5, 0, 3) rec[-35] rec[-2] + DETECTOR(8, 3, 0, 5) rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE2(0.001) 3 2 5 4 9 8 11 10 13 12 16 15 18 17 20 19 22 21 24 23 28 27 30 29 32 31 34 33 36 35 38 37 41 40 43 42 45 44 47 46 49 48 52 51 54 53 56 55 58 57 62 61 64 63 67 66 + DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 + TICK +} +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 +DEPOLARIZE1(0.001) 0 13 38 49 64 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 +DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 +TICK +MX(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 +M(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 +TICK +RX 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 +R 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 +OBSERVABLE_INCLUDE(0) rec[-20] rec[-27] rec[-32] rec[-34] +X_ERROR(0.001) 2 4 6 15 17 19 21 23 25 40 42 44 46 48 61 63 +Z_ERROR(0.001) 1 5 14 16 18 20 24 39 41 43 45 47 49 58 60 62 64 67 +DEPOLARIZE1(0.001) 0 3 7 8 9 10 11 12 13 22 26 27 28 29 30 31 32 33 34 35 36 37 38 50 51 52 53 54 55 56 57 59 65 66 68 +TICK +CX 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 +DEPOLARIZE2(0.001) 1 0 8 2 10 4 12 6 14 7 16 9 18 11 20 13 27 15 29 17 31 19 33 21 35 23 37 25 39 26 41 28 43 30 45 32 47 34 49 36 51 40 53 42 55 44 57 46 59 48 60 50 62 52 64 54 66 61 68 63 +DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 +TICK +CX 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 +DEPOLARIZE2(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 39 40 41 42 43 44 45 46 47 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63 65 66 67 68 +DEPOLARIZE1(0.001) 0 13 38 49 64 +TICK +CX 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 +DETECTOR(1, 1, 0, 1) rec[-34] +DETECTOR(1, 2, 0, 5) rec[-52] rec[-16] +DETECTOR(1, 4, 0, 3) rec[-51] rec[-15] +DETECTOR(1, 5, 0, 0) rec[-67] rec[-66] rec[-33] +DETECTOR(1, 6, 0, 4) rec[-14] +DETECTOR(3, 1, 0, 1) rec[-32] +DETECTOR(3, 2, 0, 5) rec[-50] rec[-49] rec[-13] +DETECTOR(3, 3, 0, 2) rec[-65] rec[-31] +DETECTOR(3, 4, 0, 3) rec[-48] rec[-12] +DETECTOR(3, 5, 0, 0) rec[-64] rec[-30] +DETECTOR(3, 6, 0, 4) rec[-47] rec[-11] +DETECTOR(3, 7, 0, 1) rec[-63] rec[-29] +DETECTOR(3, 8, 0, 5) rec[-10] +DETECTOR(3, 10, 0, 3) rec[-46] rec[-9] +DETECTOR(3, 11, 0, 0) rec[-61] rec[-60] rec[-28] +DETECTOR(3, 12, 0, 4) rec[-8] +DETECTOR(5, 1, 0, 1) rec[-27] +DETECTOR(5, 2, 0, 5) rec[-45] rec[-44] rec[-7] +DETECTOR(5, 3, 0, 2) rec[-59] rec[-26] +DETECTOR(5, 4, 0, 3) rec[-43] rec[-6] +DETECTOR(5, 5, 0, 0) rec[-58] rec[-25] +DETECTOR(5, 6, 0, 4) rec[-42] rec[-5] +DETECTOR(5, 7, 0, 1) rec[-57] rec[-24] +DETECTOR(5, 8, 0, 5) rec[-41] rec[-39] rec[-4] +DETECTOR(5, 9, 0, 2) rec[-56] rec[-23] +DETECTOR(5, 10, 0, 3) rec[-40] rec[-3] +DETECTOR(5, 11, 0, 0) rec[-55] rec[-22] +DETECTOR(6, 9, 0, 2) rec[-21] +DETECTOR(7, 1, 0, 1) rec[-20] +DETECTOR(7, 2, 0, 5) rec[-38] rec[-37] rec[-35] rec[-2] +DETECTOR(7, 3, 0, 2) rec[-54] rec[-19] +DETECTOR(7, 4, 0, 3) rec[-36] rec[-1] +DETECTOR(7, 5, 0, 0) rec[-53] rec[-18] +DETECTOR(8, 3, 0, 2) rec[-17] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE2(0.001) 2 3 4 5 8 9 10 11 12 13 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31 32 33 34 35 36 37 38 40 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 58 61 62 63 64 66 67 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 +TICK +CX 67 66 64 63 62 61 58 57 56 55 54 53 52 51 49 48 47 46 45 44 43 42 41 40 38 37 36 35 34 33 32 31 30 29 28 27 24 23 22 21 20 19 18 17 16 15 13 12 11 10 9 8 5 4 3 2 +DEPOLARIZE2(0.001) 67 66 64 63 62 61 58 57 56 55 54 53 52 51 49 48 47 46 45 44 43 42 41 40 38 37 36 35 34 33 32 31 30 29 28 27 24 23 22 21 20 19 18 17 16 15 13 12 11 10 9 8 5 4 3 2 +DEPOLARIZE1(0.001) 0 1 6 7 14 25 26 39 50 59 60 65 68 +TICK +CX 68 67 66 65 63 62 61 60 59 58 57 56 55 54 53 52 51 50 48 47 46 45 44 43 42 41 40 39 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 12 11 10 9 8 7 6 5 4 3 2 1 +DEPOLARIZE2(0.001) 68 67 66 65 63 62 61 60 59 58 57 56 55 54 53 52 51 50 48 47 46 45 44 43 42 41 40 39 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 12 11 10 9 8 7 6 5 4 3 2 1 +DEPOLARIZE1(0.001) 0 13 38 49 64 +TICK +CX 63 68 61 66 54 64 52 62 50 60 48 59 46 57 44 55 42 53 40 51 36 49 34 47 32 45 30 43 28 41 26 39 25 37 23 35 21 33 19 31 17 29 15 27 13 20 11 18 9 16 7 14 6 12 4 10 2 8 0 1 +DEPOLARIZE2(0.001) 63 68 61 66 54 64 52 62 50 60 48 59 46 57 44 55 42 53 40 51 36 49 34 47 32 45 30 43 28 41 26 39 25 37 23 35 21 33 19 31 17 29 15 27 13 20 11 18 9 16 7 14 6 12 4 10 2 8 0 1 +DEPOLARIZE1(0.001) 3 5 22 24 38 56 58 65 67 +TICK +M(0.001) 67 64 62 60 58 49 47 45 43 41 39 24 20 18 16 14 5 1 +MX(0.001) 68 66 65 59 57 56 55 54 53 52 51 50 38 37 36 35 34 33 32 31 30 29 28 27 26 22 13 12 11 10 9 8 7 3 0 63 61 48 46 44 42 40 25 23 21 19 17 15 6 4 2 +DETECTOR(1, 1, 0, 1) rec[-18] rec[-17] +DETECTOR(1, 1, 0, 4) rec[-52] +DETECTOR(1, 2, 0, 2) rec[-103] rec[-1] +DETECTOR(1, 4, 0, 0) rec[-102] rec[-2] +DETECTOR(1, 5, 0, 0) rec[-24] rec[-22] rec[-18] rec[-3] rec[-2] +DETECTOR(1, 5, 0, 3) rec[-84] rec[-83] rec[-53] +DETECTOR(1, 6, 0, 1) rec[-3] +DETECTOR(3, 1, 0, 1) rec[-21] rec[-19] +DETECTOR(3, 1, 0, 4) rec[-54] +DETECTOR(3, 2, 0, 2) rec[-101] rec[-100] rec[-4] +DETECTOR(3, 3, 0, 2) rec[-28] rec[-23] rec[-21] rec[-20] rec[-19] rec[-4] +DETECTOR(3, 3, 0, 5) rec[-82] rec[-55] +DETECTOR(3, 4, 0, 0) rec[-99] rec[-5] +DETECTOR(3, 5, 0, 0) rec[-30] rec[-25] rec[-23] rec[-22] rec[-21] rec[-5] +DETECTOR(3, 5, 0, 3) rec[-81] rec[-56] +DETECTOR(3, 6, 0, 1) rec[-98] rec[-6] +DETECTOR(3, 7, 0, 1) rec[-32] rec[-26] rec[-25] rec[-24] rec[-23] rec[-6] +DETECTOR(3, 7, 0, 4) rec[-80] rec[-57] +DETECTOR(3, 8, 0, 2) rec[-7] +DETECTOR(3, 10, 0, 0) rec[-97] rec[-8] +DETECTOR(3, 11, 0, 0) rec[-38] rec[-36] rec[-26] rec[-9] rec[-8] +DETECTOR(3, 11, 0, 3) rec[-78] rec[-77] rec[-58] +DETECTOR(3, 12, 0, 1) rec[-9] +DETECTOR(5, 1, 0, 1) rec[-29] rec[-27] +DETECTOR(5, 1, 0, 4) rec[-59] +DETECTOR(5, 2, 0, 2) rec[-96] rec[-95] rec[-10] +DETECTOR(5, 3, 0, 2) rec[-41] rec[-31] rec[-29] rec[-28] rec[-27] rec[-10] +DETECTOR(5, 3, 0, 5) rec[-76] rec[-60] +DETECTOR(5, 4, 0, 0) rec[-94] rec[-11] +DETECTOR(5, 5, 0, 0) rec[-43] rec[-33] rec[-31] rec[-30] rec[-29] rec[-11] +DETECTOR(5, 5, 0, 3) rec[-75] rec[-61] +DETECTOR(5, 6, 0, 1) rec[-93] rec[-12] +DETECTOR(5, 7, 0, 1) rec[-45] rec[-35] rec[-33] rec[-32] rec[-31] rec[-12] +DETECTOR(5, 7, 0, 4) rec[-74] rec[-62] +DETECTOR(5, 8, 0, 2) rec[-92] rec[-90] rec[-13] +DETECTOR(5, 9, 0, 2) rec[-47] rec[-37] rec[-35] rec[-34] rec[-33] rec[-13] +DETECTOR(5, 9, 0, 5) rec[-73] rec[-63] +DETECTOR(5, 10, 0, 0) rec[-91] rec[-14] +DETECTOR(5, 11, 0, 0) rec[-48] rec[-39] rec[-37] rec[-36] rec[-35] rec[-14] +DETECTOR(5, 11, 0, 3) rec[-72] rec[-64] +DETECTOR(6, 9, 0, 2) rec[-48] rec[-47] rec[-46] +DETECTOR(6, 9, 0, 5) rec[-65] +DETECTOR(7, 1, 0, 1) rec[-42] rec[-40] +DETECTOR(7, 1, 0, 4) rec[-66] +DETECTOR(7, 2, 0, 2) rec[-89] rec[-88] rec[-86] rec[-15] +DETECTOR(7, 3, 0, 2) rec[-50] rec[-44] rec[-42] rec[-41] rec[-40] rec[-15] +DETECTOR(7, 3, 0, 5) rec[-71] rec[-67] +DETECTOR(7, 4, 0, 0) rec[-87] rec[-16] +DETECTOR(7, 5, 0, 0) rec[-51] rec[-46] rec[-44] rec[-43] rec[-42] rec[-16] +DETECTOR(7, 5, 0, 3) rec[-70] rec[-68] +DETECTOR(8, 3, 0, 2) rec[-51] rec[-50] rec[-49] +DETECTOR(8, 3, 0, 5) rec[-69] +OBSERVABLE_INCLUDE(0) rec[-51] rec[-49] rec[-48] rec[-46] rec[-44] rec[-42] rec[-40] rec[-39] rec[-38] rec[-37] rec[-35] rec[-33] rec[-31] rec[-29] rec[-27] rec[-26] rec[-25] rec[-24] rec[-23] rec[-21] rec[-19] rec[-18] rec[-17] rec[-9] rec[-3] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 67 64 62 60 58 49 47 45 43 41 39 24 20 18 16 14 5 1 68 66 65 59 57 56 55 54 53 52 51 50 38 37 36 35 34 33 32 31 30 29 28 27 26 22 13 12 11 10 9 8 7 3 0 63 61 48 46 44 42 40 25 23 21 19 17 15 6 4 2 diff --git a/test_data/phenom_color_code_d5_r5_p1000.stim b/test_data/phenom_color_code_d5_r5_p1000.stim new file mode 100644 index 0000000..60b5e70 --- /dev/null +++ b/test_data/phenom_color_code_d5_r5_p1000.stim @@ -0,0 +1,73 @@ +QUBIT_COORDS(0, 0) 0 +QUBIT_COORDS(0, 1) 1 +QUBIT_COORDS(1, 1) 2 +QUBIT_COORDS(1, 2) 3 +QUBIT_COORDS(1, 3) 4 +QUBIT_COORDS(1, 4) 5 +QUBIT_COORDS(2, 1) 6 +QUBIT_COORDS(2, 2) 7 +QUBIT_COORDS(2, 3) 8 +QUBIT_COORDS(2, 4) 9 +QUBIT_COORDS(2, 5) 10 +QUBIT_COORDS(2, 6) 11 +QUBIT_COORDS(2, 7) 12 +QUBIT_COORDS(3, 1) 13 +QUBIT_COORDS(3, 2) 14 +QUBIT_COORDS(3, 3) 15 +QUBIT_COORDS(3, 4) 16 +QUBIT_COORDS(3, 5) 17 +QUBIT_COORDS(4, 1) 18 +QUBIT_COORDS(4, 2) 19 +MPP X0*X1*X2*X3*X4*X5*X6*X7*X8*X9*X10*X11*X12*X13*X14*X15*X16*X17*X18*X19 +OBSERVABLE_INCLUDE(0) rec[-1] +MPP Z0*Z1*Z2*Z3*Z4*Z5*Z6*Z7*Z8*Z9*Z10*Z11*Z12*Z13*Z14*Z15*Z16*Z17*Z18*Z19 +OBSERVABLE_INCLUDE(1) rec[-1] +MPP X1*X2*X3*X4 X2*X3*X6*X7 X3*X4*X5*X7*X8*X9 X5*X9*X10*X11 X6*X7*X8*X13*X14*X15 X13*X14*X18*X19 X8*X9*X10*X15*X16*X17 X10*X11*X12*X17 X14*X15*X16*X19 Z1*Z2*Z3*Z4 Z2*Z3*Z6*Z7 Z3*Z4*Z5*Z7*Z8*Z9 Z5*Z9*Z10*Z11 Z6*Z7*Z8*Z13*Z14*Z15 Z13*Z14*Z18*Z19 Z8*Z9*Z10*Z15*Z16*Z17 Z10*Z11*Z12*Z17 Z14*Z15*Z16*Z19 +TICK +REPEAT 5 { + DEPOLARIZE1(0.001) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + MPP(0.001) X1*X2*X3*X4 X2*X3*X6*X7 X3*X4*X5*X7*X8*X9 X5*X9*X10*X11 X6*X7*X8*X13*X14*X15 X13*X14*X18*X19 X8*X9*X10*X15*X16*X17 X10*X11*X12*X17 X14*X15*X16*X19 Z1*Z2*Z3*Z4 Z2*Z3*Z6*Z7 Z3*Z4*Z5*Z7*Z8*Z9 Z5*Z9*Z10*Z11 Z6*Z7*Z8*Z13*Z14*Z15 Z13*Z14*Z18*Z19 Z8*Z9*Z10*Z15*Z16*Z17 Z10*Z11*Z12*Z17 Z14*Z15*Z16*Z19 + DETECTOR(1, 1, 0, 1) rec[-36] rec[-18] + DETECTOR(1, 2, 0, 2) rec[-35] rec[-17] + DETECTOR(1, 4, 0, 0) rec[-34] rec[-16] + DETECTOR(2, 4, 0, 1) rec[-33] rec[-15] + DETECTOR(3, 1, 0, 1) rec[-32] rec[-14] + DETECTOR(3, 2, 0, 2) rec[-31] rec[-13] + DETECTOR(3, 3, 0, 2) rec[-30] rec[-12] + DETECTOR(3, 5, 0, 0) rec[-29] rec[-11] + DETECTOR(4, 2, 0, 0) rec[-28] rec[-10] + DETECTOR(1.125, 1, 0, 4) rec[-27] rec[-9] + DETECTOR(1.125, 2, 0, 5) rec[-26] rec[-8] + DETECTOR(1.125, 4, 0, 3) rec[-25] rec[-7] + DETECTOR(2.125, 4, 0, 4) rec[-24] rec[-6] + DETECTOR(3.125, 1, 0, 4) rec[-23] rec[-5] + DETECTOR(3.125, 2, 0, 5) rec[-22] rec[-4] + DETECTOR(3.125, 3, 0, 5) rec[-21] rec[-3] + DETECTOR(3.125, 5, 0, 3) rec[-20] rec[-2] + DETECTOR(4.125, 2, 0, 3) rec[-19] rec[-1] + SHIFT_COORDS(0, 0, 1) + TICK +} +MPP X1*X2*X3*X4 X2*X3*X6*X7 X3*X4*X5*X7*X8*X9 X5*X9*X10*X11 X6*X7*X8*X13*X14*X15 X13*X14*X18*X19 X8*X9*X10*X15*X16*X17 X10*X11*X12*X17 X14*X15*X16*X19 Z1*Z2*Z3*Z4 Z2*Z3*Z6*Z7 Z3*Z4*Z5*Z7*Z8*Z9 Z5*Z9*Z10*Z11 Z6*Z7*Z8*Z13*Z14*Z15 Z13*Z14*Z18*Z19 Z8*Z9*Z10*Z15*Z16*Z17 Z10*Z11*Z12*Z17 Z14*Z15*Z16*Z19 +DETECTOR(1, 1, 0, 1) rec[-36] rec[-18] +DETECTOR(1, 2, 0, 2) rec[-35] rec[-17] +DETECTOR(1, 4, 0, 0) rec[-34] rec[-16] +DETECTOR(2, 4, 0, 1) rec[-33] rec[-15] +DETECTOR(3, 1, 0, 1) rec[-32] rec[-14] +DETECTOR(3, 2, 0, 2) rec[-31] rec[-13] +DETECTOR(3, 3, 0, 2) rec[-30] rec[-12] +DETECTOR(3, 5, 0, 0) rec[-29] rec[-11] +DETECTOR(4, 2, 0, 0) rec[-28] rec[-10] +DETECTOR(1.125, 1, 0, 4) rec[-27] rec[-9] +DETECTOR(1.125, 2, 0, 5) rec[-26] rec[-8] +DETECTOR(1.125, 4, 0, 3) rec[-25] rec[-7] +DETECTOR(2.125, 4, 0, 4) rec[-24] rec[-6] +DETECTOR(3.125, 1, 0, 4) rec[-23] rec[-5] +DETECTOR(3.125, 2, 0, 5) rec[-22] rec[-4] +DETECTOR(3.125, 3, 0, 5) rec[-21] rec[-3] +DETECTOR(3.125, 5, 0, 3) rec[-20] rec[-2] +DETECTOR(4.125, 2, 0, 3) rec[-19] rec[-1] +MPP X0*X1*X2*X3*X4*X5*X6*X7*X8*X9*X10*X11*X12*X13*X14*X15*X16*X17*X18*X19 +OBSERVABLE_INCLUDE(0) rec[-1] +MPP Z0*Z1*Z2*Z3*Z4*Z5*Z6*Z7*Z8*Z9*Z10*Z11*Z12*Z13*Z14*Z15*Z16*Z17*Z18*Z19 +OBSERVABLE_INCLUDE(1) rec[-1] diff --git a/test_data/rep_code_d9_transit_p10.stim b/test_data/rep_code_d9_transit_p10.stim new file mode 100644 index 0000000..0d979bf --- /dev/null +++ b/test_data/rep_code_d9_transit_p10.stim @@ -0,0 +1,26 @@ +QUBIT_COORDS(0, 0) 0 +QUBIT_COORDS(1, 0) 1 +QUBIT_COORDS(2, 0) 2 +QUBIT_COORDS(3, 0) 3 +QUBIT_COORDS(4, 0) 4 +QUBIT_COORDS(5, 0) 5 +QUBIT_COORDS(6, 0) 6 +QUBIT_COORDS(7, 0) 7 +QUBIT_COORDS(8, 0) 8 +MPP Z0 +OBSERVABLE_INCLUDE(0) rec[-1] +MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4 Z4*Z5 Z5*Z6 Z6*Z7 Z7*Z8 +TICK +DEPOLARIZE1(0.1) 0 1 2 3 4 5 6 7 8 +TICK +MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4 Z4*Z5 Z5*Z6 Z6*Z7 Z7*Z8 +DETECTOR(0.5, 0, 0, 3) rec[-16] rec[-8] +DETECTOR(1.5, 0, 0, 3) rec[-15] rec[-7] +DETECTOR(2.5, 0, 0, 3) rec[-14] rec[-6] +DETECTOR(3.5, 0, 0, 3) rec[-13] rec[-5] +DETECTOR(4.5, 0, 0, 3) rec[-12] rec[-4] +DETECTOR(5.5, 0, 0, 3) rec[-11] rec[-3] +DETECTOR(6.5, 0, 0, 3) rec[-10] rec[-2] +DETECTOR(7.5, 0, 0, 3) rec[-9] rec[-1] +MPP Z0 +OBSERVABLE_INCLUDE(0) rec[-1] diff --git a/test_data/rep_code_rbrrr_d9_transit_p10.stim b/test_data/rep_code_rbrrr_d9_transit_p10.stim new file mode 100644 index 0000000..37b7633 --- /dev/null +++ b/test_data/rep_code_rbrrr_d9_transit_p10.stim @@ -0,0 +1,26 @@ +QUBIT_COORDS(0, 0) 0 +QUBIT_COORDS(1, 0) 1 +QUBIT_COORDS(2, 0) 2 +QUBIT_COORDS(3, 0) 3 +QUBIT_COORDS(4, 0) 4 +QUBIT_COORDS(5, 0) 5 +QUBIT_COORDS(6, 0) 6 +QUBIT_COORDS(7, 0) 7 +QUBIT_COORDS(8, 0) 8 +MPP Z0 +OBSERVABLE_INCLUDE(0) rec[-1] +MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4 Z4*Z5 Z5*Z6 Z6*Z7 Z7*Z8 +TICK +DEPOLARIZE1(0.1) 0 1 2 3 4 5 6 7 8 +TICK +MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4 Z4*Z5 Z5*Z6 Z6*Z7 Z7*Z8 +DETECTOR(0.5, 0, 0, 3) rec[-16] rec[-8] +DETECTOR(1.5, 0, 0, 5) rec[-15] rec[-7] +DETECTOR(2.5, 0, 0, 3) rec[-14] rec[-6] +DETECTOR(3.5, 0, 0, 3) rec[-13] rec[-5] +DETECTOR(4.5, 0, 0, 3) rec[-12] rec[-4] +DETECTOR(5.5, 0, 0, 3) rec[-11] rec[-3] +DETECTOR(6.5, 0, 0, 5) rec[-10] rec[-2] +DETECTOR(7.5, 0, 0, 3) rec[-9] rec[-1] +MPP Z0 +OBSERVABLE_INCLUDE(0) rec[-1] diff --git a/test_data/rep_code_rg_d9_transit_p10.stim b/test_data/rep_code_rg_d9_transit_p10.stim new file mode 100644 index 0000000..46d85c5 --- /dev/null +++ b/test_data/rep_code_rg_d9_transit_p10.stim @@ -0,0 +1,26 @@ +QUBIT_COORDS(0, 0) 0 +QUBIT_COORDS(1, 0) 1 +QUBIT_COORDS(2, 0) 2 +QUBIT_COORDS(3, 0) 3 +QUBIT_COORDS(4, 0) 4 +QUBIT_COORDS(5, 0) 5 +QUBIT_COORDS(6, 0) 6 +QUBIT_COORDS(7, 0) 7 +QUBIT_COORDS(8, 0) 8 +MPP Z0 +OBSERVABLE_INCLUDE(0) rec[-1] +MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4 Z4*Z5 Z5*Z6 Z6*Z7 Z7*Z8 +TICK +DEPOLARIZE1(0.1) 0 1 2 3 4 5 6 7 8 +TICK +MPP Z0*Z1 Z1*Z2 Z2*Z3 Z3*Z4 Z4*Z5 Z5*Z6 Z6*Z7 Z7*Z8 +DETECTOR(0.5, 0, 0, 3) rec[-16] rec[-8] +DETECTOR(1.5, 0, 0, 4) rec[-15] rec[-7] +DETECTOR(2.5, 0, 0, 3) rec[-14] rec[-6] +DETECTOR(3.5, 0, 0, 4) rec[-13] rec[-5] +DETECTOR(4.5, 0, 0, 3) rec[-12] rec[-4] +DETECTOR(5.5, 0, 0, 4) rec[-11] rec[-3] +DETECTOR(6.5, 0, 0, 3) rec[-10] rec[-2] +DETECTOR(7.5, 0, 0, 4) rec[-9] rec[-1] +MPP Z0 +OBSERVABLE_INCLUDE(0) rec[-1] diff --git a/test_data/superdense_color_code_d5_r20_p1000.stim b/test_data/superdense_color_code_d5_r20_p1000.stim new file mode 100644 index 0000000..6a0fcec --- /dev/null +++ b/test_data/superdense_color_code_d5_r20_p1000.stim @@ -0,0 +1,221 @@ +QUBIT_COORDS(0, 0) 0 +QUBIT_COORDS(1, 0) 1 +QUBIT_COORDS(1, 1) 2 +QUBIT_COORDS(1, 2) 3 +QUBIT_COORDS(2, 0) 4 +QUBIT_COORDS(2, 1) 5 +QUBIT_COORDS(2, 2) 6 +QUBIT_COORDS(2, 3) 7 +QUBIT_COORDS(3, 0) 8 +QUBIT_COORDS(3, 1) 9 +QUBIT_COORDS(3, 2) 10 +QUBIT_COORDS(3, 3) 11 +QUBIT_COORDS(3, 4) 12 +QUBIT_COORDS(3, 5) 13 +QUBIT_COORDS(4, 0) 14 +QUBIT_COORDS(4, 1) 15 +QUBIT_COORDS(4, 2) 16 +QUBIT_COORDS(4, 3) 17 +QUBIT_COORDS(4, 4) 18 +QUBIT_COORDS(4, 5) 19 +QUBIT_COORDS(4, 6) 20 +QUBIT_COORDS(5, 0) 21 +QUBIT_COORDS(5, 1) 22 +QUBIT_COORDS(5, 2) 23 +QUBIT_COORDS(5, 3) 24 +QUBIT_COORDS(5, 4) 25 +QUBIT_COORDS(5, 5) 26 +QUBIT_COORDS(6, 0) 27 +QUBIT_COORDS(6, 1) 28 +QUBIT_COORDS(6, 2) 29 +QUBIT_COORDS(6, 3) 30 +QUBIT_COORDS(6, 4) 31 +QUBIT_COORDS(7, 0) 32 +QUBIT_COORDS(7, 1) 33 +QUBIT_COORDS(7, 2) 34 +QUBIT_COORDS(8, 0) 35 +QUBIT_COORDS(8, 1) 36 +RX 1 3 9 11 13 21 23 25 33 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 +R 4 6 15 17 19 27 29 31 36 +X_ERROR(0.001) 4 6 15 17 19 27 29 31 36 +Z_ERROR(0.001) 1 3 9 11 13 21 23 25 33 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 +TICK +CX 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 +DEPOLARIZE2(0.001) 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 +DEPOLARIZE1(0.001) 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 +TICK +CX 2 1 10 9 12 11 22 21 24 23 26 25 34 33 5 4 7 6 16 15 18 17 20 19 28 27 30 29 +DEPOLARIZE2(0.001) 2 1 10 9 12 11 22 21 24 23 26 25 34 33 5 4 7 6 16 15 18 17 20 19 28 27 30 29 +DEPOLARIZE1(0.001) 0 3 8 13 14 31 32 35 36 +TICK +CX 0 1 5 9 7 11 14 21 16 23 18 25 28 33 8 4 10 6 22 15 24 17 26 19 32 27 34 29 +DEPOLARIZE2(0.001) 0 1 5 9 7 11 14 21 16 23 18 25 28 33 8 4 10 6 22 15 24 17 26 19 32 27 34 29 +DEPOLARIZE1(0.001) 2 3 12 13 20 30 31 35 36 +TICK +CX 2 3 8 9 10 11 12 13 22 23 24 25 32 33 5 6 14 15 16 17 18 19 28 29 30 31 35 36 +DEPOLARIZE2(0.001) 2 3 8 9 10 11 12 13 22 23 24 25 32 33 5 6 14 15 16 17 18 19 28 29 30 31 35 36 +DEPOLARIZE1(0.001) 0 1 4 7 20 21 26 27 34 +TICK +CX 1 2 9 10 11 12 21 22 23 24 25 26 33 34 4 5 6 7 15 16 17 18 19 20 27 28 29 30 +DEPOLARIZE2(0.001) 1 2 9 10 11 12 21 22 23 24 25 26 33 34 4 5 6 7 15 16 17 18 19 20 27 28 29 30 +DEPOLARIZE1(0.001) 0 3 8 13 14 31 32 35 36 +TICK +CX 1 0 9 5 11 7 21 14 23 16 25 18 33 28 4 8 6 10 15 22 17 24 19 26 27 32 29 34 +DEPOLARIZE2(0.001) 1 0 9 5 11 7 21 14 23 16 25 18 33 28 4 8 6 10 15 22 17 24 19 26 27 32 29 34 +DEPOLARIZE1(0.001) 2 3 12 13 20 30 31 35 36 +TICK +CX 3 2 9 8 11 10 13 12 23 22 25 24 33 32 6 5 15 14 17 16 19 18 29 28 31 30 36 35 +DEPOLARIZE2(0.001) 3 2 9 8 11 10 13 12 23 22 25 24 33 32 6 5 15 14 17 16 19 18 29 28 31 30 36 35 +DEPOLARIZE1(0.001) 0 1 4 7 20 21 26 27 34 +TICK +CX 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 +DEPOLARIZE2(0.001) 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 +DEPOLARIZE1(0.001) 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 +TICK +MX(0.001) 1 3 9 11 13 21 23 25 33 +M(0.001) 4 6 15 17 19 27 29 31 36 +DETECTOR(1, 0, 0, 0) rec[-18] +DETECTOR(1, 2, 0, 2) rec[-17] +DETECTOR(3, 1, 0, 1) rec[-16] +DETECTOR(3, 3, 0, 0) rec[-15] +DETECTOR(3, 5, 0, 2) rec[-14] +DETECTOR(5, 0, 0, 0) rec[-13] +DETECTOR(5, 2, 0, 2) rec[-12] +DETECTOR(5, 4, 0, 1) rec[-11] +DETECTOR(7, 1, 0, 1) rec[-10] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 1 3 9 11 13 21 23 25 33 4 6 15 17 19 27 29 31 36 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 +TICK +REPEAT 18 { + RX 1 3 9 11 13 21 23 25 33 + R 4 6 15 17 19 27 29 31 36 + X_ERROR(0.001) 4 6 15 17 19 27 29 31 36 + Z_ERROR(0.001) 1 3 9 11 13 21 23 25 33 + DEPOLARIZE1(0.001) 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 + TICK + CX 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 + DEPOLARIZE2(0.001) 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 + DEPOLARIZE1(0.001) 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 + TICK + CX 2 1 10 9 12 11 22 21 24 23 26 25 34 33 5 4 7 6 16 15 18 17 20 19 28 27 30 29 + DEPOLARIZE2(0.001) 2 1 10 9 12 11 22 21 24 23 26 25 34 33 5 4 7 6 16 15 18 17 20 19 28 27 30 29 + DEPOLARIZE1(0.001) 0 3 8 13 14 31 32 35 36 + TICK + CX 0 1 5 9 7 11 14 21 16 23 18 25 28 33 8 4 10 6 22 15 24 17 26 19 32 27 34 29 + DEPOLARIZE2(0.001) 0 1 5 9 7 11 14 21 16 23 18 25 28 33 8 4 10 6 22 15 24 17 26 19 32 27 34 29 + DEPOLARIZE1(0.001) 2 3 12 13 20 30 31 35 36 + TICK + CX 2 3 8 9 10 11 12 13 22 23 24 25 32 33 5 6 14 15 16 17 18 19 28 29 30 31 35 36 + DEPOLARIZE2(0.001) 2 3 8 9 10 11 12 13 22 23 24 25 32 33 5 6 14 15 16 17 18 19 28 29 30 31 35 36 + DEPOLARIZE1(0.001) 0 1 4 7 20 21 26 27 34 + TICK + CX 1 2 9 10 11 12 21 22 23 24 25 26 33 34 4 5 6 7 15 16 17 18 19 20 27 28 29 30 + DEPOLARIZE2(0.001) 1 2 9 10 11 12 21 22 23 24 25 26 33 34 4 5 6 7 15 16 17 18 19 20 27 28 29 30 + DEPOLARIZE1(0.001) 0 3 8 13 14 31 32 35 36 + TICK + CX 1 0 9 5 11 7 21 14 23 16 25 18 33 28 4 8 6 10 15 22 17 24 19 26 27 32 29 34 + DEPOLARIZE2(0.001) 1 0 9 5 11 7 21 14 23 16 25 18 33 28 4 8 6 10 15 22 17 24 19 26 27 32 29 34 + DEPOLARIZE1(0.001) 2 3 12 13 20 30 31 35 36 + TICK + CX 3 2 9 8 11 10 13 12 23 22 25 24 33 32 6 5 15 14 17 16 19 18 29 28 31 30 36 35 + DEPOLARIZE2(0.001) 3 2 9 8 11 10 13 12 23 22 25 24 33 32 6 5 15 14 17 16 19 18 29 28 31 30 36 35 + DEPOLARIZE1(0.001) 0 1 4 7 20 21 26 27 34 + TICK + CX 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 + DEPOLARIZE2(0.001) 1 4 3 6 9 15 11 17 13 19 21 27 23 29 25 31 33 36 + DEPOLARIZE1(0.001) 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 + TICK + MX(0.001) 1 3 9 11 13 21 23 25 33 + M(0.001) 4 6 15 17 19 27 29 31 36 + DETECTOR(1, 0, 0, 0) rec[-36] rec[-18] + DETECTOR(1, 2, 0, 2) rec[-35] rec[-17] + DETECTOR(2, 0, 0, 3) rec[-27] rec[-26] rec[-9] + DETECTOR(2, 2, 0, 5) rec[-27] rec[-8] + DETECTOR(3, 1, 0, 1) rec[-34] rec[-16] + DETECTOR(3, 3, 0, 0) rec[-33] rec[-15] + DETECTOR(3, 5, 0, 2) rec[-32] rec[-14] + DETECTOR(4, 1, 0, 4) rec[-24] rec[-7] + DETECTOR(4, 3, 0, 3) rec[-25] rec[-23] rec[-6] + DETECTOR(4, 5, 0, 5) rec[-24] rec[-5] + DETECTOR(5, 0, 0, 0) rec[-31] rec[-13] + DETECTOR(5, 2, 0, 2) rec[-30] rec[-12] + DETECTOR(5, 4, 0, 1) rec[-29] rec[-11] + DETECTOR(6, 0, 0, 3) rec[-22] rec[-21] rec[-4] + DETECTOR(6, 2, 0, 5) rec[-22] rec[-20] rec[-3] + DETECTOR(6, 4, 0, 4) rec[-21] rec[-2] + DETECTOR(7, 1, 0, 1) rec[-28] rec[-10] + DETECTOR(8, 1, 0, 4) rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 1 3 9 11 13 21 23 25 33 4 6 15 17 19 27 29 31 36 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 + TICK +} +R 36 31 29 27 19 17 15 6 4 +RX 33 25 23 21 13 11 9 3 1 +X_ERROR(0.001) 36 31 29 27 19 17 15 6 4 +Z_ERROR(0.001) 33 25 23 21 13 11 9 3 1 +DEPOLARIZE1(0.001) 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 +TICK +CX 33 36 25 31 23 29 21 27 13 19 11 17 9 15 3 6 1 4 +DEPOLARIZE2(0.001) 33 36 25 31 23 29 21 27 13 19 11 17 9 15 3 6 1 4 +DEPOLARIZE1(0.001) 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 +TICK +CX 36 35 31 30 29 28 19 18 17 16 15 14 6 5 33 32 25 24 23 22 13 12 11 10 9 8 3 2 +DEPOLARIZE2(0.001) 36 35 31 30 29 28 19 18 17 16 15 14 6 5 33 32 25 24 23 22 13 12 11 10 9 8 3 2 +DEPOLARIZE1(0.001) 0 1 4 7 20 21 26 27 34 +TICK +CX 29 34 27 32 19 26 17 24 15 22 6 10 4 8 33 28 25 18 23 16 21 14 11 7 9 5 1 0 +DEPOLARIZE2(0.001) 29 34 27 32 19 26 17 24 15 22 6 10 4 8 33 28 25 18 23 16 21 14 11 7 9 5 1 0 +DEPOLARIZE1(0.001) 2 3 12 13 20 30 31 35 36 +TICK +CX 29 30 27 28 19 20 17 18 15 16 6 7 4 5 33 34 25 26 23 24 21 22 11 12 9 10 1 2 +DEPOLARIZE2(0.001) 29 30 27 28 19 20 17 18 15 16 6 7 4 5 33 34 25 26 23 24 21 22 11 12 9 10 1 2 +DEPOLARIZE1(0.001) 0 3 8 13 14 31 32 35 36 +TICK +CX 35 36 30 31 28 29 18 19 16 17 14 15 5 6 32 33 24 25 22 23 12 13 10 11 8 9 2 3 +DEPOLARIZE2(0.001) 35 36 30 31 28 29 18 19 16 17 14 15 5 6 32 33 24 25 22 23 12 13 10 11 8 9 2 3 +DEPOLARIZE1(0.001) 0 1 4 7 20 21 26 27 34 +TICK +CX 34 29 32 27 26 19 24 17 22 15 10 6 8 4 28 33 18 25 16 23 14 21 7 11 5 9 0 1 +DEPOLARIZE2(0.001) 34 29 32 27 26 19 24 17 22 15 10 6 8 4 28 33 18 25 16 23 14 21 7 11 5 9 0 1 +DEPOLARIZE1(0.001) 2 3 12 13 20 30 31 35 36 +TICK +CX 30 29 28 27 20 19 18 17 16 15 7 6 5 4 34 33 26 25 24 23 22 21 12 11 10 9 2 1 +DEPOLARIZE2(0.001) 30 29 28 27 20 19 18 17 16 15 7 6 5 4 34 33 26 25 24 23 22 21 12 11 10 9 2 1 +DEPOLARIZE1(0.001) 0 3 8 13 14 31 32 35 36 +TICK +CX 33 36 25 31 23 29 21 27 13 19 11 17 9 15 3 6 1 4 +DEPOLARIZE2(0.001) 33 36 25 31 23 29 21 27 13 19 11 17 9 15 3 6 1 4 +DEPOLARIZE1(0.001) 0 2 5 7 8 10 12 14 16 18 20 22 24 26 28 30 32 34 35 +TICK +M(0.001) 36 31 29 27 19 17 15 6 4 +MX(0.001) 35 34 32 30 28 26 24 22 20 18 16 14 12 10 8 7 5 2 0 33 25 23 21 13 11 9 3 1 +DETECTOR(1, 0, 0, 0) rec[-14] rec[-12] rec[-11] rec[-10] rec[-2] rec[-1] +DETECTOR(1, 0, 0, 0) rec[-55] rec[-1] +DETECTOR(1, 2, 0, 2) rec[-15] rec[-13] rec[-12] rec[-11] rec[-1] +DETECTOR(1, 2, 0, 2) rec[-54] rec[-2] +DETECTOR(2, 0, 0, 3) rec[-46] rec[-45] rec[-29] +DETECTOR(2, 2, 0, 5) rec[-46] rec[-30] +DETECTOR(3, 1, 0, 1) rec[-21] rec[-18] rec[-17] rec[-15] rec[-14] rec[-12] rec[-4] +DETECTOR(3, 1, 0, 1) rec[-53] rec[-3] +DETECTOR(3, 3, 0, 0) rec[-22] rec[-19] rec[-18] rec[-16] rec[-15] rec[-13] rec[-5] rec[-3] +DETECTOR(3, 3, 0, 0) rec[-52] rec[-4] +DETECTOR(3, 5, 0, 2) rec[-23] rec[-20] rec[-19] rec[-16] rec[-4] +DETECTOR(3, 5, 0, 2) rec[-51] rec[-5] +DETECTOR(4, 1, 0, 4) rec[-43] rec[-31] +DETECTOR(4, 3, 0, 3) rec[-44] rec[-42] rec[-32] +DETECTOR(4, 5, 0, 5) rec[-43] rec[-33] +DETECTOR(5, 0, 0, 0) rec[-26] rec[-24] rec[-21] rec[-17] rec[-7] rec[-6] +DETECTOR(5, 0, 0, 0) rec[-50] rec[-6] +DETECTOR(5, 2, 0, 2) rec[-27] rec[-25] rec[-24] rec[-22] rec[-21] rec[-18] rec[-8] rec[-6] +DETECTOR(5, 2, 0, 2) rec[-49] rec[-7] +DETECTOR(5, 4, 0, 1) rec[-25] rec[-23] rec[-22] rec[-19] rec[-7] +DETECTOR(5, 4, 0, 1) rec[-48] rec[-8] +DETECTOR(6, 0, 0, 3) rec[-41] rec[-40] rec[-34] +DETECTOR(6, 2, 0, 5) rec[-41] rec[-39] rec[-35] +DETECTOR(6, 4, 0, 4) rec[-40] rec[-36] +DETECTOR(7, 1, 0, 1) rec[-28] rec[-27] rec[-26] rec[-24] +DETECTOR(7, 1, 0, 1) rec[-47] rec[-9] +DETECTOR(8, 1, 0, 4) rec[-37] +OBSERVABLE_INCLUDE(0) rec[-28] rec[-27] rec[-26] rec[-25] rec[-24] rec[-23] rec[-22] rec[-21] rec[-20] rec[-19] rec[-18] rec[-17] rec[-16] rec[-15] rec[-14] rec[-13] rec[-12] rec[-11] rec[-10] rec[-9] rec[-8] rec[-7] rec[-5] rec[-4] rec[-3] rec[-2] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 36 31 29 27 19 17 15 6 4 35 34 32 30 28 26 24 22 20 18 16 14 12 10 8 7 5 2 0 33 25 23 21 13 11 9 3 1 diff --git a/test_data/surface_code_d5_r5_p1000.stim b/test_data/surface_code_d5_r5_p1000.stim new file mode 100644 index 0000000..a7fbf92 --- /dev/null +++ b/test_data/surface_code_d5_r5_p1000.stim @@ -0,0 +1,203 @@ +QUBIT_COORDS(0, 0) 0 +QUBIT_COORDS(0, 1) 1 +QUBIT_COORDS(0, 2) 2 +QUBIT_COORDS(0, 3) 3 +QUBIT_COORDS(0, 4) 4 +QUBIT_COORDS(1, 0) 5 +QUBIT_COORDS(1, 1) 6 +QUBIT_COORDS(1, 2) 7 +QUBIT_COORDS(1, 3) 8 +QUBIT_COORDS(1, 4) 9 +QUBIT_COORDS(2, 0) 10 +QUBIT_COORDS(2, 1) 11 +QUBIT_COORDS(2, 2) 12 +QUBIT_COORDS(2, 3) 13 +QUBIT_COORDS(2, 4) 14 +QUBIT_COORDS(3, 0) 15 +QUBIT_COORDS(3, 1) 16 +QUBIT_COORDS(3, 2) 17 +QUBIT_COORDS(3, 3) 18 +QUBIT_COORDS(3, 4) 19 +QUBIT_COORDS(4, 0) 20 +QUBIT_COORDS(4, 1) 21 +QUBIT_COORDS(4, 2) 22 +QUBIT_COORDS(4, 3) 23 +QUBIT_COORDS(4, 4) 24 +QUBIT_COORDS(-0.5, 1.5) 25 +QUBIT_COORDS(-0.5, 3.5) 26 +QUBIT_COORDS(0.5, -0.5) 27 +QUBIT_COORDS(0.5, 0.5) 28 +QUBIT_COORDS(0.5, 1.5) 29 +QUBIT_COORDS(0.5, 2.5) 30 +QUBIT_COORDS(0.5, 3.5) 31 +QUBIT_COORDS(1.5, 0.5) 32 +QUBIT_COORDS(1.5, 1.5) 33 +QUBIT_COORDS(1.5, 2.5) 34 +QUBIT_COORDS(1.5, 3.5) 35 +QUBIT_COORDS(1.5, 4.5) 36 +QUBIT_COORDS(2.5, -0.5) 37 +QUBIT_COORDS(2.5, 0.5) 38 +QUBIT_COORDS(2.5, 1.5) 39 +QUBIT_COORDS(2.5, 2.5) 40 +QUBIT_COORDS(2.5, 3.5) 41 +QUBIT_COORDS(3.5, 0.5) 42 +QUBIT_COORDS(3.5, 1.5) 43 +QUBIT_COORDS(3.5, 2.5) 44 +QUBIT_COORDS(3.5, 3.5) 45 +QUBIT_COORDS(3.5, 4.5) 46 +QUBIT_COORDS(4.5, 0.5) 47 +QUBIT_COORDS(4.5, 2.5) 48 +RX 27 29 31 32 34 36 37 39 41 42 44 46 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 +R 25 26 28 30 33 35 38 40 43 45 47 48 +X_ERROR(0.001) 25 26 28 30 33 35 38 40 43 45 47 48 +Z_ERROR(0.001) 27 29 31 32 34 36 37 39 41 42 44 46 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 +TICK +CX 1 25 3 26 5 28 7 30 11 33 13 35 15 38 17 40 21 43 23 45 29 6 31 8 32 10 34 12 36 14 39 16 41 18 42 20 44 22 46 24 +DEPOLARIZE2(0.001) 1 25 3 26 5 28 7 30 11 33 13 35 15 38 17 40 21 43 23 45 29 6 31 8 32 10 34 12 36 14 39 16 41 18 42 20 44 22 46 24 +DEPOLARIZE1(0.001) 0 2 4 9 19 27 37 47 48 +TICK +CX 2 25 4 26 6 28 8 30 12 33 14 35 16 38 18 40 22 43 24 45 29 1 31 3 32 5 34 7 36 9 39 11 41 13 42 15 44 17 46 19 +DEPOLARIZE2(0.001) 2 25 4 26 6 28 8 30 12 33 14 35 16 38 18 40 22 43 24 45 29 1 31 3 32 5 34 7 36 9 39 11 41 13 42 15 44 17 46 19 +DEPOLARIZE1(0.001) 0 10 20 21 23 27 37 47 48 +TICK +CX 0 28 2 30 6 33 8 35 10 38 12 40 16 43 18 45 20 47 22 48 27 5 29 7 31 9 32 11 34 13 37 15 39 17 41 19 42 21 44 23 +DEPOLARIZE2(0.001) 0 28 2 30 6 33 8 35 10 38 12 40 16 43 18 45 20 47 22 48 27 5 29 7 31 9 32 11 34 13 37 15 39 17 41 19 42 21 44 23 +DEPOLARIZE1(0.001) 1 3 4 14 24 25 26 36 46 +TICK +CX 1 28 3 30 7 33 9 35 11 38 13 40 17 43 19 45 21 47 23 48 27 0 29 2 31 4 32 6 34 8 37 10 39 12 41 14 42 16 44 18 +DEPOLARIZE2(0.001) 1 28 3 30 7 33 9 35 11 38 13 40 17 43 19 45 21 47 23 48 27 0 29 2 31 4 32 6 34 8 37 10 39 12 41 14 42 16 44 18 +DEPOLARIZE1(0.001) 5 15 20 22 24 25 26 36 46 +TICK +MX(0.001) 27 29 31 32 34 36 37 39 41 42 44 46 +M(0.001) 25 26 28 30 33 35 38 40 43 45 47 48 +DETECTOR(0.5, -0.5, 0, 1) rec[-24] +DETECTOR(0.5, 1.5, 0, 1) rec[-23] +DETECTOR(0.5, 3.5, 0, 1) rec[-22] +DETECTOR(1.5, 0.5, 0, 0) rec[-21] +DETECTOR(1.5, 2.5, 0, 0) rec[-20] +DETECTOR(1.5, 4.5, 0, 0) rec[-19] +DETECTOR(2.5, -0.5, 0, 1) rec[-18] +DETECTOR(2.5, 1.5, 0, 1) rec[-17] +DETECTOR(2.5, 3.5, 0, 1) rec[-16] +DETECTOR(3.5, 0.5, 0, 0) rec[-15] +DETECTOR(3.5, 2.5, 0, 0) rec[-14] +DETECTOR(3.5, 4.5, 0, 0) rec[-13] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 27 29 31 32 34 36 37 39 41 42 44 46 25 26 28 30 33 35 38 40 43 45 47 48 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 +TICK +REPEAT 3 { + RX 27 29 31 32 34 36 37 39 41 42 44 46 + R 25 26 28 30 33 35 38 40 43 45 47 48 + X_ERROR(0.001) 25 26 28 30 33 35 38 40 43 45 47 48 + Z_ERROR(0.001) 27 29 31 32 34 36 37 39 41 42 44 46 + DEPOLARIZE1(0.001) 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 + TICK + CX 1 25 3 26 5 28 7 30 11 33 13 35 15 38 17 40 21 43 23 45 29 6 31 8 32 10 34 12 36 14 39 16 41 18 42 20 44 22 46 24 + DEPOLARIZE2(0.001) 1 25 3 26 5 28 7 30 11 33 13 35 15 38 17 40 21 43 23 45 29 6 31 8 32 10 34 12 36 14 39 16 41 18 42 20 44 22 46 24 + DEPOLARIZE1(0.001) 0 2 4 9 19 27 37 47 48 + TICK + CX 2 25 4 26 6 28 8 30 12 33 14 35 16 38 18 40 22 43 24 45 29 1 31 3 32 5 34 7 36 9 39 11 41 13 42 15 44 17 46 19 + DEPOLARIZE2(0.001) 2 25 4 26 6 28 8 30 12 33 14 35 16 38 18 40 22 43 24 45 29 1 31 3 32 5 34 7 36 9 39 11 41 13 42 15 44 17 46 19 + DEPOLARIZE1(0.001) 0 10 20 21 23 27 37 47 48 + TICK + CX 0 28 2 30 6 33 8 35 10 38 12 40 16 43 18 45 20 47 22 48 27 5 29 7 31 9 32 11 34 13 37 15 39 17 41 19 42 21 44 23 + DEPOLARIZE2(0.001) 0 28 2 30 6 33 8 35 10 38 12 40 16 43 18 45 20 47 22 48 27 5 29 7 31 9 32 11 34 13 37 15 39 17 41 19 42 21 44 23 + DEPOLARIZE1(0.001) 1 3 4 14 24 25 26 36 46 + TICK + CX 1 28 3 30 7 33 9 35 11 38 13 40 17 43 19 45 21 47 23 48 27 0 29 2 31 4 32 6 34 8 37 10 39 12 41 14 42 16 44 18 + DEPOLARIZE2(0.001) 1 28 3 30 7 33 9 35 11 38 13 40 17 43 19 45 21 47 23 48 27 0 29 2 31 4 32 6 34 8 37 10 39 12 41 14 42 16 44 18 + DEPOLARIZE1(0.001) 5 15 20 22 24 25 26 36 46 + TICK + MX(0.001) 27 29 31 32 34 36 37 39 41 42 44 46 + M(0.001) 25 26 28 30 33 35 38 40 43 45 47 48 + DETECTOR(-0.5, 1.5, 0, 3) rec[-36] rec[-12] + DETECTOR(-0.5, 3.5, 0, 3) rec[-35] rec[-11] + DETECTOR(0.5, -0.5, 0, 1) rec[-48] rec[-24] + DETECTOR(0.5, 0.5, 0, 4) rec[-34] rec[-10] + DETECTOR(0.5, 1.5, 0, 1) rec[-47] rec[-23] + DETECTOR(0.5, 2.5, 0, 4) rec[-33] rec[-9] + DETECTOR(0.5, 3.5, 0, 1) rec[-46] rec[-22] + DETECTOR(1.5, 0.5, 0, 0) rec[-45] rec[-21] + DETECTOR(1.5, 1.5, 0, 3) rec[-32] rec[-8] + DETECTOR(1.5, 2.5, 0, 0) rec[-44] rec[-20] + DETECTOR(1.5, 3.5, 0, 3) rec[-31] rec[-7] + DETECTOR(1.5, 4.5, 0, 0) rec[-43] rec[-19] + DETECTOR(2.5, -0.5, 0, 1) rec[-42] rec[-18] + DETECTOR(2.5, 0.5, 0, 4) rec[-30] rec[-6] + DETECTOR(2.5, 1.5, 0, 1) rec[-41] rec[-17] + DETECTOR(2.5, 2.5, 0, 4) rec[-29] rec[-5] + DETECTOR(2.5, 3.5, 0, 1) rec[-40] rec[-16] + DETECTOR(3.5, 0.5, 0, 0) rec[-39] rec[-15] + DETECTOR(3.5, 1.5, 0, 3) rec[-28] rec[-4] + DETECTOR(3.5, 2.5, 0, 0) rec[-38] rec[-14] + DETECTOR(3.5, 3.5, 0, 3) rec[-27] rec[-3] + DETECTOR(3.5, 4.5, 0, 0) rec[-37] rec[-13] + DETECTOR(4.5, 0.5, 0, 4) rec[-26] rec[-2] + DETECTOR(4.5, 2.5, 0, 4) rec[-25] rec[-1] + SHIFT_COORDS(0, 0, 1) + DEPOLARIZE1(0.001) 27 29 31 32 34 36 37 39 41 42 44 46 25 26 28 30 33 35 38 40 43 45 47 48 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 + TICK +} +RX 27 29 31 32 34 36 37 39 41 42 44 46 +R 25 26 28 30 33 35 38 40 43 45 47 48 +X_ERROR(0.001) 25 26 28 30 33 35 38 40 43 45 47 48 +Z_ERROR(0.001) 27 29 31 32 34 36 37 39 41 42 44 46 +DEPOLARIZE1(0.001) 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 +TICK +CX 1 25 3 26 5 28 7 30 11 33 13 35 15 38 17 40 21 43 23 45 29 6 31 8 32 10 34 12 36 14 39 16 41 18 42 20 44 22 46 24 +DEPOLARIZE2(0.001) 1 25 3 26 5 28 7 30 11 33 13 35 15 38 17 40 21 43 23 45 29 6 31 8 32 10 34 12 36 14 39 16 41 18 42 20 44 22 46 24 +DEPOLARIZE1(0.001) 0 2 4 9 19 27 37 47 48 +TICK +CX 2 25 4 26 6 28 8 30 12 33 14 35 16 38 18 40 22 43 24 45 29 1 31 3 32 5 34 7 36 9 39 11 41 13 42 15 44 17 46 19 +DEPOLARIZE2(0.001) 2 25 4 26 6 28 8 30 12 33 14 35 16 38 18 40 22 43 24 45 29 1 31 3 32 5 34 7 36 9 39 11 41 13 42 15 44 17 46 19 +DEPOLARIZE1(0.001) 0 10 20 21 23 27 37 47 48 +TICK +CX 0 28 2 30 6 33 8 35 10 38 12 40 16 43 18 45 20 47 22 48 27 5 29 7 31 9 32 11 34 13 37 15 39 17 41 19 42 21 44 23 +DEPOLARIZE2(0.001) 0 28 2 30 6 33 8 35 10 38 12 40 16 43 18 45 20 47 22 48 27 5 29 7 31 9 32 11 34 13 37 15 39 17 41 19 42 21 44 23 +DEPOLARIZE1(0.001) 1 3 4 14 24 25 26 36 46 +TICK +CX 1 28 3 30 7 33 9 35 11 38 13 40 17 43 19 45 21 47 23 48 27 0 29 2 31 4 32 6 34 8 37 10 39 12 41 14 42 16 44 18 +DEPOLARIZE2(0.001) 1 28 3 30 7 33 9 35 11 38 13 40 17 43 19 45 21 47 23 48 27 0 29 2 31 4 32 6 34 8 37 10 39 12 41 14 42 16 44 18 +DEPOLARIZE1(0.001) 5 15 20 22 24 25 26 36 46 +TICK +MX(0.001) 27 29 31 32 34 36 37 39 41 42 44 46 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 +M(0.001) 25 26 28 30 33 35 38 40 43 45 47 48 +DETECTOR(-0.5, 1.5, 0, 3) rec[-61] rec[-12] +DETECTOR(-0.5, 3.5, 0, 3) rec[-60] rec[-11] +DETECTOR(0.5, -0.5, 0, 1) rec[-73] rec[-49] +DETECTOR(0.5, 0.5, 0, 4) rec[-59] rec[-10] +DETECTOR(0.5, 1.5, 0, 1) rec[-72] rec[-48] +DETECTOR(0.5, 2.5, 0, 4) rec[-58] rec[-9] +DETECTOR(0.5, 3.5, 0, 1) rec[-71] rec[-47] +DETECTOR(1.5, 0.5, 0, 0) rec[-70] rec[-46] +DETECTOR(1.5, 1.5, 0, 3) rec[-57] rec[-8] +DETECTOR(1.5, 2.5, 0, 0) rec[-69] rec[-45] +DETECTOR(1.5, 3.5, 0, 3) rec[-56] rec[-7] +DETECTOR(1.5, 4.5, 0, 0) rec[-68] rec[-44] +DETECTOR(2.5, -0.5, 0, 1) rec[-67] rec[-43] +DETECTOR(2.5, 0.5, 0, 4) rec[-55] rec[-6] +DETECTOR(2.5, 1.5, 0, 1) rec[-66] rec[-42] +DETECTOR(2.5, 2.5, 0, 4) rec[-54] rec[-5] +DETECTOR(2.5, 3.5, 0, 1) rec[-65] rec[-41] +DETECTOR(3.5, 0.5, 0, 0) rec[-64] rec[-40] +DETECTOR(3.5, 1.5, 0, 3) rec[-53] rec[-4] +DETECTOR(3.5, 2.5, 0, 0) rec[-63] rec[-39] +DETECTOR(3.5, 3.5, 0, 3) rec[-52] rec[-3] +DETECTOR(3.5, 4.5, 0, 0) rec[-62] rec[-38] +DETECTOR(4.5, 0.5, 0, 4) rec[-51] rec[-2] +DETECTOR(4.5, 2.5, 0, 4) rec[-50] rec[-1] +DETECTOR(0.5, -0.5, 0, 1) rec[-49] rec[-37] rec[-32] +DETECTOR(0.5, 1.5, 0, 1) rec[-48] rec[-36] rec[-35] rec[-31] rec[-30] +DETECTOR(0.5, 3.5, 0, 1) rec[-47] rec[-34] rec[-33] rec[-29] rec[-28] +DETECTOR(1.5, 0.5, 0, 0) rec[-46] rec[-32] rec[-31] rec[-27] rec[-26] +DETECTOR(1.5, 2.5, 0, 0) rec[-45] rec[-30] rec[-29] rec[-25] rec[-24] +DETECTOR(1.5, 4.5, 0, 0) rec[-44] rec[-28] rec[-23] +DETECTOR(2.5, -0.5, 0, 1) rec[-43] rec[-27] rec[-22] +DETECTOR(2.5, 1.5, 0, 1) rec[-42] rec[-26] rec[-25] rec[-21] rec[-20] +DETECTOR(2.5, 3.5, 0, 1) rec[-41] rec[-24] rec[-23] rec[-19] rec[-18] +DETECTOR(3.5, 0.5, 0, 0) rec[-40] rec[-22] rec[-21] rec[-17] rec[-16] +DETECTOR(3.5, 2.5, 0, 0) rec[-39] rec[-20] rec[-19] rec[-15] rec[-14] +DETECTOR(3.5, 4.5, 0, 0) rec[-38] rec[-18] rec[-13] +OBSERVABLE_INCLUDE(0) rec[-37] rec[-36] rec[-35] rec[-33] rec[-34] +SHIFT_COORDS(0, 0, 1) +DEPOLARIZE1(0.001) 27 29 31 32 34 36 37 39 41 42 44 46 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 28 30 33 35 38 40 43 45 47 48 diff --git a/test_data/toric_superdense_color_code_epr_d12_r5_p1000.stim b/test_data/toric_superdense_color_code_epr_d12_r5_p1000.stim new file mode 100644 index 0000000..9365837 --- /dev/null +++ b/test_data/toric_superdense_color_code_epr_d12_r5_p1000.stim @@ -0,0 +1,573 @@ +QUBIT_COORDS(-2, 0) 0 +QUBIT_COORDS(-1, 0) 1 +QUBIT_COORDS(0, 0) 2 +QUBIT_COORDS(0, 1) 3 +QUBIT_COORDS(0, 2) 4 +QUBIT_COORDS(0, 3) 5 +QUBIT_COORDS(0, 4) 6 +QUBIT_COORDS(0, 5) 7 +QUBIT_COORDS(0, 6) 8 +QUBIT_COORDS(0, 7) 9 +QUBIT_COORDS(0, 8) 10 +QUBIT_COORDS(0, 9) 11 +QUBIT_COORDS(0, 10) 12 +QUBIT_COORDS(0, 11) 13 +QUBIT_COORDS(0, 12) 14 +QUBIT_COORDS(0, 13) 15 +QUBIT_COORDS(0, 14) 16 +QUBIT_COORDS(0, 15) 17 +QUBIT_COORDS(1, 0) 18 +QUBIT_COORDS(1, 1) 19 +QUBIT_COORDS(1, 2) 20 +QUBIT_COORDS(1, 3) 21 +QUBIT_COORDS(1, 4) 22 +QUBIT_COORDS(1, 5) 23 +QUBIT_COORDS(1, 6) 24 +QUBIT_COORDS(1, 7) 25 +QUBIT_COORDS(1, 8) 26 +QUBIT_COORDS(1, 9) 27 +QUBIT_COORDS(1, 10) 28 +QUBIT_COORDS(1, 11) 29 +QUBIT_COORDS(1, 12) 30 +QUBIT_COORDS(1, 13) 31 +QUBIT_COORDS(1, 14) 32 +QUBIT_COORDS(1, 15) 33 +QUBIT_COORDS(2, 0) 34 +QUBIT_COORDS(2, 1) 35 +QUBIT_COORDS(2, 2) 36 +QUBIT_COORDS(2, 3) 37 +QUBIT_COORDS(2, 4) 38 +QUBIT_COORDS(2, 5) 39 +QUBIT_COORDS(2, 6) 40 +QUBIT_COORDS(2, 7) 41 +QUBIT_COORDS(2, 8) 42 +QUBIT_COORDS(2, 9) 43 +QUBIT_COORDS(2, 10) 44 +QUBIT_COORDS(2, 11) 45 +QUBIT_COORDS(2, 12) 46 +QUBIT_COORDS(2, 13) 47 +QUBIT_COORDS(2, 14) 48 +QUBIT_COORDS(2, 15) 49 +QUBIT_COORDS(3, 0) 50 +QUBIT_COORDS(3, 1) 51 +QUBIT_COORDS(3, 2) 52 +QUBIT_COORDS(3, 3) 53 +QUBIT_COORDS(3, 4) 54 +QUBIT_COORDS(3, 5) 55 +QUBIT_COORDS(3, 6) 56 +QUBIT_COORDS(3, 7) 57 +QUBIT_COORDS(3, 8) 58 +QUBIT_COORDS(3, 9) 59 +QUBIT_COORDS(3, 10) 60 +QUBIT_COORDS(3, 11) 61 +QUBIT_COORDS(3, 12) 62 +QUBIT_COORDS(3, 13) 63 +QUBIT_COORDS(3, 14) 64 +QUBIT_COORDS(3, 15) 65 +QUBIT_COORDS(4, 0) 66 +QUBIT_COORDS(4, 1) 67 +QUBIT_COORDS(4, 2) 68 +QUBIT_COORDS(4, 3) 69 +QUBIT_COORDS(4, 4) 70 +QUBIT_COORDS(4, 5) 71 +QUBIT_COORDS(4, 6) 72 +QUBIT_COORDS(4, 7) 73 +QUBIT_COORDS(4, 8) 74 +QUBIT_COORDS(4, 9) 75 +QUBIT_COORDS(4, 10) 76 +QUBIT_COORDS(4, 11) 77 +QUBIT_COORDS(4, 12) 78 +QUBIT_COORDS(4, 13) 79 +QUBIT_COORDS(4, 14) 80 +QUBIT_COORDS(4, 15) 81 +QUBIT_COORDS(5, 0) 82 +QUBIT_COORDS(5, 1) 83 +QUBIT_COORDS(5, 2) 84 +QUBIT_COORDS(5, 3) 85 +QUBIT_COORDS(5, 4) 86 +QUBIT_COORDS(5, 5) 87 +QUBIT_COORDS(5, 6) 88 +QUBIT_COORDS(5, 7) 89 +QUBIT_COORDS(5, 8) 90 +QUBIT_COORDS(5, 9) 91 +QUBIT_COORDS(5, 10) 92 +QUBIT_COORDS(5, 11) 93 +QUBIT_COORDS(5, 12) 94 +QUBIT_COORDS(5, 13) 95 +QUBIT_COORDS(5, 14) 96 +QUBIT_COORDS(5, 15) 97 +QUBIT_COORDS(6, 0) 98 +QUBIT_COORDS(6, 1) 99 +QUBIT_COORDS(6, 2) 100 +QUBIT_COORDS(6, 3) 101 +QUBIT_COORDS(6, 4) 102 +QUBIT_COORDS(6, 5) 103 +QUBIT_COORDS(6, 6) 104 +QUBIT_COORDS(6, 7) 105 +QUBIT_COORDS(6, 8) 106 +QUBIT_COORDS(6, 9) 107 +QUBIT_COORDS(6, 10) 108 +QUBIT_COORDS(6, 11) 109 +QUBIT_COORDS(6, 12) 110 +QUBIT_COORDS(6, 13) 111 +QUBIT_COORDS(6, 14) 112 +QUBIT_COORDS(6, 15) 113 +QUBIT_COORDS(7, 0) 114 +QUBIT_COORDS(7, 1) 115 +QUBIT_COORDS(7, 2) 116 +QUBIT_COORDS(7, 3) 117 +QUBIT_COORDS(7, 4) 118 +QUBIT_COORDS(7, 5) 119 +QUBIT_COORDS(7, 6) 120 +QUBIT_COORDS(7, 7) 121 +QUBIT_COORDS(7, 8) 122 +QUBIT_COORDS(7, 9) 123 +QUBIT_COORDS(7, 10) 124 +QUBIT_COORDS(7, 11) 125 +QUBIT_COORDS(7, 12) 126 +QUBIT_COORDS(7, 13) 127 +QUBIT_COORDS(7, 14) 128 +QUBIT_COORDS(7, 15) 129 +QUBIT_COORDS(8, 0) 130 +QUBIT_COORDS(8, 1) 131 +QUBIT_COORDS(8, 2) 132 +QUBIT_COORDS(8, 3) 133 +QUBIT_COORDS(8, 4) 134 +QUBIT_COORDS(8, 5) 135 +QUBIT_COORDS(8, 6) 136 +QUBIT_COORDS(8, 7) 137 +QUBIT_COORDS(8, 8) 138 +QUBIT_COORDS(8, 9) 139 +QUBIT_COORDS(8, 10) 140 +QUBIT_COORDS(8, 11) 141 +QUBIT_COORDS(8, 12) 142 +QUBIT_COORDS(8, 13) 143 +QUBIT_COORDS(8, 14) 144 +QUBIT_COORDS(8, 15) 145 +QUBIT_COORDS(9, 0) 146 +QUBIT_COORDS(9, 1) 147 +QUBIT_COORDS(9, 2) 148 +QUBIT_COORDS(9, 3) 149 +QUBIT_COORDS(9, 4) 150 +QUBIT_COORDS(9, 5) 151 +QUBIT_COORDS(9, 6) 152 +QUBIT_COORDS(9, 7) 153 +QUBIT_COORDS(9, 8) 154 +QUBIT_COORDS(9, 9) 155 +QUBIT_COORDS(9, 10) 156 +QUBIT_COORDS(9, 11) 157 +QUBIT_COORDS(9, 12) 158 +QUBIT_COORDS(9, 13) 159 +QUBIT_COORDS(9, 14) 160 +QUBIT_COORDS(9, 15) 161 +QUBIT_COORDS(10, 0) 162 +QUBIT_COORDS(10, 1) 163 +QUBIT_COORDS(10, 2) 164 +QUBIT_COORDS(10, 3) 165 +QUBIT_COORDS(10, 4) 166 +QUBIT_COORDS(10, 5) 167 +QUBIT_COORDS(10, 6) 168 +QUBIT_COORDS(10, 7) 169 +QUBIT_COORDS(10, 8) 170 +QUBIT_COORDS(10, 9) 171 +QUBIT_COORDS(10, 10) 172 +QUBIT_COORDS(10, 11) 173 +QUBIT_COORDS(10, 12) 174 +QUBIT_COORDS(10, 13) 175 +QUBIT_COORDS(10, 14) 176 +QUBIT_COORDS(10, 15) 177 +QUBIT_COORDS(11, 0) 178 +QUBIT_COORDS(11, 1) 179 +QUBIT_COORDS(11, 2) 180 +QUBIT_COORDS(11, 3) 181 +QUBIT_COORDS(11, 4) 182 +QUBIT_COORDS(11, 5) 183 +QUBIT_COORDS(11, 6) 184 +QUBIT_COORDS(11, 7) 185 +QUBIT_COORDS(11, 8) 186 +QUBIT_COORDS(11, 9) 187 +QUBIT_COORDS(11, 10) 188 +QUBIT_COORDS(11, 11) 189 +QUBIT_COORDS(11, 12) 190 +QUBIT_COORDS(11, 13) 191 +QUBIT_COORDS(11, 14) 192 +QUBIT_COORDS(11, 15) 193 +MPP X4*X17*X18*X19*X178*X179 Z4*Z17*Z18*Z19*Z178*Z179 X5*X8*X22*X23*X182*X183 Z5*Z8*Z22*Z23*Z182*Z183 X9*X12*X26*X27*X186*X187 Z9*Z12*Z26*Z27*Z186*Z187 X13*X16*X30*X31*X190*X191 Z13*Z16*Z30*Z31*Z190*Z191 X4*X5*X19*X22*X36*X37 Z4*Z5*Z19*Z22*Z36*Z37 X8*X9*X23*X26*X40*X41 Z8*Z9*Z23*Z26*Z40*Z41 X12*X13*X27*X30*X44*X45 Z12*Z13*Z27*Z30*Z44*Z45 X16*X17*X18*X31*X48*X49 Z16*Z17*Z18*Z31*Z48*Z49 X18*X19*X36*X49*X50*X51 Z18*Z19*Z36*Z49*Z50*Z51 X22*X23*X37*X40*X54*X55 Z22*Z23*Z37*Z40*Z54*Z55 X26*X27*X41*X44*X58*X59 Z26*Z27*Z41*Z44*Z58*Z59 X30*X31*X45*X48*X62*X63 Z30*Z31*Z45*Z48*Z62*Z63 X36*X37*X51*X54*X68*X69 Z36*Z37*Z51*Z54*Z68*Z69 X40*X41*X55*X58*X72*X73 Z40*Z41*Z55*Z58*Z72*Z73 X44*X45*X59*X62*X76*X77 Z44*Z45*Z59*Z62*Z76*Z77 X48*X49*X50*X63*X80*X81 Z48*Z49*Z50*Z63*Z80*Z81 X50*X51*X68*X81*X82*X83 Z50*Z51*Z68*Z81*Z82*Z83 X54*X55*X69*X72*X86*X87 Z54*Z55*Z69*Z72*Z86*Z87 X58*X59*X73*X76*X90*X91 Z58*Z59*Z73*Z76*Z90*Z91 X62*X63*X77*X80*X94*X95 Z62*Z63*Z77*Z80*Z94*Z95 X68*X69*X83*X86*X100*X101 Z68*Z69*Z83*Z86*Z100*Z101 X72*X73*X87*X90*X104*X105 Z72*Z73*Z87*Z90*Z104*Z105 X76*X77*X91*X94*X108*X109 Z76*Z77*Z91*Z94*Z108*Z109 X80*X81*X82*X95*X112*X113 Z80*Z81*Z82*Z95*Z112*Z113 X82*X83*X100*X113*X114*X115 Z82*Z83*Z100*Z113*Z114*Z115 X86*X87*X101*X104*X118*X119 Z86*Z87*Z101*Z104*Z118*Z119 X90*X91*X105*X108*X122*X123 Z90*Z91*Z105*Z108*Z122*Z123 X94*X95*X109*X112*X126*X127 Z94*Z95*Z109*Z112*Z126*Z127 X100*X101*X115*X118*X132*X133 Z100*Z101*Z115*Z118*Z132*Z133 X104*X105*X119*X122*X136*X137 Z104*Z105*Z119*Z122*Z136*Z137 X108*X109*X123*X126*X140*X141 Z108*Z109*Z123*Z126*Z140*Z141 X112*X113*X114*X127*X144*X145 Z112*Z113*Z114*Z127*Z144*Z145 X114*X115*X132*X145*X146*X147 Z114*Z115*Z132*Z145*Z146*Z147 X118*X119*X133*X136*X150*X151 Z118*Z119*Z133*Z136*Z150*Z151 X122*X123*X137*X140*X154*X155 Z122*Z123*Z137*Z140*Z154*Z155 X126*X127*X141*X144*X158*X159 Z126*Z127*Z141*Z144*Z158*Z159 X132*X133*X147*X150*X164*X165 Z132*Z133*Z147*Z150*Z164*Z165 X136*X137*X151*X154*X168*X169 Z136*Z137*Z151*Z154*Z168*Z169 X140*X141*X155*X158*X172*X173 Z140*Z141*Z155*Z158*Z172*Z173 X144*X145*X146*X159*X176*X177 Z144*Z145*Z146*Z159*Z176*Z177 X146*X147*X164*X177*X178*X179 Z146*Z147*Z164*Z177*Z178*Z179 X150*X151*X165*X168*X182*X183 Z150*Z151*Z165*Z168*Z182*Z183 X154*X155*X169*X172*X186*X187 Z154*Z155*Z169*Z172*Z186*Z187 X158*X159*X173*X176*X190*X191 Z158*Z159*Z173*Z176*Z190*Z191 X4*X5*X164*X165*X179*X182 Z4*Z5*Z164*Z165*Z179*Z182 X8*X9*X168*X169*X183*X186 Z8*Z9*Z168*Z169*Z183*Z186 X12*X13*X172*X173*X187*X190 Z12*Z13*Z172*Z173*Z187*Z190 X16*X17*X176*X177*X178*X191 Z16*Z17*Z176*Z177*Z178*Z191 X1*X4*X5*X8*X9*X12*X13*X16*X17 X0*X22*X37*X69*X86*X118*X133*X165*X182 Z1*Z4*Z19*Z51*Z68*Z100*Z115*Z147*Z164 Z0*Z36*Z37*Z40*Z41*Z44*Z45*Z48*Z49 +OBSERVABLE_INCLUDE(0) rec[-4] +OBSERVABLE_INCLUDE(1) rec[-3] +OBSERVABLE_INCLUDE(2) rec[-2] +OBSERVABLE_INCLUDE(3) rec[-1] +TICK +RX 2 6 10 14 20 24 28 32 34 38 42 46 52 56 60 64 66 70 74 78 84 88 92 96 98 102 106 110 116 120 124 128 130 134 138 142 148 152 156 160 162 166 170 174 180 184 188 192 +R 3 7 11 15 21 25 29 33 35 39 43 47 53 57 61 65 67 71 75 79 85 89 93 97 99 103 107 111 117 121 125 129 131 135 139 143 149 153 157 161 163 167 171 175 181 185 189 193 +X_ERROR(0.001) 3 7 11 15 21 25 29 33 35 39 43 47 53 57 61 65 67 71 75 79 85 89 93 97 99 103 107 111 117 121 125 129 131 135 139 143 149 153 157 161 163 167 171 175 181 185 189 193 +Z_ERROR(0.001) 2 6 10 14 20 24 28 32 34 38 42 46 52 56 60 64 66 70 74 78 84 88 92 96 98 102 106 110 116 120 124 128 130 134 138 142 148 152 156 160 162 166 170 174 180 184 188 192 +DEPOLARIZE1(0.001) 4 5 8 9 12 13 16 17 18 19 22 23 26 27 30 31 36 37 40 41 44 45 48 49 50 51 54 55 58 59 62 63 68 69 72 73 76 77 80 81 82 83 86 87 90 91 94 95 100 101 104 105 108 109 112 113 114 115 118 119 122 123 126 127 132 133 136 137 140 141 144 145 146 147 150 151 154 155 158 159 164 165 168 169 172 173 176 177 178 179 182 183 186 187 190 191 +TICK +CX 2 3 6 7 10 11 14 15 20 21 24 25 28 29 32 33 34 35 38 39 42 43 46 47 52 53 56 57 60 61 64 65 66 67 70 71 74 75 78 79 84 85 88 89 92 93 96 97 98 99 102 103 106 107 110 111 116 117 120 121 124 125 128 129 130 131 134 135 138 139 142 143 148 149 152 153 156 157 160 161 162 163 166 167 170 171 174 175 180 181 184 185 188 189 192 193 +DEPOLARIZE2(0.001) 2 3 6 7 10 11 14 15 20 21 24 25 28 29 32 33 34 35 38 39 42 43 46 47 52 53 56 57 60 61 64 65 66 67 70 71 74 75 78 79 84 85 88 89 92 93 96 97 98 99 102 103 106 107 110 111 116 117 120 121 124 125 128 129 130 131 134 135 138 139 142 143 148 149 152 153 156 157 160 161 162 163 166 167 170 171 174 175 180 181 184 185 188 189 192 193 +DEPOLARIZE1(0.001) 4 5 8 9 12 13 16 17 18 19 22 23 26 27 30 31 36 37 40 41 44 45 48 49 50 51 54 55 58 59 62 63 68 69 72 73 76 77 80 81 82 83 86 87 90 91 94 95 100 101 104 105 108 109 112 113 114 115 118 119 122 123 126 127 132 133 136 137 140 141 144 145 146 147 150 151 154 155 158 159 164 165 168 169 172 173 176 177 178 179 182 183 186 187 190 191 +TICK +CX 4 180 8 184 12 188 16 192 18 2 22 6 26 10 30 14 36 20 40 24 44 28 48 32 50 34 54 38 58 42 62 46 68 52 72 56 76 60 80 64 82 66 86 70 90 74 94 78 100 84 104 88 108 92 112 96 114 98 118 102 122 106 126 110 132 116 136 120 140 124 144 128 146 130 150 134 154 138 158 142 164 148 168 152 172 156 176 160 178 162 182 166 186 170 190 174 5 181 9 185 13 189 17 193 19 3 23 7 27 11 31 15 37 21 41 25 45 29 49 33 51 35 55 39 59 43 63 47 69 53 73 57 77 61 81 65 83 67 87 71 91 75 95 79 101 85 105 89 109 93 113 97 115 99 119 103 123 107 127 111 133 117 137 121 141 125 145 129 147 131 151 135 155 139 159 143 165 149 169 153 173 157 177 161 179 163 183 167 187 171 191 175 +DEPOLARIZE2(0.001) 4 180 8 184 12 188 16 192 18 2 22 6 26 10 30 14 36 20 40 24 44 28 48 32 50 34 54 38 58 42 62 46 68 52 72 56 76 60 80 64 82 66 86 70 90 74 94 78 100 84 104 88 108 92 112 96 114 98 118 102 122 106 126 110 132 116 136 120 140 124 144 128 146 130 150 134 154 138 158 142 164 148 168 152 172 156 176 160 178 162 182 166 186 170 190 174 5 181 9 185 13 189 17 193 19 3 23 7 27 11 31 15 37 21 41 25 45 29 49 33 51 35 55 39 59 43 63 47 69 53 73 57 77 61 81 65 83 67 87 71 91 75 95 79 101 85 105 89 109 93 113 97 115 99 119 103 123 107 127 111 133 117 137 121 141 125 145 129 147 131 151 135 155 139 159 143 165 149 169 153 173 157 177 161 179 163 183 167 187 171 191 175 +TICK +CX 5 6 9 10 13 14 17 2 19 20 23 24 27 28 31 32 37 38 41 42 45 46 49 34 51 52 55 56 59 60 63 64 69 70 73 74 77 78 81 66 83 84 87 88 91 92 95 96 101 102 105 106 109 110 113 98 115 116 119 120 123 124 127 128 133 134 137 138 141 142 145 130 147 148 151 152 155 156 159 160 165 166 169 170 173 174 177 162 179 180 183 184 187 188 191 192 4 3 8 7 12 11 16 15 18 33 22 21 26 25 30 29 36 35 40 39 44 43 48 47 50 65 54 53 58 57 62 61 68 67 72 71 76 75 80 79 82 97 86 85 90 89 94 93 100 99 104 103 108 107 112 111 114 129 118 117 122 121 126 125 132 131 136 135 140 139 144 143 146 161 150 149 154 153 158 157 164 163 168 167 172 171 176 175 178 193 182 181 186 185 190 189 +DEPOLARIZE2(0.001) 5 6 9 10 13 14 17 2 19 20 23 24 27 28 31 32 37 38 41 42 45 46 49 34 51 52 55 56 59 60 63 64 69 70 73 74 77 78 81 66 83 84 87 88 91 92 95 96 101 102 105 106 109 110 113 98 115 116 119 120 123 124 127 128 133 134 137 138 141 142 145 130 147 148 151 152 155 156 159 160 165 166 169 170 173 174 177 162 179 180 183 184 187 188 191 192 4 3 8 7 12 11 16 15 18 33 22 21 26 25 30 29 36 35 40 39 44 43 48 47 50 65 54 53 58 57 62 61 68 67 72 71 76 75 80 79 82 97 86 85 90 89 94 93 100 99 104 103 108 107 112 111 114 129 118 117 122 121 126 125 132 131 136 135 140 139 144 143 146 161 150 149 154 153 158 157 164 163 168 167 172 171 176 175 178 193 182 181 186 185 190 189 +TICK +CX 4 20 8 24 12 28 16 32 18 34 22 38 26 42 30 46 36 52 40 56 44 60 48 64 50 66 54 70 58 74 62 78 68 84 72 88 76 92 80 96 82 98 86 102 90 106 94 110 100 116 104 120 108 124 112 128 114 130 118 134 122 138 126 142 132 148 136 152 140 156 144 160 146 162 150 166 154 170 158 174 164 180 168 184 172 188 176 192 178 2 182 6 186 10 190 14 5 21 9 25 13 29 17 33 19 35 23 39 27 43 31 47 37 53 41 57 45 61 49 65 51 67 55 71 59 75 63 79 69 85 73 89 77 93 81 97 83 99 87 103 91 107 95 111 101 117 105 121 109 125 113 129 115 131 119 135 123 139 127 143 133 149 137 153 141 157 145 161 147 163 151 167 155 171 159 175 165 181 169 185 173 189 177 193 179 3 183 7 187 11 191 15 +DEPOLARIZE2(0.001) 4 20 8 24 12 28 16 32 18 34 22 38 26 42 30 46 36 52 40 56 44 60 48 64 50 66 54 70 58 74 62 78 68 84 72 88 76 92 80 96 82 98 86 102 90 106 94 110 100 116 104 120 108 124 112 128 114 130 118 134 122 138 126 142 132 148 136 152 140 156 144 160 146 162 150 166 154 170 158 174 164 180 168 184 172 188 176 192 178 2 182 6 186 10 190 14 5 21 9 25 13 29 17 33 19 35 23 39 27 43 31 47 37 53 41 57 45 61 49 65 51 67 55 71 59 75 63 79 69 85 73 89 77 93 81 97 83 99 87 103 91 107 95 111 101 117 105 121 109 125 113 129 115 131 119 135 123 139 127 143 133 149 137 153 141 157 145 161 147 163 151 167 155 171 159 175 165 181 169 185 173 189 177 193 179 3 183 7 187 11 191 15 +TICK +CX 2 18 6 22 10 26 14 30 20 36 24 40 28 44 32 48 34 50 38 54 42 58 46 62 52 68 56 72 60 76 64 80 66 82 70 86 74 90 78 94 84 100 88 104 92 108 96 112 98 114 102 118 106 122 110 126 116 132 120 136 124 140 128 144 130 146 134 150 138 154 142 158 148 164 152 168 156 172 160 176 162 178 166 182 170 186 174 190 180 4 184 8 188 12 192 16 3 19 7 23 11 27 15 31 21 37 25 41 29 45 33 49 35 51 39 55 43 59 47 63 53 69 57 73 61 77 65 81 67 83 71 87 75 91 79 95 85 101 89 105 93 109 97 113 99 115 103 119 107 123 111 127 117 133 121 137 125 141 129 145 131 147 135 151 139 155 143 159 149 165 153 169 157 173 161 177 163 179 167 183 171 187 175 191 181 5 185 9 189 13 193 17 +DEPOLARIZE2(0.001) 2 18 6 22 10 26 14 30 20 36 24 40 28 44 32 48 34 50 38 54 42 58 46 62 52 68 56 72 60 76 64 80 66 82 70 86 74 90 78 94 84 100 88 104 92 108 96 112 98 114 102 118 106 122 110 126 116 132 120 136 124 140 128 144 130 146 134 150 138 154 142 158 148 164 152 168 156 172 160 176 162 178 166 182 170 186 174 190 180 4 184 8 188 12 192 16 3 19 7 23 11 27 15 31 21 37 25 41 29 45 33 49 35 51 39 55 43 59 47 63 53 69 57 73 61 77 65 81 67 83 71 87 75 91 79 95 85 101 89 105 93 109 97 113 99 115 103 119 107 123 111 127 117 133 121 137 125 141 129 145 131 147 135 151 139 155 143 159 149 165 153 169 157 173 161 177 163 179 167 183 171 187 175 191 181 5 185 9 189 13 193 17 +TICK +CX 2 17 6 5 10 9 14 13 20 19 24 23 28 27 32 31 34 49 38 37 42 41 46 45 52 51 56 55 60 59 64 63 66 81 70 69 74 73 78 77 84 83 88 87 92 91 96 95 98 113 102 101 106 105 110 109 116 115 120 119 124 123 128 127 130 145 134 133 138 137 142 141 148 147 152 151 156 155 160 159 162 177 166 165 170 169 174 173 180 179 184 183 188 187 192 191 3 4 7 8 11 12 15 16 21 22 25 26 29 30 33 18 35 36 39 40 43 44 47 48 53 54 57 58 61 62 65 50 67 68 71 72 75 76 79 80 85 86 89 90 93 94 97 82 99 100 103 104 107 108 111 112 117 118 121 122 125 126 129 114 131 132 135 136 139 140 143 144 149 150 153 154 157 158 161 146 163 164 167 168 171 172 175 176 181 182 185 186 189 190 193 178 +DEPOLARIZE2(0.001) 2 17 6 5 10 9 14 13 20 19 24 23 28 27 32 31 34 49 38 37 42 41 46 45 52 51 56 55 60 59 64 63 66 81 70 69 74 73 78 77 84 83 88 87 92 91 96 95 98 113 102 101 106 105 110 109 116 115 120 119 124 123 128 127 130 145 134 133 138 137 142 141 148 147 152 151 156 155 160 159 162 177 166 165 170 169 174 173 180 179 184 183 188 187 192 191 3 4 7 8 11 12 15 16 21 22 25 26 29 30 33 18 35 36 39 40 43 44 47 48 53 54 57 58 61 62 65 50 67 68 71 72 75 76 79 80 85 86 89 90 93 94 97 82 99 100 103 104 107 108 111 112 117 118 121 122 125 126 129 114 131 132 135 136 139 140 143 144 149 150 153 154 157 158 161 146 163 164 167 168 171 172 175 176 181 182 185 186 189 190 193 178 +TICK +CX 2 178 6 182 10 186 14 190 20 4 24 8 28 12 32 16 34 18 38 22 42 26 46 30 52 36 56 40 60 44 64 48 66 50 70 54 74 58 78 62 84 68 88 72 92 76 96 80 98 82 102 86 106 90 110 94 116 100 120 104 124 108 128 112 130 114 134 118 138 122 142 126 148 132 152 136 156 140 160 144 162 146 166 150 170 154 174 158 180 164 184 168 188 172 192 176 3 179 7 183 11 187 15 191 21 5 25 9 29 13 33 17 35 19 39 23 43 27 47 31 53 37 57 41 61 45 65 49 67 51 71 55 75 59 79 63 85 69 89 73 93 77 97 81 99 83 103 87 107 91 111 95 117 101 121 105 125 109 129 113 131 115 135 119 139 123 143 127 149 133 153 137 157 141 161 145 163 147 167 151 171 155 175 159 181 165 185 169 189 173 193 177 +DEPOLARIZE2(0.001) 2 178 6 182 10 186 14 190 20 4 24 8 28 12 32 16 34 18 38 22 42 26 46 30 52 36 56 40 60 44 64 48 66 50 70 54 74 58 78 62 84 68 88 72 92 76 96 80 98 82 102 86 106 90 110 94 116 100 120 104 124 108 128 112 130 114 134 118 138 122 142 126 148 132 152 136 156 140 160 144 162 146 166 150 170 154 174 158 180 164 184 168 188 172 192 176 3 179 7 183 11 187 15 191 21 5 25 9 29 13 33 17 35 19 39 23 43 27 47 31 53 37 57 41 61 45 65 49 67 51 71 55 75 59 79 63 85 69 89 73 93 77 97 81 99 83 103 87 107 91 111 95 117 101 121 105 125 109 129 113 131 115 135 119 139 123 143 127 149 133 153 137 157 141 161 145 163 147 167 151 171 155 175 159 181 165 185 169 189 173 193 177 +TICK +CX 2 3 6 7 10 11 14 15 20 21 24 25 28 29 32 33 34 35 38 39 42 43 46 47 52 53 56 57 60 61 64 65 66 67 70 71 74 75 78 79 84 85 88 89 92 93 96 97 98 99 102 103 106 107 110 111 116 117 120 121 124 125 128 129 130 131 134 135 138 139 142 143 148 149 152 153 156 157 160 161 162 163 166 167 170 171 174 175 180 181 184 185 188 189 192 193 +DEPOLARIZE2(0.001) 2 3 6 7 10 11 14 15 20 21 24 25 28 29 32 33 34 35 38 39 42 43 46 47 52 53 56 57 60 61 64 65 66 67 70 71 74 75 78 79 84 85 88 89 92 93 96 97 98 99 102 103 106 107 110 111 116 117 120 121 124 125 128 129 130 131 134 135 138 139 142 143 148 149 152 153 156 157 160 161 162 163 166 167 170 171 174 175 180 181 184 185 188 189 192 193 +DEPOLARIZE1(0.001) 4 5 8 9 12 13 16 17 18 19 22 23 26 27 30 31 36 37 40 41 44 45 48 49 50 51 54 55 58 59 62 63 68 69 72 73 76 77 80 81 82 83 86 87 90 91 94 95 100 101 104 105 108 109 112 113 114 115 118 119 122 123 126 127 132 133 136 137 140 141 144 145 146 147 150 151 154 155 158 159 164 165 168 169 172 173 176 177 178 179 182 183 186 187 190 191 +TICK +MX(0.001) 2 6 10 14 20 24 28 32 34 38 42 46 52 56 60 64 66 70 74 78 84 88 92 96 98 102 106 110 116 120 124 128 130 134 138 142 148 152 156 160 162 166 170 174 180 184 188 192 +M(0.001) 3 7 11 15 21 25 29 33 35 39 43 47 53 57 61 65 67 71 75 79 85 89 93 97 99 103 107 111 117 121 125 129 131 135 139 143 149 153 157 161 163 167 171 175 181 185 189 193 +DEPOLARIZE1(0.001) 2 6 10 14 20 24 28 32 34 38 42 46 52 56 60 64 66 70 74 78 84 88 92 96 98 102 106 110 116 120 124 128 130 134 138 142 148 152 156 160 162 166 170 174 180 184 188 192 3 7 11 15 21 25 29 33 35 39 43 47 53 57 61 65 67 71 75 79 85 89 93 97 99 103 107 111 117 121 125 129 131 135 139 143 149 153 157 161 163 167 171 175 181 185 189 193 4 5 8 9 12 13 16 17 18 19 22 23 26 27 30 31 36 37 40 41 44 45 48 49 50 51 54 55 58 59 62 63 68 69 72 73 76 77 80 81 82 83 86 87 90 91 94 95 100 101 104 105 108 109 112 113 114 115 118 119 122 123 126 127 132 133 136 137 140 141 144 145 146 147 150 151 154 155 158 159 164 165 168 169 172 173 176 177 178 179 182 183 186 187 190 191 +DETECTOR(0, 0, 0, 0) rec[-196] rec[-96] +DETECTOR(0, 1, 0, 3) rec[-195] rec[-48] +DETECTOR(0, 4, 0, 0) rec[-194] rec[-95] +DETECTOR(0, 5, 0, 3) rec[-193] rec[-47] +DETECTOR(0, 8, 0, 0) rec[-192] rec[-94] +DETECTOR(0, 9, 0, 3) rec[-191] rec[-46] +DETECTOR(0, 12, 0, 0) rec[-190] rec[-93] +DETECTOR(0, 13, 0, 3) rec[-189] rec[-45] +DETECTOR(1, 2, 0, 1) rec[-188] rec[-92] +DETECTOR(1, 3, 0, 4) rec[-187] rec[-44] +DETECTOR(1, 6, 0, 1) rec[-186] rec[-91] +DETECTOR(1, 7, 0, 4) rec[-185] rec[-43] +DETECTOR(1, 10, 0, 1) rec[-184] rec[-90] +DETECTOR(1, 11, 0, 4) rec[-183] rec[-42] +DETECTOR(1, 14, 0, 1) rec[-182] rec[-89] +DETECTOR(1, 15, 0, 4) rec[-181] rec[-41] +DETECTOR(2, 0, 0, 2) rec[-180] rec[-88] +DETECTOR(2, 1, 0, 5) rec[-179] rec[-40] +DETECTOR(2, 4, 0, 2) rec[-178] rec[-87] +DETECTOR(2, 5, 0, 5) rec[-177] rec[-39] +DETECTOR(2, 8, 0, 2) rec[-176] rec[-86] +DETECTOR(2, 9, 0, 5) rec[-175] rec[-38] +DETECTOR(2, 12, 0, 2) rec[-174] rec[-85] +DETECTOR(2, 13, 0, 5) rec[-173] rec[-37] +DETECTOR(3, 2, 0, 0) rec[-172] rec[-84] +DETECTOR(3, 3, 0, 3) rec[-171] rec[-36] +DETECTOR(3, 6, 0, 0) rec[-170] rec[-83] +DETECTOR(3, 7, 0, 3) rec[-169] rec[-35] +DETECTOR(3, 10, 0, 0) rec[-168] rec[-82] +DETECTOR(3, 11, 0, 3) rec[-167] rec[-34] +DETECTOR(3, 14, 0, 0) rec[-166] rec[-81] +DETECTOR(3, 15, 0, 3) rec[-165] rec[-33] +DETECTOR(4, 0, 0, 1) rec[-164] rec[-80] +DETECTOR(4, 1, 0, 4) rec[-163] rec[-32] +DETECTOR(4, 4, 0, 1) rec[-162] rec[-79] +DETECTOR(4, 5, 0, 4) rec[-161] rec[-31] +DETECTOR(4, 8, 0, 1) rec[-160] rec[-78] +DETECTOR(4, 9, 0, 4) rec[-159] rec[-30] +DETECTOR(4, 12, 0, 1) rec[-158] rec[-77] +DETECTOR(4, 13, 0, 4) rec[-157] rec[-29] +DETECTOR(5, 2, 0, 2) rec[-156] rec[-76] +DETECTOR(5, 3, 0, 5) rec[-155] rec[-28] +DETECTOR(5, 6, 0, 2) rec[-154] rec[-75] +DETECTOR(5, 7, 0, 5) rec[-153] rec[-27] +DETECTOR(5, 10, 0, 2) rec[-152] rec[-74] +DETECTOR(5, 11, 0, 5) rec[-151] rec[-26] +DETECTOR(5, 14, 0, 2) rec[-150] rec[-73] +DETECTOR(5, 15, 0, 5) rec[-149] rec[-25] +DETECTOR(6, 0, 0, 0) rec[-148] rec[-72] +DETECTOR(6, 1, 0, 3) rec[-147] rec[-24] +DETECTOR(6, 4, 0, 0) rec[-146] rec[-71] +DETECTOR(6, 5, 0, 3) rec[-145] rec[-23] +DETECTOR(6, 8, 0, 0) rec[-144] rec[-70] +DETECTOR(6, 9, 0, 3) rec[-143] rec[-22] +DETECTOR(6, 12, 0, 0) rec[-142] rec[-69] +DETECTOR(6, 13, 0, 3) rec[-141] rec[-21] +DETECTOR(7, 2, 0, 1) rec[-140] rec[-68] +DETECTOR(7, 3, 0, 4) rec[-139] rec[-20] +DETECTOR(7, 6, 0, 1) rec[-138] rec[-67] +DETECTOR(7, 7, 0, 4) rec[-137] rec[-19] +DETECTOR(7, 10, 0, 1) rec[-136] rec[-66] +DETECTOR(7, 11, 0, 4) rec[-135] rec[-18] +DETECTOR(7, 14, 0, 1) rec[-134] rec[-65] +DETECTOR(7, 15, 0, 4) rec[-133] rec[-17] +DETECTOR(8, 0, 0, 2) rec[-132] rec[-64] +DETECTOR(8, 1, 0, 5) rec[-131] rec[-16] +DETECTOR(8, 4, 0, 2) rec[-130] rec[-63] +DETECTOR(8, 5, 0, 5) rec[-129] rec[-15] +DETECTOR(8, 8, 0, 2) rec[-128] rec[-62] +DETECTOR(8, 9, 0, 5) rec[-127] rec[-14] +DETECTOR(8, 12, 0, 2) rec[-126] rec[-61] +DETECTOR(8, 13, 0, 5) rec[-125] rec[-13] +DETECTOR(9, 2, 0, 0) rec[-124] rec[-60] +DETECTOR(9, 3, 0, 3) rec[-123] rec[-12] +DETECTOR(9, 6, 0, 0) rec[-122] rec[-59] +DETECTOR(9, 7, 0, 3) rec[-121] rec[-11] +DETECTOR(9, 10, 0, 0) rec[-120] rec[-58] +DETECTOR(9, 11, 0, 3) rec[-119] rec[-10] +DETECTOR(9, 14, 0, 0) rec[-118] rec[-57] +DETECTOR(9, 15, 0, 3) rec[-117] rec[-9] +DETECTOR(10, 0, 0, 1) rec[-116] rec[-56] +DETECTOR(10, 1, 0, 4) rec[-115] rec[-8] +DETECTOR(10, 4, 0, 1) rec[-114] rec[-55] +DETECTOR(10, 5, 0, 4) rec[-113] rec[-7] +DETECTOR(10, 8, 0, 1) rec[-112] rec[-54] +DETECTOR(10, 9, 0, 4) rec[-111] rec[-6] +DETECTOR(10, 12, 0, 1) rec[-110] rec[-53] +DETECTOR(10, 13, 0, 4) rec[-109] rec[-5] +DETECTOR(11, 2, 0, 2) rec[-108] rec[-52] +DETECTOR(11, 3, 0, 5) rec[-107] rec[-4] +DETECTOR(11, 6, 0, 2) rec[-106] rec[-51] +DETECTOR(11, 7, 0, 5) rec[-105] rec[-3] +DETECTOR(11, 10, 0, 2) rec[-104] rec[-50] +DETECTOR(11, 11, 0, 5) rec[-103] rec[-2] +DETECTOR(11, 14, 0, 2) rec[-102] rec[-49] +DETECTOR(11, 15, 0, 5) rec[-101] rec[-1] +OBSERVABLE_INCLUDE(3) rec[-44] rec[-43] rec[-42] rec[-41] rec[-40] rec[-39] rec[-38] rec[-37] rec[-36] rec[-35] rec[-34] rec[-33] +SHIFT_COORDS(0, 0, 1) +TICK +REPEAT 4 { + RX 2 6 10 14 20 24 28 32 34 38 42 46 52 56 60 64 66 70 74 78 84 88 92 96 98 102 106 110 116 120 124 128 130 134 138 142 148 152 156 160 162 166 170 174 180 184 188 192 + R 3 7 11 15 21 25 29 33 35 39 43 47 53 57 61 65 67 71 75 79 85 89 93 97 99 103 107 111 117 121 125 129 131 135 139 143 149 153 157 161 163 167 171 175 181 185 189 193 + X_ERROR(0.001) 3 7 11 15 21 25 29 33 35 39 43 47 53 57 61 65 67 71 75 79 85 89 93 97 99 103 107 111 117 121 125 129 131 135 139 143 149 153 157 161 163 167 171 175 181 185 189 193 + Z_ERROR(0.001) 2 6 10 14 20 24 28 32 34 38 42 46 52 56 60 64 66 70 74 78 84 88 92 96 98 102 106 110 116 120 124 128 130 134 138 142 148 152 156 160 162 166 170 174 180 184 188 192 + DEPOLARIZE1(0.001) 4 5 8 9 12 13 16 17 18 19 22 23 26 27 30 31 36 37 40 41 44 45 48 49 50 51 54 55 58 59 62 63 68 69 72 73 76 77 80 81 82 83 86 87 90 91 94 95 100 101 104 105 108 109 112 113 114 115 118 119 122 123 126 127 132 133 136 137 140 141 144 145 146 147 150 151 154 155 158 159 164 165 168 169 172 173 176 177 178 179 182 183 186 187 190 191 + TICK + CX 2 3 6 7 10 11 14 15 20 21 24 25 28 29 32 33 34 35 38 39 42 43 46 47 52 53 56 57 60 61 64 65 66 67 70 71 74 75 78 79 84 85 88 89 92 93 96 97 98 99 102 103 106 107 110 111 116 117 120 121 124 125 128 129 130 131 134 135 138 139 142 143 148 149 152 153 156 157 160 161 162 163 166 167 170 171 174 175 180 181 184 185 188 189 192 193 + DEPOLARIZE2(0.001) 2 3 6 7 10 11 14 15 20 21 24 25 28 29 32 33 34 35 38 39 42 43 46 47 52 53 56 57 60 61 64 65 66 67 70 71 74 75 78 79 84 85 88 89 92 93 96 97 98 99 102 103 106 107 110 111 116 117 120 121 124 125 128 129 130 131 134 135 138 139 142 143 148 149 152 153 156 157 160 161 162 163 166 167 170 171 174 175 180 181 184 185 188 189 192 193 + DEPOLARIZE1(0.001) 4 5 8 9 12 13 16 17 18 19 22 23 26 27 30 31 36 37 40 41 44 45 48 49 50 51 54 55 58 59 62 63 68 69 72 73 76 77 80 81 82 83 86 87 90 91 94 95 100 101 104 105 108 109 112 113 114 115 118 119 122 123 126 127 132 133 136 137 140 141 144 145 146 147 150 151 154 155 158 159 164 165 168 169 172 173 176 177 178 179 182 183 186 187 190 191 + TICK + CX 4 180 8 184 12 188 16 192 18 2 22 6 26 10 30 14 36 20 40 24 44 28 48 32 50 34 54 38 58 42 62 46 68 52 72 56 76 60 80 64 82 66 86 70 90 74 94 78 100 84 104 88 108 92 112 96 114 98 118 102 122 106 126 110 132 116 136 120 140 124 144 128 146 130 150 134 154 138 158 142 164 148 168 152 172 156 176 160 178 162 182 166 186 170 190 174 5 181 9 185 13 189 17 193 19 3 23 7 27 11 31 15 37 21 41 25 45 29 49 33 51 35 55 39 59 43 63 47 69 53 73 57 77 61 81 65 83 67 87 71 91 75 95 79 101 85 105 89 109 93 113 97 115 99 119 103 123 107 127 111 133 117 137 121 141 125 145 129 147 131 151 135 155 139 159 143 165 149 169 153 173 157 177 161 179 163 183 167 187 171 191 175 + DEPOLARIZE2(0.001) 4 180 8 184 12 188 16 192 18 2 22 6 26 10 30 14 36 20 40 24 44 28 48 32 50 34 54 38 58 42 62 46 68 52 72 56 76 60 80 64 82 66 86 70 90 74 94 78 100 84 104 88 108 92 112 96 114 98 118 102 122 106 126 110 132 116 136 120 140 124 144 128 146 130 150 134 154 138 158 142 164 148 168 152 172 156 176 160 178 162 182 166 186 170 190 174 5 181 9 185 13 189 17 193 19 3 23 7 27 11 31 15 37 21 41 25 45 29 49 33 51 35 55 39 59 43 63 47 69 53 73 57 77 61 81 65 83 67 87 71 91 75 95 79 101 85 105 89 109 93 113 97 115 99 119 103 123 107 127 111 133 117 137 121 141 125 145 129 147 131 151 135 155 139 159 143 165 149 169 153 173 157 177 161 179 163 183 167 187 171 191 175 + TICK + CX 5 6 9 10 13 14 17 2 19 20 23 24 27 28 31 32 37 38 41 42 45 46 49 34 51 52 55 56 59 60 63 64 69 70 73 74 77 78 81 66 83 84 87 88 91 92 95 96 101 102 105 106 109 110 113 98 115 116 119 120 123 124 127 128 133 134 137 138 141 142 145 130 147 148 151 152 155 156 159 160 165 166 169 170 173 174 177 162 179 180 183 184 187 188 191 192 4 3 8 7 12 11 16 15 18 33 22 21 26 25 30 29 36 35 40 39 44 43 48 47 50 65 54 53 58 57 62 61 68 67 72 71 76 75 80 79 82 97 86 85 90 89 94 93 100 99 104 103 108 107 112 111 114 129 118 117 122 121 126 125 132 131 136 135 140 139 144 143 146 161 150 149 154 153 158 157 164 163 168 167 172 171 176 175 178 193 182 181 186 185 190 189 + DEPOLARIZE2(0.001) 5 6 9 10 13 14 17 2 19 20 23 24 27 28 31 32 37 38 41 42 45 46 49 34 51 52 55 56 59 60 63 64 69 70 73 74 77 78 81 66 83 84 87 88 91 92 95 96 101 102 105 106 109 110 113 98 115 116 119 120 123 124 127 128 133 134 137 138 141 142 145 130 147 148 151 152 155 156 159 160 165 166 169 170 173 174 177 162 179 180 183 184 187 188 191 192 4 3 8 7 12 11 16 15 18 33 22 21 26 25 30 29 36 35 40 39 44 43 48 47 50 65 54 53 58 57 62 61 68 67 72 71 76 75 80 79 82 97 86 85 90 89 94 93 100 99 104 103 108 107 112 111 114 129 118 117 122 121 126 125 132 131 136 135 140 139 144 143 146 161 150 149 154 153 158 157 164 163 168 167 172 171 176 175 178 193 182 181 186 185 190 189 + TICK + CX 4 20 8 24 12 28 16 32 18 34 22 38 26 42 30 46 36 52 40 56 44 60 48 64 50 66 54 70 58 74 62 78 68 84 72 88 76 92 80 96 82 98 86 102 90 106 94 110 100 116 104 120 108 124 112 128 114 130 118 134 122 138 126 142 132 148 136 152 140 156 144 160 146 162 150 166 154 170 158 174 164 180 168 184 172 188 176 192 178 2 182 6 186 10 190 14 5 21 9 25 13 29 17 33 19 35 23 39 27 43 31 47 37 53 41 57 45 61 49 65 51 67 55 71 59 75 63 79 69 85 73 89 77 93 81 97 83 99 87 103 91 107 95 111 101 117 105 121 109 125 113 129 115 131 119 135 123 139 127 143 133 149 137 153 141 157 145 161 147 163 151 167 155 171 159 175 165 181 169 185 173 189 177 193 179 3 183 7 187 11 191 15 + DEPOLARIZE2(0.001) 4 20 8 24 12 28 16 32 18 34 22 38 26 42 30 46 36 52 40 56 44 60 48 64 50 66 54 70 58 74 62 78 68 84 72 88 76 92 80 96 82 98 86 102 90 106 94 110 100 116 104 120 108 124 112 128 114 130 118 134 122 138 126 142 132 148 136 152 140 156 144 160 146 162 150 166 154 170 158 174 164 180 168 184 172 188 176 192 178 2 182 6 186 10 190 14 5 21 9 25 13 29 17 33 19 35 23 39 27 43 31 47 37 53 41 57 45 61 49 65 51 67 55 71 59 75 63 79 69 85 73 89 77 93 81 97 83 99 87 103 91 107 95 111 101 117 105 121 109 125 113 129 115 131 119 135 123 139 127 143 133 149 137 153 141 157 145 161 147 163 151 167 155 171 159 175 165 181 169 185 173 189 177 193 179 3 183 7 187 11 191 15 + TICK + CX 2 18 6 22 10 26 14 30 20 36 24 40 28 44 32 48 34 50 38 54 42 58 46 62 52 68 56 72 60 76 64 80 66 82 70 86 74 90 78 94 84 100 88 104 92 108 96 112 98 114 102 118 106 122 110 126 116 132 120 136 124 140 128 144 130 146 134 150 138 154 142 158 148 164 152 168 156 172 160 176 162 178 166 182 170 186 174 190 180 4 184 8 188 12 192 16 3 19 7 23 11 27 15 31 21 37 25 41 29 45 33 49 35 51 39 55 43 59 47 63 53 69 57 73 61 77 65 81 67 83 71 87 75 91 79 95 85 101 89 105 93 109 97 113 99 115 103 119 107 123 111 127 117 133 121 137 125 141 129 145 131 147 135 151 139 155 143 159 149 165 153 169 157 173 161 177 163 179 167 183 171 187 175 191 181 5 185 9 189 13 193 17 + DEPOLARIZE2(0.001) 2 18 6 22 10 26 14 30 20 36 24 40 28 44 32 48 34 50 38 54 42 58 46 62 52 68 56 72 60 76 64 80 66 82 70 86 74 90 78 94 84 100 88 104 92 108 96 112 98 114 102 118 106 122 110 126 116 132 120 136 124 140 128 144 130 146 134 150 138 154 142 158 148 164 152 168 156 172 160 176 162 178 166 182 170 186 174 190 180 4 184 8 188 12 192 16 3 19 7 23 11 27 15 31 21 37 25 41 29 45 33 49 35 51 39 55 43 59 47 63 53 69 57 73 61 77 65 81 67 83 71 87 75 91 79 95 85 101 89 105 93 109 97 113 99 115 103 119 107 123 111 127 117 133 121 137 125 141 129 145 131 147 135 151 139 155 143 159 149 165 153 169 157 173 161 177 163 179 167 183 171 187 175 191 181 5 185 9 189 13 193 17 + TICK + CX 2 17 6 5 10 9 14 13 20 19 24 23 28 27 32 31 34 49 38 37 42 41 46 45 52 51 56 55 60 59 64 63 66 81 70 69 74 73 78 77 84 83 88 87 92 91 96 95 98 113 102 101 106 105 110 109 116 115 120 119 124 123 128 127 130 145 134 133 138 137 142 141 148 147 152 151 156 155 160 159 162 177 166 165 170 169 174 173 180 179 184 183 188 187 192 191 3 4 7 8 11 12 15 16 21 22 25 26 29 30 33 18 35 36 39 40 43 44 47 48 53 54 57 58 61 62 65 50 67 68 71 72 75 76 79 80 85 86 89 90 93 94 97 82 99 100 103 104 107 108 111 112 117 118 121 122 125 126 129 114 131 132 135 136 139 140 143 144 149 150 153 154 157 158 161 146 163 164 167 168 171 172 175 176 181 182 185 186 189 190 193 178 + DEPOLARIZE2(0.001) 2 17 6 5 10 9 14 13 20 19 24 23 28 27 32 31 34 49 38 37 42 41 46 45 52 51 56 55 60 59 64 63 66 81 70 69 74 73 78 77 84 83 88 87 92 91 96 95 98 113 102 101 106 105 110 109 116 115 120 119 124 123 128 127 130 145 134 133 138 137 142 141 148 147 152 151 156 155 160 159 162 177 166 165 170 169 174 173 180 179 184 183 188 187 192 191 3 4 7 8 11 12 15 16 21 22 25 26 29 30 33 18 35 36 39 40 43 44 47 48 53 54 57 58 61 62 65 50 67 68 71 72 75 76 79 80 85 86 89 90 93 94 97 82 99 100 103 104 107 108 111 112 117 118 121 122 125 126 129 114 131 132 135 136 139 140 143 144 149 150 153 154 157 158 161 146 163 164 167 168 171 172 175 176 181 182 185 186 189 190 193 178 + TICK + CX 2 178 6 182 10 186 14 190 20 4 24 8 28 12 32 16 34 18 38 22 42 26 46 30 52 36 56 40 60 44 64 48 66 50 70 54 74 58 78 62 84 68 88 72 92 76 96 80 98 82 102 86 106 90 110 94 116 100 120 104 124 108 128 112 130 114 134 118 138 122 142 126 148 132 152 136 156 140 160 144 162 146 166 150 170 154 174 158 180 164 184 168 188 172 192 176 3 179 7 183 11 187 15 191 21 5 25 9 29 13 33 17 35 19 39 23 43 27 47 31 53 37 57 41 61 45 65 49 67 51 71 55 75 59 79 63 85 69 89 73 93 77 97 81 99 83 103 87 107 91 111 95 117 101 121 105 125 109 129 113 131 115 135 119 139 123 143 127 149 133 153 137 157 141 161 145 163 147 167 151 171 155 175 159 181 165 185 169 189 173 193 177 + DEPOLARIZE2(0.001) 2 178 6 182 10 186 14 190 20 4 24 8 28 12 32 16 34 18 38 22 42 26 46 30 52 36 56 40 60 44 64 48 66 50 70 54 74 58 78 62 84 68 88 72 92 76 96 80 98 82 102 86 106 90 110 94 116 100 120 104 124 108 128 112 130 114 134 118 138 122 142 126 148 132 152 136 156 140 160 144 162 146 166 150 170 154 174 158 180 164 184 168 188 172 192 176 3 179 7 183 11 187 15 191 21 5 25 9 29 13 33 17 35 19 39 23 43 27 47 31 53 37 57 41 61 45 65 49 67 51 71 55 75 59 79 63 85 69 89 73 93 77 97 81 99 83 103 87 107 91 111 95 117 101 121 105 125 109 129 113 131 115 135 119 139 123 143 127 149 133 153 137 157 141 161 145 163 147 167 151 171 155 175 159 181 165 185 169 189 173 193 177 + TICK + CX 2 3 6 7 10 11 14 15 20 21 24 25 28 29 32 33 34 35 38 39 42 43 46 47 52 53 56 57 60 61 64 65 66 67 70 71 74 75 78 79 84 85 88 89 92 93 96 97 98 99 102 103 106 107 110 111 116 117 120 121 124 125 128 129 130 131 134 135 138 139 142 143 148 149 152 153 156 157 160 161 162 163 166 167 170 171 174 175 180 181 184 185 188 189 192 193 + DEPOLARIZE2(0.001) 2 3 6 7 10 11 14 15 20 21 24 25 28 29 32 33 34 35 38 39 42 43 46 47 52 53 56 57 60 61 64 65 66 67 70 71 74 75 78 79 84 85 88 89 92 93 96 97 98 99 102 103 106 107 110 111 116 117 120 121 124 125 128 129 130 131 134 135 138 139 142 143 148 149 152 153 156 157 160 161 162 163 166 167 170 171 174 175 180 181 184 185 188 189 192 193 + DEPOLARIZE1(0.001) 4 5 8 9 12 13 16 17 18 19 22 23 26 27 30 31 36 37 40 41 44 45 48 49 50 51 54 55 58 59 62 63 68 69 72 73 76 77 80 81 82 83 86 87 90 91 94 95 100 101 104 105 108 109 112 113 114 115 118 119 122 123 126 127 132 133 136 137 140 141 144 145 146 147 150 151 154 155 158 159 164 165 168 169 172 173 176 177 178 179 182 183 186 187 190 191 + TICK + MX(0.001) 2 6 10 14 20 24 28 32 34 38 42 46 52 56 60 64 66 70 74 78 84 88 92 96 98 102 106 110 116 120 124 128 130 134 138 142 148 152 156 160 162 166 170 174 180 184 188 192 + M(0.001) 3 7 11 15 21 25 29 33 35 39 43 47 53 57 61 65 67 71 75 79 85 89 93 97 99 103 107 111 117 121 125 129 131 135 139 143 149 153 157 161 163 167 171 175 181 185 189 193 + DEPOLARIZE1(0.001) 2 6 10 14 20 24 28 32 34 38 42 46 52 56 60 64 66 70 74 78 84 88 92 96 98 102 106 110 116 120 124 128 130 134 138 142 148 152 156 160 162 166 170 174 180 184 188 192 3 7 11 15 21 25 29 33 35 39 43 47 53 57 61 65 67 71 75 79 85 89 93 97 99 103 107 111 117 121 125 129 131 135 139 143 149 153 157 161 163 167 171 175 181 185 189 193 4 5 8 9 12 13 16 17 18 19 22 23 26 27 30 31 36 37 40 41 44 45 48 49 50 51 54 55 58 59 62 63 68 69 72 73 76 77 80 81 82 83 86 87 90 91 94 95 100 101 104 105 108 109 112 113 114 115 118 119 122 123 126 127 132 133 136 137 140 141 144 145 146 147 150 151 154 155 158 159 164 165 168 169 172 173 176 177 178 179 182 183 186 187 190 191 + DETECTOR(0, 0, 0, 0) rec[-192] rec[-96] + DETECTOR(0, 1, 0, 3) rec[-136] rec[-104] rec[-48] + DETECTOR(0, 4, 0, 0) rec[-191] rec[-95] + DETECTOR(0, 5, 0, 3) rec[-135] rec[-103] rec[-47] + DETECTOR(0, 8, 0, 0) rec[-190] rec[-94] + DETECTOR(0, 9, 0, 3) rec[-134] rec[-102] rec[-46] + DETECTOR(0, 12, 0, 0) rec[-189] rec[-93] + DETECTOR(0, 13, 0, 3) rec[-133] rec[-101] rec[-45] + DETECTOR(1, 2, 0, 1) rec[-188] rec[-92] + DETECTOR(1, 3, 0, 4) rec[-132] rec[-100] rec[-44] + DETECTOR(1, 6, 0, 1) rec[-187] rec[-91] + DETECTOR(1, 7, 0, 4) rec[-131] rec[-99] rec[-43] + DETECTOR(1, 10, 0, 1) rec[-186] rec[-90] + DETECTOR(1, 11, 0, 4) rec[-130] rec[-98] rec[-42] + DETECTOR(1, 14, 0, 1) rec[-185] rec[-89] + DETECTOR(1, 15, 0, 4) rec[-129] rec[-97] rec[-41] + DETECTOR(2, 0, 0, 2) rec[-184] rec[-88] + DETECTOR(2, 1, 0, 5) rec[-144] rec[-128] rec[-40] + DETECTOR(2, 4, 0, 2) rec[-183] rec[-87] + DETECTOR(2, 5, 0, 5) rec[-143] rec[-127] rec[-39] + DETECTOR(2, 8, 0, 2) rec[-182] rec[-86] + DETECTOR(2, 9, 0, 5) rec[-142] rec[-126] rec[-38] + DETECTOR(2, 12, 0, 2) rec[-181] rec[-85] + DETECTOR(2, 13, 0, 5) rec[-141] rec[-125] rec[-37] + DETECTOR(3, 2, 0, 0) rec[-180] rec[-84] + DETECTOR(3, 3, 0, 3) rec[-140] rec[-124] rec[-36] + DETECTOR(3, 6, 0, 0) rec[-179] rec[-83] + DETECTOR(3, 7, 0, 3) rec[-139] rec[-123] rec[-35] + DETECTOR(3, 10, 0, 0) rec[-178] rec[-82] + DETECTOR(3, 11, 0, 3) rec[-138] rec[-122] rec[-34] + DETECTOR(3, 14, 0, 0) rec[-177] rec[-81] + DETECTOR(3, 15, 0, 3) rec[-137] rec[-121] rec[-33] + DETECTOR(4, 0, 0, 1) rec[-176] rec[-80] + DETECTOR(4, 1, 0, 4) rec[-136] rec[-120] rec[-32] + DETECTOR(4, 4, 0, 1) rec[-175] rec[-79] + DETECTOR(4, 5, 0, 4) rec[-135] rec[-119] rec[-31] + DETECTOR(4, 8, 0, 1) rec[-174] rec[-78] + DETECTOR(4, 9, 0, 4) rec[-134] rec[-118] rec[-30] + DETECTOR(4, 12, 0, 1) rec[-173] rec[-77] + DETECTOR(4, 13, 0, 4) rec[-133] rec[-117] rec[-29] + DETECTOR(5, 2, 0, 2) rec[-172] rec[-76] + DETECTOR(5, 3, 0, 5) rec[-132] rec[-116] rec[-28] + DETECTOR(5, 6, 0, 2) rec[-171] rec[-75] + DETECTOR(5, 7, 0, 5) rec[-131] rec[-115] rec[-27] + DETECTOR(5, 10, 0, 2) rec[-170] rec[-74] + DETECTOR(5, 11, 0, 5) rec[-130] rec[-114] rec[-26] + DETECTOR(5, 14, 0, 2) rec[-169] rec[-73] + DETECTOR(5, 15, 0, 5) rec[-129] rec[-113] rec[-25] + DETECTOR(6, 0, 0, 0) rec[-168] rec[-72] + DETECTOR(6, 1, 0, 3) rec[-128] rec[-112] rec[-24] + DETECTOR(6, 4, 0, 0) rec[-167] rec[-71] + DETECTOR(6, 5, 0, 3) rec[-127] rec[-111] rec[-23] + DETECTOR(6, 8, 0, 0) rec[-166] rec[-70] + DETECTOR(6, 9, 0, 3) rec[-126] rec[-110] rec[-22] + DETECTOR(6, 12, 0, 0) rec[-165] rec[-69] + DETECTOR(6, 13, 0, 3) rec[-125] rec[-109] rec[-21] + DETECTOR(7, 2, 0, 1) rec[-164] rec[-68] + DETECTOR(7, 3, 0, 4) rec[-124] rec[-108] rec[-20] + DETECTOR(7, 6, 0, 1) rec[-163] rec[-67] + DETECTOR(7, 7, 0, 4) rec[-123] rec[-107] rec[-19] + DETECTOR(7, 10, 0, 1) rec[-162] rec[-66] + DETECTOR(7, 11, 0, 4) rec[-122] rec[-106] rec[-18] + DETECTOR(7, 14, 0, 1) rec[-161] rec[-65] + DETECTOR(7, 15, 0, 4) rec[-121] rec[-105] rec[-17] + DETECTOR(8, 0, 0, 2) rec[-160] rec[-64] + DETECTOR(8, 1, 0, 5) rec[-120] rec[-104] rec[-16] + DETECTOR(8, 4, 0, 2) rec[-159] rec[-63] + DETECTOR(8, 5, 0, 5) rec[-119] rec[-103] rec[-15] + DETECTOR(8, 8, 0, 2) rec[-158] rec[-62] + DETECTOR(8, 9, 0, 5) rec[-118] rec[-102] rec[-14] + DETECTOR(8, 12, 0, 2) rec[-157] rec[-61] + DETECTOR(8, 13, 0, 5) rec[-117] rec[-101] rec[-13] + DETECTOR(9, 2, 0, 0) rec[-156] rec[-60] + DETECTOR(9, 3, 0, 3) rec[-116] rec[-100] rec[-12] + DETECTOR(9, 6, 0, 0) rec[-155] rec[-59] + DETECTOR(9, 7, 0, 3) rec[-115] rec[-99] rec[-11] + DETECTOR(9, 10, 0, 0) rec[-154] rec[-58] + DETECTOR(9, 11, 0, 3) rec[-114] rec[-98] rec[-10] + DETECTOR(9, 14, 0, 0) rec[-153] rec[-57] + DETECTOR(9, 15, 0, 3) rec[-113] rec[-97] rec[-9] + DETECTOR(10, 0, 0, 1) rec[-152] rec[-56] + DETECTOR(10, 1, 0, 4) rec[-144] rec[-112] rec[-8] + DETECTOR(10, 4, 0, 1) rec[-151] rec[-55] + DETECTOR(10, 5, 0, 4) rec[-143] rec[-111] rec[-7] + DETECTOR(10, 8, 0, 1) rec[-150] rec[-54] + DETECTOR(10, 9, 0, 4) rec[-142] rec[-110] rec[-6] + DETECTOR(10, 12, 0, 1) rec[-149] rec[-53] + DETECTOR(10, 13, 0, 4) rec[-141] rec[-109] rec[-5] + DETECTOR(11, 2, 0, 2) rec[-148] rec[-52] + DETECTOR(11, 3, 0, 5) rec[-140] rec[-108] rec[-4] + DETECTOR(11, 6, 0, 2) rec[-147] rec[-51] + DETECTOR(11, 7, 0, 5) rec[-139] rec[-107] rec[-3] + DETECTOR(11, 10, 0, 2) rec[-146] rec[-50] + DETECTOR(11, 11, 0, 5) rec[-138] rec[-106] rec[-2] + DETECTOR(11, 14, 0, 2) rec[-145] rec[-49] + DETECTOR(11, 15, 0, 5) rec[-137] rec[-105] rec[-1] + OBSERVABLE_INCLUDE(3) rec[-44] rec[-43] rec[-42] rec[-41] rec[-40] rec[-39] rec[-38] rec[-37] rec[-36] rec[-35] rec[-34] rec[-33] + SHIFT_COORDS(0, 0, 1) + TICK +} +MPP X4*X17*X18*X19*X178*X179 Z4*Z17*Z18*Z19*Z178*Z179 X5*X8*X22*X23*X182*X183 Z5*Z8*Z22*Z23*Z182*Z183 X9*X12*X26*X27*X186*X187 Z9*Z12*Z26*Z27*Z186*Z187 X13*X16*X30*X31*X190*X191 Z13*Z16*Z30*Z31*Z190*Z191 X4*X5*X19*X22*X36*X37 Z4*Z5*Z19*Z22*Z36*Z37 X8*X9*X23*X26*X40*X41 Z8*Z9*Z23*Z26*Z40*Z41 X12*X13*X27*X30*X44*X45 Z12*Z13*Z27*Z30*Z44*Z45 X16*X17*X18*X31*X48*X49 Z16*Z17*Z18*Z31*Z48*Z49 X18*X19*X36*X49*X50*X51 Z18*Z19*Z36*Z49*Z50*Z51 X22*X23*X37*X40*X54*X55 Z22*Z23*Z37*Z40*Z54*Z55 X26*X27*X41*X44*X58*X59 Z26*Z27*Z41*Z44*Z58*Z59 X30*X31*X45*X48*X62*X63 Z30*Z31*Z45*Z48*Z62*Z63 X36*X37*X51*X54*X68*X69 Z36*Z37*Z51*Z54*Z68*Z69 X40*X41*X55*X58*X72*X73 Z40*Z41*Z55*Z58*Z72*Z73 X44*X45*X59*X62*X76*X77 Z44*Z45*Z59*Z62*Z76*Z77 X48*X49*X50*X63*X80*X81 Z48*Z49*Z50*Z63*Z80*Z81 X50*X51*X68*X81*X82*X83 Z50*Z51*Z68*Z81*Z82*Z83 X54*X55*X69*X72*X86*X87 Z54*Z55*Z69*Z72*Z86*Z87 X58*X59*X73*X76*X90*X91 Z58*Z59*Z73*Z76*Z90*Z91 X62*X63*X77*X80*X94*X95 Z62*Z63*Z77*Z80*Z94*Z95 X68*X69*X83*X86*X100*X101 Z68*Z69*Z83*Z86*Z100*Z101 X72*X73*X87*X90*X104*X105 Z72*Z73*Z87*Z90*Z104*Z105 X76*X77*X91*X94*X108*X109 Z76*Z77*Z91*Z94*Z108*Z109 X80*X81*X82*X95*X112*X113 Z80*Z81*Z82*Z95*Z112*Z113 X82*X83*X100*X113*X114*X115 Z82*Z83*Z100*Z113*Z114*Z115 X86*X87*X101*X104*X118*X119 Z86*Z87*Z101*Z104*Z118*Z119 X90*X91*X105*X108*X122*X123 Z90*Z91*Z105*Z108*Z122*Z123 X94*X95*X109*X112*X126*X127 Z94*Z95*Z109*Z112*Z126*Z127 X100*X101*X115*X118*X132*X133 Z100*Z101*Z115*Z118*Z132*Z133 X104*X105*X119*X122*X136*X137 Z104*Z105*Z119*Z122*Z136*Z137 X108*X109*X123*X126*X140*X141 Z108*Z109*Z123*Z126*Z140*Z141 X112*X113*X114*X127*X144*X145 Z112*Z113*Z114*Z127*Z144*Z145 X114*X115*X132*X145*X146*X147 Z114*Z115*Z132*Z145*Z146*Z147 X118*X119*X133*X136*X150*X151 Z118*Z119*Z133*Z136*Z150*Z151 X122*X123*X137*X140*X154*X155 Z122*Z123*Z137*Z140*Z154*Z155 X126*X127*X141*X144*X158*X159 Z126*Z127*Z141*Z144*Z158*Z159 X132*X133*X147*X150*X164*X165 Z132*Z133*Z147*Z150*Z164*Z165 X136*X137*X151*X154*X168*X169 Z136*Z137*Z151*Z154*Z168*Z169 X140*X141*X155*X158*X172*X173 Z140*Z141*Z155*Z158*Z172*Z173 X144*X145*X146*X159*X176*X177 Z144*Z145*Z146*Z159*Z176*Z177 X146*X147*X164*X177*X178*X179 Z146*Z147*Z164*Z177*Z178*Z179 X150*X151*X165*X168*X182*X183 Z150*Z151*Z165*Z168*Z182*Z183 X154*X155*X169*X172*X186*X187 Z154*Z155*Z169*Z172*Z186*Z187 X158*X159*X173*X176*X190*X191 Z158*Z159*Z173*Z176*Z190*Z191 X4*X5*X164*X165*X179*X182 Z4*Z5*Z164*Z165*Z179*Z182 X8*X9*X168*X169*X183*X186 Z8*Z9*Z168*Z169*Z183*Z186 X12*X13*X172*X173*X187*X190 Z12*Z13*Z172*Z173*Z187*Z190 X16*X17*X176*X177*X178*X191 Z16*Z17*Z176*Z177*Z178*Z191 X1*X4*X5*X8*X9*X12*X13*X16*X17 X0*X22*X37*X69*X86*X118*X133*X165*X182 Z1*Z4*Z19*Z51*Z68*Z100*Z115*Z147*Z164 Z0*Z36*Z37*Z40*Z41*Z44*Z45*Z48*Z49 +DETECTOR(0, 0, 0, 0) rec[-196] rec[-100] +DETECTOR(0, 1, 0, 3) rec[-140] rec[-108] rec[-99] +DETECTOR(0, 4, 0, 0) rec[-195] rec[-98] +DETECTOR(0, 5, 0, 3) rec[-139] rec[-107] rec[-97] +DETECTOR(0, 8, 0, 0) rec[-194] rec[-96] +DETECTOR(0, 9, 0, 3) rec[-138] rec[-106] rec[-95] +DETECTOR(0, 12, 0, 0) rec[-193] rec[-94] +DETECTOR(0, 13, 0, 3) rec[-137] rec[-105] rec[-93] +DETECTOR(1, 2, 0, 1) rec[-192] rec[-92] +DETECTOR(1, 3, 0, 4) rec[-136] rec[-104] rec[-91] +DETECTOR(1, 6, 0, 1) rec[-191] rec[-90] +DETECTOR(1, 7, 0, 4) rec[-135] rec[-103] rec[-89] +DETECTOR(1, 10, 0, 1) rec[-190] rec[-88] +DETECTOR(1, 11, 0, 4) rec[-134] rec[-102] rec[-87] +DETECTOR(1, 14, 0, 1) rec[-189] rec[-86] +DETECTOR(1, 15, 0, 4) rec[-133] rec[-101] rec[-85] +DETECTOR(2, 0, 0, 2) rec[-188] rec[-84] +DETECTOR(2, 1, 0, 5) rec[-148] rec[-132] rec[-83] +DETECTOR(2, 4, 0, 2) rec[-187] rec[-82] +DETECTOR(2, 5, 0, 5) rec[-147] rec[-131] rec[-81] +DETECTOR(2, 8, 0, 2) rec[-186] rec[-80] +DETECTOR(2, 9, 0, 5) rec[-146] rec[-130] rec[-79] +DETECTOR(2, 12, 0, 2) rec[-185] rec[-78] +DETECTOR(2, 13, 0, 5) rec[-145] rec[-129] rec[-77] +DETECTOR(3, 2, 0, 0) rec[-184] rec[-76] +DETECTOR(3, 3, 0, 3) rec[-144] rec[-128] rec[-75] +DETECTOR(3, 6, 0, 0) rec[-183] rec[-74] +DETECTOR(3, 7, 0, 3) rec[-143] rec[-127] rec[-73] +DETECTOR(3, 10, 0, 0) rec[-182] rec[-72] +DETECTOR(3, 11, 0, 3) rec[-142] rec[-126] rec[-71] +DETECTOR(3, 14, 0, 0) rec[-181] rec[-70] +DETECTOR(3, 15, 0, 3) rec[-141] rec[-125] rec[-69] +DETECTOR(4, 0, 0, 1) rec[-180] rec[-68] +DETECTOR(4, 1, 0, 4) rec[-140] rec[-124] rec[-67] +DETECTOR(4, 4, 0, 1) rec[-179] rec[-66] +DETECTOR(4, 5, 0, 4) rec[-139] rec[-123] rec[-65] +DETECTOR(4, 8, 0, 1) rec[-178] rec[-64] +DETECTOR(4, 9, 0, 4) rec[-138] rec[-122] rec[-63] +DETECTOR(4, 12, 0, 1) rec[-177] rec[-62] +DETECTOR(4, 13, 0, 4) rec[-137] rec[-121] rec[-61] +DETECTOR(5, 2, 0, 2) rec[-176] rec[-60] +DETECTOR(5, 3, 0, 5) rec[-136] rec[-120] rec[-59] +DETECTOR(5, 6, 0, 2) rec[-175] rec[-58] +DETECTOR(5, 7, 0, 5) rec[-135] rec[-119] rec[-57] +DETECTOR(5, 10, 0, 2) rec[-174] rec[-56] +DETECTOR(5, 11, 0, 5) rec[-134] rec[-118] rec[-55] +DETECTOR(5, 14, 0, 2) rec[-173] rec[-54] +DETECTOR(5, 15, 0, 5) rec[-133] rec[-117] rec[-53] +DETECTOR(6, 0, 0, 0) rec[-172] rec[-52] +DETECTOR(6, 1, 0, 3) rec[-132] rec[-116] rec[-51] +DETECTOR(6, 4, 0, 0) rec[-171] rec[-50] +DETECTOR(6, 5, 0, 3) rec[-131] rec[-115] rec[-49] +DETECTOR(6, 8, 0, 0) rec[-170] rec[-48] +DETECTOR(6, 9, 0, 3) rec[-130] rec[-114] rec[-47] +DETECTOR(6, 12, 0, 0) rec[-169] rec[-46] +DETECTOR(6, 13, 0, 3) rec[-129] rec[-113] rec[-45] +DETECTOR(7, 2, 0, 1) rec[-168] rec[-44] +DETECTOR(7, 3, 0, 4) rec[-128] rec[-112] rec[-43] +DETECTOR(7, 6, 0, 1) rec[-167] rec[-42] +DETECTOR(7, 7, 0, 4) rec[-127] rec[-111] rec[-41] +DETECTOR(7, 10, 0, 1) rec[-166] rec[-40] +DETECTOR(7, 11, 0, 4) rec[-126] rec[-110] rec[-39] +DETECTOR(7, 14, 0, 1) rec[-165] rec[-38] +DETECTOR(7, 15, 0, 4) rec[-125] rec[-109] rec[-37] +DETECTOR(8, 0, 0, 2) rec[-164] rec[-36] +DETECTOR(8, 1, 0, 5) rec[-124] rec[-108] rec[-35] +DETECTOR(8, 4, 0, 2) rec[-163] rec[-34] +DETECTOR(8, 5, 0, 5) rec[-123] rec[-107] rec[-33] +DETECTOR(8, 8, 0, 2) rec[-162] rec[-32] +DETECTOR(8, 9, 0, 5) rec[-122] rec[-106] rec[-31] +DETECTOR(8, 12, 0, 2) rec[-161] rec[-30] +DETECTOR(8, 13, 0, 5) rec[-121] rec[-105] rec[-29] +DETECTOR(9, 2, 0, 0) rec[-160] rec[-28] +DETECTOR(9, 3, 0, 3) rec[-120] rec[-104] rec[-27] +DETECTOR(9, 6, 0, 0) rec[-159] rec[-26] +DETECTOR(9, 7, 0, 3) rec[-119] rec[-103] rec[-25] +DETECTOR(9, 10, 0, 0) rec[-158] rec[-24] +DETECTOR(9, 11, 0, 3) rec[-118] rec[-102] rec[-23] +DETECTOR(9, 14, 0, 0) rec[-157] rec[-22] +DETECTOR(9, 15, 0, 3) rec[-117] rec[-101] rec[-21] +DETECTOR(10, 0, 0, 1) rec[-156] rec[-20] +DETECTOR(10, 1, 0, 4) rec[-148] rec[-116] rec[-19] +DETECTOR(10, 4, 0, 1) rec[-155] rec[-18] +DETECTOR(10, 5, 0, 4) rec[-147] rec[-115] rec[-17] +DETECTOR(10, 8, 0, 1) rec[-154] rec[-16] +DETECTOR(10, 9, 0, 4) rec[-146] rec[-114] rec[-15] +DETECTOR(10, 12, 0, 1) rec[-153] rec[-14] +DETECTOR(10, 13, 0, 4) rec[-145] rec[-113] rec[-13] +DETECTOR(11, 2, 0, 2) rec[-152] rec[-12] +DETECTOR(11, 3, 0, 5) rec[-144] rec[-112] rec[-11] +DETECTOR(11, 6, 0, 2) rec[-151] rec[-10] +DETECTOR(11, 7, 0, 5) rec[-143] rec[-111] rec[-9] +DETECTOR(11, 10, 0, 2) rec[-150] rec[-8] +DETECTOR(11, 11, 0, 5) rec[-142] rec[-110] rec[-7] +DETECTOR(11, 14, 0, 2) rec[-149] rec[-6] +DETECTOR(11, 15, 0, 5) rec[-141] rec[-109] rec[-5] +OBSERVABLE_INCLUDE(0) rec[-4] +OBSERVABLE_INCLUDE(1) rec[-3] +OBSERVABLE_INCLUDE(2) rec[-2] +OBSERVABLE_INCLUDE(3) rec[-1] +SHIFT_COORDS(0, 0, 1) +TICK diff --git a/tools/doctest_proper.py b/tools/doctest_proper.py new file mode 100755 index 0000000..5931196 --- /dev/null +++ b/tools/doctest_proper.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 + +"""Runs doctests on a module, including any objects imported into the module.""" +import argparse +import doctest +import inspect +import sys +from typing import Dict + + +SKIPPED_FIELDS = { + '__base__', + '__name__', + '__path__', + '__spec__', + '__version__', + '__package__', + '__subclasshook__', + '__abstractmethods__', + '__bases__', + '__basicsize__', + '__class__', + '__builtins__', + '__cached__', + '__doc__', + '__loader__', + '__file__', +} + + +def no_really_i_have_a_doc_why_is_this_needed_argh(v: object, fullname: str) -> object: + def so_much_doc(): + pass + so_much_doc.__doc__ = v.__doc__ + so_much_doc.__qualname__ = fullname + return so_much_doc + + +def gen(*, obj: object, fullname: str, out: Dict[str, object]) -> None: + if obj is None: + return + if inspect.isfunction(obj) or inspect.ismethod(obj) or inspect.isbuiltin(obj) or inspect.isroutine(obj): + if hasattr(obj, '__doc__'): + out[fullname] = obj + return + if not inspect.ismodule(obj) and not inspect.isclass(obj): + if hasattr(obj, '__doc__'): + out[fullname] = no_really_i_have_a_doc_why_is_this_needed_argh(obj, fullname) + return + if hasattr(obj, '__doc__'): + out[fullname] = obj + + for sub_name in dir(obj): + if sub_name in SKIPPED_FIELDS: + continue + if sub_name.startswith('__pybind11_module'): + continue + sub_obj = getattr(obj, sub_name, None) + if inspect.ismodule(sub_obj): + continue + sub_full_name = fullname + "." + sub_name + gen(obj=sub_obj, fullname=sub_full_name, out=out) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--module", + type=str, + required=True, + nargs='+', + help="The module to test. " + "This module will be imported, " + "its imported values will be recursively explored, " + "and doctests will be run on them.") + parser.add_argument( + '--import', + default=(), + nargs='*', + type=str, + help="Modules to import for each doctest.") + args = parser.parse_args() + + globs = { + k: __import__(k) for k in getattr(args, 'import') + } + any_failed = False + for module_name in args.module: + module = __import__(module_name) + out = {} + gen(obj=module, fullname=module_name, out=out) + module.__test__ = {k: v for k, v in out.items()} + if doctest.testmod(module, globs=globs).failed: + any_failed = True + if any_failed: + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/tools/fuse_xz_data b/tools/fuse_xz_data new file mode 100755 index 0000000..2d1fe42 --- /dev/null +++ b/tools/fuse_xz_data @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 + +import argparse +import sys +from typing import List + +import sinter + + +def get_basis(stat: sinter.TaskStats) -> str | None: + metadata = dict(sorted(stat.json_metadata.items())) + if 'b' in metadata: + return metadata['b'] + if 'c' in metadata and metadata['c'][-2:] in ['_X', '_Z']: + return metadata['c'][:-1] + return None + + +def sort_by_all_except_basis(stat: sinter.TaskStats) -> str: + metadata = dict(sorted(stat.json_metadata.items())) + if 'b' in metadata: + del metadata['b'] + if 'c' in metadata and metadata['c'][-2:] in ['_X', '_Z']: + metadata['c'] = metadata['c'][:-2] + return repr(metadata) + ":" + stat.decoder + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--stats", + type=str, + required=True, + ) + args = parser.parse_args() + + stats: List[sinter.TaskStats] = sinter.stats_from_csv_files(args.stats) + + print(sinter.CSV_HEADER) + for _, pair in sinter.group_by(stats, key=sort_by_all_except_basis).items(): + for e in pair: + print(e) + if len(pair) > 2: + raise ValueError(f"More than two bases:\n " + '\n '.join(repr(e) for e in pair)) + if len(pair) == 1: + if get_basis(pair[0]) is None: + continue + print("WARNING: duplicating unpaired value with metadata ", pair[0].json_metadata, "and decoder", pair[0].decoder, file=sys.stderr) + a, b = pair[0], pair[0] + else: + a, b = pair + if a.shots > b.shots: + a, b = b, a + assert a.discards == b.discards == 0 + new_errors = round((1 - (1 - a.errors / a.shots) * (1 - b.errors / b.shots)) * a.shots) + + new_metadata = dict(a.json_metadata) + if 'b' in a.json_metadata: + new_metadata['b'] = 'XZ' + elif 'c' in a.json_metadata and a.json_metadata['c'][-2:] in ['_X', '_Z']: + new_metadata['c'] = a.json_metadata['c'][:-2] + '_XZ' + else: + raise NotImplementedError(f"Missed basis:\n " + '\n '.join(repr(e) for e in pair)) + combo = sinter.TaskStats( + strong_id=a.strong_id + '*' + b.strong_id, + decoder=a.decoder, + json_metadata=new_metadata, + shots=a.shots, + errors=new_errors, + discards=0, + seconds=a.seconds + b.seconds, + ) + print(combo) + + +if __name__ == '__main__': + main() diff --git a/tools/gen_chromobius_api_reference.py b/tools/gen_chromobius_api_reference.py new file mode 100755 index 0000000..7335e69 --- /dev/null +++ b/tools/gen_chromobius_api_reference.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +""" +Iterates over modules and classes, listing their attributes and methods in markdown. +""" + +import chromobius + +import sys + +from util_gen_stub_file import generate_documentation + + +def main(): + version = chromobius.__version__ + if "dev" in version or version == "VERSION_INFO" or "-dev" in sys.argv: + version = "(Development Version)" + is_dev = True + else: + version = "v" + version + is_dev = False + objects = [ + obj + for obj in generate_documentation(obj=chromobius, full_name="chromobius", level=0) + if all('[DEPRECATED]' not in line for line in obj.lines) + ] + global_methods = [obj for obj in objects if obj.full_name.islower()] + not_global_methods = [obj for obj in objects if not obj.full_name.islower()] + + print(f"# Chromobius {version} API Reference") + print() + print("## Index") + print("- ``") + for obj in global_methods: + level = obj.level + 1 + print((level - 1) * " " + f"- [`{obj.full_name}`](#{obj.full_name})") + for obj in not_global_methods: + level = obj.level + print((level - 1) * " " + f"- [`{obj.full_name}`](#{obj.full_name})") + + print(f''' +```python +# Types used by the method definitions. +from typing import overload, TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Tuple, Union +import io +import pathlib +import numpy as np +``` +'''.strip()) + + for obj in global_methods + not_global_methods: + print() + print(f'') + print("```python") + print(f'# {obj.full_name}') + print() + if len(obj.full_name.split('.')) > 2: + print(f'# (in class {".".join(obj.full_name.split(".")[:-1])})') + else: + print(f'# (at top-level in the chromobius module)') + print('\n'.join(obj.lines)) + print("```") + + +if __name__ == '__main__': + main() diff --git a/tools/gen_chromobius_stub_file.py b/tools/gen_chromobius_stub_file.py new file mode 100755 index 0000000..6458848 --- /dev/null +++ b/tools/gen_chromobius_stub_file.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +""" +Produces a .pyi file for chromobius, describing the contained classes and functions. +""" + +import chromobius +import sys + +from util_gen_stub_file import generate_documentation + + +def main(): + version = chromobius.__version__ + if "dev" in version or version == "VERSION_INFO" or "-dev" in sys.argv: + version = "(Development Version)" + else: + version = "v" + version + print(f''' +"""Chromobius {version}: an implementation of the mobius color code decoder.""" +# (This a stubs file describing the classes and methods in stim.) +from __future__ import annotations +from typing import overload, TYPE_CHECKING, Any, Iterable +if TYPE_CHECKING: + import io + import pathlib + import numpy as np + import stim + import sinter + import chromobius +'''.strip()) + + for obj in generate_documentation(obj=chromobius, full_name="chromobius", level=-1): + text = '\n'.join((" " * obj.level + line).rstrip() + for paragraph in obj.lines + for line in paragraph.splitlines()) + assert "stim::" not in text, "CONTAINS C++ STYLE TYPE SIGNATURE!!:\n" + text + print(text) + + +if __name__ == '__main__': + main() diff --git a/tools/gen_circuits b/tools/gen_circuits new file mode 100755 index 0000000..7e9afe7 --- /dev/null +++ b/tools/gen_circuits @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 + +import argparse +import itertools +import pathlib + +import sys +src_path = pathlib.Path(__file__).parent.parent / 'src' +assert src_path.exists() +sys.path.append(str(src_path)) + +import gen +from clorco._make_circuit import make_circuit + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--out_dir", + type=str, + required=True, + ) + parser.add_argument("--diameter", nargs='+', required=True, type=int) + parser.add_argument("--rounds", nargs='+', required=True, type=str) + parser.add_argument("--noise_strength", nargs='+', default=(None,), type=float) + parser.add_argument("--noise_model", nargs='+', required=True, choices=['si1000', 'uniform', 'none', 'bitflip']) + parser.add_argument("--style", nargs='+', required=True, type=str) + parser.add_argument("--extra", nargs='+', default=(None,)) + parser.add_argument("--extra2", nargs='+', default=(None,)) + parser.add_argument("--extra3", nargs='+', default=(None,)) + parser.add_argument("--convert_to_cz", nargs='+', default=('auto',)) + parser.add_argument("--debug_out_dir", default=None, type=str) + parser.add_argument( + "--stdout", + action="store_true", + ) + args = parser.parse_args() + + out_dir = pathlib.Path(args.out_dir) + out_dir.mkdir(exist_ok=True, parents=True) + debug_out_dir = None + if args.debug_out_dir is not None: + debug_out_dir = pathlib.Path(args.debug_out_dir) + debug_out_dir.mkdir(exist_ok=True, parents=True) + + for (diameter, + noise_strength, + rounds_func, + noise_model_name, + style, + extra, + extra2, + extra3, + convert_to_cz_arg) in itertools.product( + args.diameter, + args.noise_strength, + args.rounds, + args.noise_model, + args.style, + args.extra, + args.extra2, + args.extra3, + args.convert_to_cz): + if noise_model_name != "None" and noise_strength is None: + raise ValueError("Must specify --noise_strength") + if noise_model_name == 'si1000': + noise_model = gen.NoiseModel.si1000(noise_strength) + elif noise_model_name == "uniform": + noise_model = gen.NoiseModel.uniform_depolarizing(noise_strength) + elif noise_model_name == "none": + noise_model = None + elif noise_model_name == "bitflip": + noise_model_name = 'bitflip' + noise_model = gen.NoiseModel( + idle_noise=gen.NoiseRule(after={"X_ERROR": noise_strength}), + any_clifford_1q_rule=gen.NoiseRule(after={"X_ERROR": noise_strength}), + any_clifford_2q_rule=gen.NoiseRule(after={"X_ERROR": noise_strength}), + any_measurement_rule=gen.NoiseRule(after={"X_ERROR": noise_strength}, flip_result=noise_strength), + gate_rules={ + "R": gen.NoiseRule(after={"X_ERROR": noise_strength}), + }, + ) + else: + raise NotImplementedError(f'{noise_model_name=}') + + rounds = eval(rounds_func, {'d': diameter}) + if convert_to_cz_arg == 'auto': + convert_to_cz = noise_model_name == 'si1000' + else: + convert_to_cz = bool(int(convert_to_cz_arg)) + editable_extras = {} + circuit = make_circuit( + style=style, + diameter=diameter, + noise_model=noise_model, + noise_strength=noise_strength, + debug_out_dir=debug_out_dir, + rounds=rounds, + convert_to_cz=convert_to_cz, + editable_extras=editable_extras, + ) + q = circuit.num_qubits + extra_tags = '' + for ex in [extra, extra2, extra3]: + if ex is not None: + extra_dict = eval(ex) + assert isinstance(extra_dict, dict) + for k, v in extra_dict.items(): + extra_tags += f',{k}={v}' + for k, v in editable_extras.items(): + extra_tags += f',{k}={v}' + if convert_to_cz: + extra_tags += ',gates=cz' + else: + extra_tags += ',gates=all' + path = out_dir / f'r={rounds},d={diameter},p={noise_strength},noise={noise_model_name},c={style},q={q}{extra_tags}.stim' + if args.stdout: + print(circuit) + else: + with open(path, 'w') as f: + print(circuit, file=f) + print(f'wrote file://{path.absolute()}') + + +if __name__ == '__main__': + main() diff --git a/tools/gen_timing_stats b/tools/gen_timing_stats new file mode 100755 index 0000000..66a45aa --- /dev/null +++ b/tools/gen_timing_stats @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +import collections +import pathlib + +import sys +import time +from typing import Any + +import numpy as np + +import chromobius +import sinter +import stim + +src_path = pathlib.Path(__file__).parent.parent / 'src' +assert src_path.exists() +sys.path.append(str(src_path)) + +import gen +from clorco._make_circuit import make_circuit +from sinter._decoding_all_built_in_decoders import ( + BUILT_IN_DECODERS, +) + + +def time_batch( + *, + shots: int, + sampler: stim.CompiledDetectorSampler, + compiled_decoder: sinter.CompiledDecoder, +) -> sinter.AnonTaskStats: + dets, obs = sampler.sample( + shots=shots, separate_observables=True, bit_packed=True + ) + + num_detection_events = 0 + for k in range(8): + num_detection_events += np.count_nonzero(dets & (1 << k)) + + t0 = time.monotonic() + predictions = compiled_decoder.decode_shots_bit_packed(bit_packed_detection_event_data=dets) + t1 = time.monotonic() + + errors = np.count_nonzero(np.any(predictions != obs, axis=1)) + return sinter.AnonTaskStats( + shots=shots, + errors=errors, + seconds=t1 - t0, + custom_counts=collections.Counter({'detection_events': num_detection_events}), + ) + + +def time_circuit( + *, + circuit: stim.Circuit, + json_metadata: dict[str, Any], + decoder_name: str, + target_seconds: float = 1, + max_batch_size: int = 2**12, + decoder: sinter.Decoder, +) -> sinter.TaskStats: + dem = circuit.detector_error_model() + compiled_decoder: sinter.CompiledDecoder = decoder.compile_decoder_for_dem(dem=dem) + sampler = circuit.compile_detector_sampler() + + batch_size = 1 + while True: + base_stat = time_batch( + shots=batch_size, + sampler=sampler, + compiled_decoder=compiled_decoder, + ) + if base_stat.seconds > 0.1: + break + batch_size *= 2 + if batch_size >= max_batch_size: + break + + total = sinter.AnonTaskStats() + while total.seconds < target_seconds: + time_left = target_seconds - total.seconds + expected_size = round(1.1 * time_left * base_stat.shots / base_stat.seconds) + total += time_batch( + shots=min(max_batch_size, max(1, expected_size)), + sampler=sampler, + compiled_decoder=compiled_decoder, + ) + + strong_id = sinter.Task( + circuit=circuit, + decoder=decoder_name, + detector_error_model=dem, + json_metadata=json_metadata, + ).strong_id() + + return sinter.TaskStats( + shots=total.shots, + errors=total.errors, + strong_id=strong_id, + decoder=decoder_name, + seconds=total.seconds, + json_metadata=json_metadata, + custom_counts=total.custom_counts, + ) + + +def main(): + chromobius_decoder: sinter.Decoder = chromobius.sinter_decoders()['chromobius'] + pymatching_decoder = BUILT_IN_DECODERS['pymatching'] + target_seconds = 1 + + print(sinter.CSV_HEADER, flush=True) + for d in [3, 5, 7, 9, 11, 13]: + for p in [1e-4, 2e-4, 3e-4, 5e-4, 7e-4, 1e-3, 2e-3, 3e-3, 5e-3, 7e-3, 1e-2]: + for style in ['midout_color_code_X', 'superdense_color_code_X', 'surface_code_X', 'transit_color_code', 'phenom_color_code']: + noise_strength = p + rounds = 1 if 'transit' in style else d * 4 + noise_model = gen.NoiseModel.uniform_depolarizing(noise_strength) + circuit = make_circuit( + style=style, + diameter=d, + noise_model=noise_model, + noise_strength=noise_strength, + rounds=rounds, + convert_to_cz=False, + editable_extras={}, + ) + json_metadata = { + 'd': d, + 'r': rounds, + 'p': noise_strength, + 'c': style, + 'noise': 'uniform', + 'q': circuit.num_qubits, + } + stats = time_circuit( + circuit=circuit, + json_metadata=json_metadata, + decoder=pymatching_decoder if 'surface' in style else chromobius_decoder, + decoder_name='pymatching' if 'surface' in style else 'chromobius', + target_seconds=target_seconds, + ) + print(stats, flush=True) + + +if __name__ == '__main__': + main() diff --git a/tools/overwrite_dev_versions_with_date.py b/tools/overwrite_dev_versions_with_date.py new file mode 100755 index 0000000..4730b1f --- /dev/null +++ b/tools/overwrite_dev_versions_with_date.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 + +######################################################### +# Sets version numbers to a date-based dev version. +# +# Does nothing if not on a dev version. +######################################################### +# Example usage (from repo root): +# +# ./dev/overwrite_dev_versions_with_date.sh +######################################################### + +import os +import pathlib +import re +import subprocess + + +def main(): + os.chdir(pathlib.Path(__file__).parent) + os.chdir(subprocess.check_output(["git", "rev-parse", "--show-toplevel"]).decode().strip()) + + # Generate dev version starting from major.minor version. + # (Requires the existing version to have a 'dev' suffix.) + # (Uses the timestamp of the HEAD commit, to ensure consistency when run multiple times.) + with open('setup.py') as f: + maj_min_version_line, = [line for line in f.read().splitlines() if re.match("^__version__ = '[^']+'", line)] + maj_version, min_version, patch = maj_min_version_line.split()[-1].strip("'").split('.') + if 'dev' not in patch: + return # Do nothing for non-dev versions. + timestamp = subprocess.check_output(['git', 'show', '-s', '--format=%ct', 'HEAD']).decode().strip() + new_version = f"{maj_version}.{min_version}.dev{timestamp}" + + # Overwrite existing versions. + package_setup_files = [ + "setup.py", + ] + for path in package_setup_files: + with open(path) as f: + content = f.read() + assert maj_min_version_line in content + content = content.replace(maj_min_version_line, f"__version__ = '{new_version}'") + with open(path, 'w') as f: + print(content, file=f, end='') + + +if __name__ == '__main__': + main() diff --git a/tools/plot_comparison b/tools/plot_comparison new file mode 100755 index 0000000..f6c0bd5 --- /dev/null +++ b/tools/plot_comparison @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 + +import pathlib + +import matplotlib.pyplot as plt +from sinter._main_plot import _sqrt_ticks + +import sinter + + +def get_stats() -> list[sinter.TaskStats]: + assets = pathlib.Path(__file__).parent.parent / 'assets' + stats = sinter.read_stats_from_csv_files(assets / 'stats.csv') + stats = [ + stat + for stat in stats + if stat.json_metadata['c'] in [ + 'midout_color_code_X', + 'superdense_color_code_X', + ] + ] + + cur_id = 0 + + def new_id() -> str: + nonlocal cur_id + cur_id += 1 + return 'arbitrary' + str(cur_id) + + nn_data = [ + {"d": 3, "p": 1e-3, "L": 3e-4}, + {"d": 5, "p": 1e-3, "L": 1.3e-4}, + {"d": 7, "p": 1e-3, "L": 1e-4}, + + # Interpolated + {"d": 3, "p": 2e-3, "L": 1.2e-3}, + {"d": 5, "p": 2e-3, "L": 1e-3}, + {"d": 7, "p": 2e-3, "L": 1.4e-3}, + # Interpolated + {"d": 3, "p": 2e-4, "L": 1.1e-5}, + {"d": 5, "p": 2e-4, "L": 1e-6}, + {"d": 7, "p": 2e-4, "L": 1.3e-7}, + # Interpolated + {"d": 3, "p": 3e-4, "L": 2.5e-5}, + {"d": 5, "p": 3e-4, "L": 3e-6}, + {"d": 7, "p": 3e-4, "L": 7e-7}, + # Interpolated + {"d": 3, "p": 5e-4, "L": 7e-5}, + {"d": 5, "p": 5e-4, "L": 1.5e-5}, + {"d": 7, "p": 5e-4, "L": 5e-6}, + + {"d": 3, "p": 2.5e-3, "L": 1.7e-3}, + {"d": 3, "p": 4e-4, "L": 5e-5}, + {"d": 3, "p": 1e-4, "L": 3e-6}, + {"d": 5, "p": 2.5e-3, "L": 1.5e-3}, + {"d": 5, "p": 4e-4, "L": 1e-5}, + {"d": 5, "p": 1e-4, "L": 1.1e-7}, + {"d": 7, "p": 2.5e-3, "L": 2e-3}, + {"d": 7, "p": 4e-4, "L": 3e-6}, + {"d": 7, "p": 1.7e-4, "L": 6e-8}, + ] + for e in nn_data: + stats.append(sinter.TaskStats( + strong_id=new_id(), + decoder='neural_net', + shots=10**9, + errors=round(10**9 * e["L"]), + json_metadata={ + "d": e["d"], + "p": e["p"], + "noise": "~uniform", + "src": "(2018) Baireuther et al", + "c": "bell_flagged", + "r": 1 / 20, # Paper says there are 20 steps per cycle. + "q": e["d"] * e["d"] * 1.5 - 0.5, + } + )) + + ff_data = [ + {"d": 5, "p": 1e-3, "L": 9e-3}, + {"d": 7, "p": 1e-3, "L": 5e-3}, + {"d": 9, "p": 1e-3, "L": 3e-3}, + {"d": 11, "p": 1e-3, "L": 1.4e-3}, + {"d": 13, "p": 1e-3, "L": 8e-4}, + {"d": 15, "p": 1e-3, "L": 3.5e-4}, + + {"d": 5, "p": 2e-3, "L": 4e-2}, + {"d": 7, "p": 2e-3, "L": 4e-2}, + {"d": 9, "p": 2e-3, "L": 4e-2}, + {"d": 11, "p": 2e-3, "L": 4e-2}, + {"d": 13, "p": 2e-3, "L": 4e-2}, + {"d": 15, "p": 2e-3, "L": 4e-2}, + + {"d": 5, "p": 5e-4, "L": 1e-3}, + {"d": 7, "p": 5e-4, "L": 4e-4}, + {"d": 9, "p": 5e-4, "L": 1e-4}, + {"d": 11, "p": 5e-4, "L": 3e-5}, + {"d": 13, "p": 5e-4, "L": 8e-6}, + + {"d": 5, "p": 3e-4, "L": 2.8e-4}, + {"d": 7, "p": 3e-4, "L": 5e-5}, + {"d": 9, "p": 3e-4, "L": 9e-6}, + {"d": 11, "p": 3e-4, "L": 1.2e-6}, + {"d": 13, "p": 3e-4, "L": 1e-7}, + + # Just a fake data point to get the entry in the legend. + {"d": 3, "p": 1e-4, "L": 1e-15}, + {"d": 3, "p": 2e-4, "L": 1e-15}, + ] + + def chamberland_qubit_count(d: int) -> int: + return sum(range(1, d*3, 2)) + + assert chamberland_qubit_count(3) == 16 + assert chamberland_qubit_count(5) == 49 + + for e in ff_data: + stats.append(sinter.TaskStats( + strong_id=new_id(), + decoder='restriction_flag', + shots=10**9, + errors=round(10**9 * e["L"]), + json_metadata={ + "d": e["d"], + "p": e["p"], + "noise": "~uniform", + "src": "(2019) Chamberland et al", + "c": "triple_flagged", + "r": e["d"], # page 13 says T=d+1 but last round is noiseless. Assumes error rates from plot are per-shot. + "q": chamberland_qubit_count(int(e["d"])), + } + )) + + return stats + + +def main(): + assets = pathlib.Path(__file__).parent.parent / 'assets' + ps = [2e-3, 1e-3, 5e-4, 3e-4, 2e-4, 1e-4] + for p in ps: + stats = get_stats() + stats = [stat for stat in stats if stat.json_metadata["p"] == p] + + fig: plt.Figure + ax: plt.Axes + fig, ax = plt.subplots(1, 1) + + sinter.plot_error_rate( + ax=ax, + stats=stats, + x_func=lambda stat: stat.json_metadata["q"], + group_func=lambda stat: f'''{stat.json_metadata.get("src", "(2023) this paper")} c={stat.json_metadata["c"]} p={stat.json_metadata["p"]} noise={stat.json_metadata["noise"]} decoder={stat.decoder}''', + highlight_max_likelihood_factor=None, + failure_units_per_shot_func=lambda stat: stat.json_metadata['r'], + ) + + ax.legend() + ax.set_ylim(1e-12, 1) + ax.set_xlim(1e-4, 1e-2) + ax.semilogy() + from matplotlib.scale import FuncScale + min_v, max_v, major_ticks, minor_ticks = _sqrt_ticks(0, 500) + ax.set_xlim(min_v, max_v) + ax.set_xscale(FuncScale(ax, (lambda e: e**0.5, lambda e: e**2))) + ax.set_xticks(major_ticks) + ax.set_xticks(minor_ticks, minor=True) + ax.grid(which='major', color='#000000') + ax.grid(which='minor', color='#DDDDDD') + ax.set_yticks([10**-k for k in range(13)]) + ax.set_yticks([b*10**-k for k in range(1, 13) for b in range(1, 10)], minor=True) + ax.set_xlabel("Total Qubit Count (sqrt scale)") + ax.set_ylabel("Logical Error Rate (per round)") + ax.set_title(f"Comparing to previous work with uniform circuit noise at p={p}") + + fig.set_size_inches(10, 10) + fig.set_dpi(100) + fig.tight_layout() + f = assets / 'generated' / f'prev_work_comparison_{p}.png' + fig.savefig(f) + print(f'wrote file://{f.absolute()}') + + +if __name__ == '__main__': + main() diff --git a/tools/plot_stats_timing b/tools/plot_stats_timing new file mode 100755 index 0000000..20524bf --- /dev/null +++ b/tools/plot_stats_timing @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 + +import pathlib +from typing import Any +from typing import Literal + +import matplotlib.pyplot as plt +from sinter._plotting import plot_custom + +import sinter + + +def plot_per_detection_event( + *, + stats: list[sinter.TaskStats], + per: Literal['r', 'rq', 'd'], + full_data: bool, +) -> tuple[plt.Figure, plt.Axes]: + fig: plt.Figure + ax: plt.Axes + fig, ax = plt.subplots(1, 1) + + c2c = { + 'superdense_color_code_X': 'C0', + 'midout_color_code_X': 'C1', + 'phenom_color_code': 'C2', + 'surface_code_X': 'C3', + } + if full_data: + c2c['transit_color_code'] = 'C4' + distances = [3, 5, 7, 9, 11, 13] + else: + distances = [5, 9, 13] + stats = [ + stat + for stat in stats + if 'transit' not in stat.json_metadata['c'] + ] + stats = [ + stat + for stat in stats + if stat.json_metadata['d'] in distances + ] + + markers = '>|x*pos^+8PhH doc/chromobius_api_reference.md +python tools/gen_chromobius_stub_file.py -dev > doc/chromobius.pyi diff --git a/tools/regen_file_lists.sh b/tools/regen_file_lists.sh new file mode 100755 index 0000000..28dca22 --- /dev/null +++ b/tools/regen_file_lists.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +######################################################################### +# Regenerate file_lists +######################################################################### + +if [ "$#" -ne 1 ]; then + FOLDER=file_lists +else + FOLDER=$1 +fi + +# Get to this script's git repo root. +cd "$( dirname "${BASH_SOURCE[0]}" )" +cd "$(git rev-parse --show-toplevel)" + +# LC_ALL=C forces sorting to happen by byte value +find src | grep "\\.\\(cc\\|h\\)$" | grep -v "\\.\(test\|perf\|pybind\)\\.\\(cc\\|h\\)$" | grep -v "main\\.cc$" | LC_ALL=C sort > "${FOLDER}/source_files_no_main" +find src | grep "\\.test\\.\\(cc\\|h\\)$" | LC_ALL=C sort > "${FOLDER}/test_files" +find src | grep "\\.perf\\.\\(cc\\|h\\)$" | LC_ALL=C sort > "${FOLDER}/perf_files" +find src | grep "\\.pybind\\.\\(cc\\|h\\)$" | LC_ALL=C sort > "${FOLDER}/pybind_files" + +# Regenerate 'chromobius.h' to include all relevant headers. +{ + echo "#ifndef _CHROMOBIUS_H"; + echo "#define _CHROMOBIUS_H"; + echo "/// WARNING: THE chromobius C++ API MAKES NO COMPATIBILITY GUARANTEES."; + echo "/// It may change arbitrarily and catastrophically from minor version to minor version."; + echo "/// If you need a stable API, use chromobius's Python API."; + find src | grep "\\.h$" | grep -v "\\.\(test\|perf\|pybind\)\\.h$" | grep -v "src/chromobius\\.h" | LC_ALL=C sort | sed 's/src\/\(.*\)/#include "\1"/g'; + echo "#endif"; +} > src/chromobius.h diff --git a/tools/regen_test_data.sh b/tools/regen_test_data.sh new file mode 100755 index 0000000..94f9f39 --- /dev/null +++ b/tools/regen_test_data.sh @@ -0,0 +1,152 @@ +#!/bin/bash +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +# Get to this script's git repo root. +cd "$( dirname "${BASH_SOURCE[0]}" )" +cd "$(git rev-parse --show-toplevel)" + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style midout_color_code_488_X \ + --noise_model uniform \ + --rounds 33 \ + --diameter 9 \ + --noise_strength 0.001 \ + > test_data/midout488_color_code_d9_r33_p1000.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style midout_color_code_X \ + --noise_model uniform \ + --rounds 36 \ + --diameter 9 \ + --noise_strength 0.001 \ + > test_data/midout_color_code_d9_r36_p1000.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style midout_color_code_X \ + --noise_model uniform \ + --diameter 25 \ + --rounds 100 \ + --noise_strength 0.001 \ + > test_data/midout_color_code_d25_r100_p1000.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style midout_color_code_X \ + --noise_model uniform \ + --diameter 5 \ + --rounds 10 \ + --noise_strength 0.001 \ + > test_data/midout_color_code_d5_r10_p1000.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style transit_rep_code \ + --noise_model uniform \ + --diameter 9 \ + --rounds 1 \ + --noise_strength 0.1 \ + > test_data/rep_code_d9_transit_p10.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style transit_rep_code_rg \ + --noise_model uniform \ + --diameter 9 \ + --rounds 1 \ + --noise_strength 0.1 \ + > test_data/rep_code_rg_d9_transit_p10.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style transit_rep_code_rbrrr \ + --noise_model uniform \ + --diameter 9 \ + --rounds 1 \ + --noise_strength 0.1 \ + > test_data/rep_code_rbrrr_d9_transit_p10.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style superdense_color_code_X \ + --noise_model uniform \ + --diameter 5 \ + --rounds 20 \ + --noise_strength 0.001 \ + > test_data/superdense_color_code_d5_r20_p1000.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style phenom_color_code \ + --noise_model uniform \ + --diameter 5 \ + --rounds 5 \ + --noise_strength 0.001 \ + > test_data/phenom_color_code_d5_r5_p1000.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style surface_code_X \ + --noise_model uniform \ + --diameter 5 \ + --rounds 5 \ + --noise_strength 0.001 \ + > test_data/surface_code_d5_r5_p1000.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style transit_color2surface_code \ + --noise_model uniform \ + --diameter 5 \ + --rounds 1 \ + --noise_strength 0.01 \ + > test_data/color2surface_d5_transit_p100.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style phenom_color2surface_code \ + --noise_model uniform \ + --diameter 7 \ + --rounds 7 \ + --noise_strength 0.01 \ + > test_data/color2surface_d7_phenom_r7_p100.stim & + +./tools/gen_circuits \ + --out_dir test_data \ + --stdout \ + --style toric_superdense_color_code_magicEPR \ + --noise_model uniform \ + --diameter 12 \ + --rounds 5 \ + --noise_strength 0.001 \ + > test_data/toric_superdense_color_code_epr_d12_r5_p1000.stim & + +wait diff --git a/tools/sinter_plot_print b/tools/sinter_plot_print new file mode 100755 index 0000000..9b2cf95 --- /dev/null +++ b/tools/sinter_plot_print @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +import pathlib +import subprocess +import sys + +try: + subprocess.check_output([ + 'sinter', + 'plot', + *sys.argv[1:], + ], stderr=sys.stderr) +except: + sys.exit(1) + +if '--out' in sys.argv: + path = sys.argv[sys.argv.index('--out') + 1] + print(f'wrote file://{pathlib.Path(path).absolute()}') diff --git a/tools/step1_generate_circuits.sh b/tools/step1_generate_circuits.sh new file mode 100755 index 0000000..2150417 --- /dev/null +++ b/tools/step1_generate_circuits.sh @@ -0,0 +1,93 @@ +#!/bin/bash +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +set -e +set -o pipefail + +parallel --ungroup ./tools/gen_circuits \ + --style {1} \ + --out_dir out/circuits_matchable \ + --noise_model uniform \ + --rounds "d*4" \ + --diameter {2} \ + --noise_strength 0.001 \ + ::: surface_code_X surface_code_Z \ + ::: 3 5 7 9 11 13 + + +parallel --ungroup ./tools/gen_circuits \ + --style {1} \ + --out_dir out/circuits_unmatchable \ + --noise_model uniform \ + --rounds "d*4" \ + --diameter {2} \ + --noise_strength 0.001 \ + ::: midout_color_code_488_X midout_color_code_488_Z \ + ::: 3 5 7 9 11 13 15 17 19 + + +parallel --ungroup ./tools/gen_circuits \ + --style {1} \ + --out_dir out/circuits_unmatchable \ + --noise_model uniform \ + --rounds "d*4" \ + --diameter {2} \ + --noise_strength {3} \ + ::: midout_color_code_X midout_color_code_Z superdense_color_code_X superdense_color_code_Z \ + ::: 3 5 7 9 11 13 15 17 19 \ + ::: 0.0001 0.0002 0.0003 0.0005 0.0007 0.001 0.002 0.003 0.005 0.006 0.007 0.008 0.01 + + +parallel --ungroup ./tools/gen_circuits \ + --style {1} \ + --out_dir out/circuits_unmatchable \ + --noise_model uniform \ + --rounds "d*4" \ + --diameter {2} \ + --noise_strength 0.01 \ + ::: phenom_toric_color_code \ + ::: 6 12 18 24 +parallel --ungroup ./tools/gen_circuits \ + --style {1} \ + --out_dir out/circuits_matchable \ + --noise_model uniform \ + --rounds "d*4" \ + --diameter {2} \ + --noise_strength 0.01 \ + ::: phenom_ablated_toric_color_code \ + ::: 6 12 18 24 + + +parallel --ungroup ./tools/gen_circuits \ + --style {1} \ + --out_dir out/circuits_unmatchable \ + --noise_model uniform \ + --rounds "d*4" \ + --diameter {2} \ + --noise_strength 0.01 \ + ::: phenom_rep_code phenom_surface_code phenom_color_code phenom_pyramid_code phenom_color_code_488 phenom_color2surface_code \ + ::: 3 5 7 9 11 13 + + +parallel --ungroup ./tools/gen_circuits \ + --style transit_color_code \ + --out_dir out/circuits_unmatchable \ + --noise_model bitflip \ + --rounds 1 \ + --diameter {1} \ + --noise_strength {2} \ + ::: 11 15 19 23 27 31 \ + ::: 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 diff --git a/tools/step2_collect_stats.sh b/tools/step2_collect_stats.sh new file mode 100755 index 0000000..1163964 --- /dev/null +++ b/tools/step2_collect_stats.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +set -e +set -o pipefail +trap "exit 1" INT + +sinter collect \ + --circuits out/circuits_unmatchable/*.stim out/circuits_matchable/*.stim \ + --save_resume_filepath out/stats.csv \ + --decoders chromobius \ + --processes auto \ + --max_shots 100_000_000 \ + --max_errors 1000 \ + --metadata_func auto \ + --custom_decoders "chromobius:sinter_decoders" + + +sinter collect \ + --circuits out/circuits_matchable/*.stim \ + --save_resume_filepath out/stats.csv \ + --decoders chromobius pymatching sparse_blossom_correlated \ + --processes auto \ + --max_shots 100_000_000 \ + --max_errors 1000 \ + --metadata_func auto \ + --custom_decoders "chromobius:sinter_decoders" "gqec:make_custom_sinter_decoders_dict" diff --git a/tools/step3_plot_stats.sh b/tools/step3_plot_stats.sh new file mode 100755 index 0000000..ae74312 --- /dev/null +++ b/tools/step3_plot_stats.sh @@ -0,0 +1,161 @@ +#!/bin/bash +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +set -e +set -o pipefail + +mkdir -p assets + +./tools/fuse_xz_data --stats assets/stats.csv > assets/generated/stats-xz-combo.csv + +./tools/sinter_plot_print \ + --title "Ignoring 1/3 of detectors slightly improves accuracy on the torus" \ + --in assets/stats.csv \ + --x_func "m.d" \ + --xaxis "Patch Diameter (d)" \ + --out "assets/generated/toric.png" \ + --group_func "f'''{'drop_1/3_detectors' if 'ablated' in m.c else 'all_detectors_kept'} decoder={decoder}'''" \ + --subtitle "code=toric_color_code, rounds=4d, noise=phenom, p=0.01" \ + --filter_func "m.r == m.d * 4 and abs(m.p - 0.01) < 1e-5 and 'phenom' in m.c and 'toric' in m.c" \ + --ymin 1e-12 \ + --failure_unit_name "round" \ + --failure_units_per_shot_func m.r \ + --failure_values_func "2" \ + & + +for BASIS in X Z XZ; do + NUM_OBS=1 + if [ "${BASIS}" = "XZ" ]; then + NUM_OBS=2 + fi + ./tools/sinter_plot_print \ + --title "Comparing color code and surface code circuits" \ + --in "assets/generated/stats-xz-combo.csv" \ + --x_func "m.q" \ + --xaxis "[sqrt]Total Qubits (sqrt scale)" \ + --out "assets/generated/compare_${BASIS}.png" \ + --group_func "f'''c={m.c} decoder={decoder}'''" \ + --subtitle "rounds=4d, gates=css, noise=uniform, p=0.001" \ + --line_fits \ + --xmax 1500 \ + --filter_func "m.r == m.d * 4 and abs(m.p - 0.001) < 1e-5 and m.c in ['surface_code_${BASIS}', 'midout_color_code_${BASIS}', 'midout_color_code_488_${BASIS}', 'superdense_color_code_${BASIS}']" \ + --ymin 1e-12 \ + --failure_unit_name "round" \ + --failure_units_per_shot_func m.r \ + --failure_values_func "${NUM_OBS}" \ + & + + ./tools/sinter_plot_print \ + --title "Footprint of middle-out color code circuits" \ + --in "assets/generated/stats-xz-combo.csv" \ + --x_func "m.q" \ + --xaxis "[sqrt]Total Qubits (sqrt scale)" \ + --out "assets/generated/midout_footprint_${BASIS}.png" \ + --group_func "f'''noise strength (p) = {m.p}'''" \ + --xmin 0 \ + --xmax 1500 \ + --subtitle "rounds=4d, gates=css, noise=uniform, decoder=chromobius, circuit=midout_color_code_${BASIS}" \ + --line_fits \ + --filter_func "m.r == m.d * 4 and m.c in ['midout_color_code_${BASIS}']" \ + --ymin 1e-12 \ + --failure_unit_name "round" \ + --failure_units_per_shot_func m.r \ + --failure_values_func "${NUM_OBS}" \ + & + + + ./tools/sinter_plot_print \ + --title "Error rates of middle-out Color Code Circuit" \ + --in "assets/generated/stats-xz-combo.csv" \ + --x_func "m.p" \ + --xaxis "[log]Noise Strength (p)" \ + --out "assets/generated/midout_error_${BASIS}.png" \ + --group_func "f'''patch base width = {m.d}, total qubits = {m.q}'''" \ + --subtitle "rounds=4d, gates=css, noise=uniform, decoder=chromobius, circuit=midout_color_code_${BASIS}" \ + --filter_func "m.r == m.d * 4 and m.c in ['midout_color_code_${BASIS}']" \ + --ymin 1e-12 \ + --failure_unit_name "round" \ + --failure_units_per_shot_func m.r \ + --failure_values_func "${NUM_OBS}" \ + & + + + ./tools/sinter_plot_print \ + --title "Footprint of superdense color code circuits" \ + --in "assets/generated/stats-xz-combo.csv" \ + --x_func "m.q" \ + --xaxis "[sqrt]Total Qubits (sqrt scale)" \ + --out "assets/generated/superdense_footprint_${BASIS}.png" \ + --group_func "f'''noise strength (p) = {m.p}'''" \ + --xmin 0 \ + --xmax 1500 \ + --subtitle "rounds=4d, gates=css, noise=uniform, decoder=chromobius, circuit=superdense_color_code_${BASIS}" \ + --line_fits \ + --filter_func "m.r == m.d * 4 and m.c in ['superdense_color_code_${BASIS}']" \ + --ymin 1e-12 \ + --failure_unit_name "round" \ + --failure_units_per_shot_func m.r \ + --failure_values_func "${NUM_OBS}" \ + & + + ./tools/sinter_plot_print \ + --title "Error rates of superdense color code circuits" \ + --in "assets/generated/stats-xz-combo.csv" \ + --x_func "m.p" \ + --xaxis "[log]Noise Strength (p)" \ + --out "assets/generated/superdense_error_${BASIS}.png" \ + --group_func "f'''patch base width = {m.d}, total qubits = {m.q}'''" \ + --subtitle "rounds=4d, gates=css, noise=uniform, decoder=chromobius, circuit=superdense_color_code_${BASIS}" \ + --filter_func "m.r == m.d * 4 and m.c in ['superdense_color_code_${BASIS}']" \ + --ymin 1e-12 \ + --failure_unit_name "round" \ + --failure_units_per_shot_func m.r \ + --failure_values_func "${NUM_OBS}" \ + & +done + +./tools/sinter_plot_print \ + --title "Decoding various planar codes under phenomenological noise" \ + --in assets/stats.csv \ + --x_func "m.q" \ + --xaxis "[sqrt]Data Qubits (sqrt scale)" \ + --out "assets/generated/phenom.png" \ + --line_fits \ + --group_func "f'''{m.c}'''" \ + --subtitle "rounds=4d, noise=phenom, decoder=chromobius, p=0.01" \ + --filter_func "m.r == m.d * 4 and abs(m.p - 0.01) < 1e-5 and 'phenom' in m.c and 'toric' not in m.c" \ + --ymin 1e-12 \ + --failure_unit_name "round" \ + --failure_units_per_shot_func m.r \ + --failure_values_func "1" \ + & + + +./tools/sinter_plot_print \ + --title "Reproduce code capacity noise" \ + --in assets/stats.csv \ + --x_func "m.p" \ + --xaxis "[log]Bit Flip Noise Strength" \ + --out "assets/generated/cmp_transit.png" \ + --group_func "f'''c={m.c} d={m.d}'''" \ + --subtitle "{common}" \ + --filter_func "m.c == 'transit_color_code'" \ + --plot_args_func "{'color': 'C' + str({1: 4, 2: 1, 4: 5, 5: 2}.get(index, index))}" \ + --ymin 1e-12 \ + & + + +wait diff --git a/tools/util_gen_stub_file.py b/tools/util_gen_stub_file.py new file mode 100644 index 0000000..a3667e2 --- /dev/null +++ b/tools/util_gen_stub_file.py @@ -0,0 +1,325 @@ +import dataclasses +import types +from typing import Any +from typing import Iterator + +import inspect +from typing import Tuple + +keep = { + "__add__", + "__eq__", + "__call__", + "__ge__", + "__getitem__", + "__gt__", + "__iadd__", + "__imul__", + "__init__", + "__truediv__", + "__itruediv__", + "__ne__", + "__neg__", + "__le__", + "__len__", + "__lt__", + "__mul__", + "__setitem__", + "__str__", + "__pos__", + "__pow__", + "__repr__", + "__rmul__", + "__hash__", + "__iter__", + "__next__", +} +skip = { + "__builtins__", + "__cached__", + "__getstate__", + "__setstate__", + "__path__", + "__class__", + "__delattr__", + "__dir__", + "__doc__", + "__file__", + "__format__", + "__getattribute__", + "__init_subclass__", + "__loader__", + "__module__", + "__name__", + "__new__", + "__package__", + "__reduce__", + "__reduce_ex__", + "__setattr__", + "__sizeof__", + "__spec__", + "__subclasshook__", + "__version__", + "__annotations__", + "__dataclass_fields__", + "__dataclass_params__", + "__dict__", + "__match_args__", + "__post_init__", + "__weakref__", + "__abstractmethods__", +} + + +def normalize_doc_string(d: str) -> str: + lines = d.splitlines() + indented_lines = [e for e in lines[1:] if e.strip()] + indentation = min([len(line) - len(line.lstrip()) for line in indented_lines], default=0) + return "\n".join(lines[:1] + [e[indentation:] for e in lines[1:]]) + + +def indented(*, paragraph: str, indentation: str) -> str: + return "".join( + indentation * (line != '\n') + line + for line in paragraph.splitlines(keepends=True) + ) + + +class DescribedObject: + def __init__(self): + self.full_name = "" + self.level = 0 + self.lines = [] + + +def splay_signature(sig: str) -> list[str]: + assert sig.startswith('def') + out = [] + + level = 0 + + start = sig.index('(') + 1 + if start == sig.index(')'): + return [sig] + mark = start + out.append(sig[:mark]) + for k in range(mark, len(sig)): + c = sig[k] + if c in '([': + level += 1 + if c in '])': + level -= 1 + if (c == ',' and level == 0) or level < 0: + k2 = k + (0 if level < 0 else 1) + s = sig[mark:k2].lstrip() + if s: + if not s.endswith(','): + s += ',' + out.append(' ' + s) + mark = k2 + if level < 0: + break + assert level == -1 + out.append(sig[mark:]) + return out + + +def _handle_pybind_method( + *, + obj: Any, + is_property: bool, + out_obj: DescribedObject, + parent: Any, + full_name: str, +) -> Tuple[str, bool, str, str]: + doc = normalize_doc_string(getattr(obj, "__doc__", "")) + if is_property: + out_obj.lines.append("@property") + doc_lines = doc.splitlines() + new_args_name = None + was_args = False + sig_handled = False + has_setter = False + doc_lines_left = [] + for line in doc_lines: + if was_args and line.strip().startswith('*') and ':' in line: + new_args_name = line[line.index('*'):line.index(':')] + if '@overload ' in line: + _, sig = line.split('@overload ') + out_obj.lines.append("@overload") + is_static = '(self' not in sig and inspect.isclass(parent) + if is_static: + out_obj.lines.append("@staticmethod") + out_obj.lines.extend(splay_signature(sig)) + out_obj.lines.append(" pass") + elif '@signature ' in line: + _, sig = line.split('@signature ') + is_static = '(self' not in sig and inspect.isclass(parent) + if is_static: + out_obj.lines.append("@staticmethod") + out_obj.lines.extend(splay_signature(sig)) + sig_handled = True + else: + doc_lines_left.append(line) + was_args = 'Args:' in line + + term_name = full_name.split(".")[-1] + if is_property: + if hasattr(obj, 'fget'): + sig_name = term_name + obj.fget.__doc__.replace('arg0', 'self').strip() + else: + sig_name = f'{term_name}(self)' + if getattr(obj, 'fset', None) is not None: + has_setter = True + elif doc_lines_left[0].startswith(term_name): + sig_name = term_name + doc_lines_left[0][len(term_name):] + doc_lines_left = doc_lines_left[1:] + else: + sig_name = term_name + + doc = "\n".join(doc_lines_left).lstrip() + text = "" + if not sig_handled: + if "(self: " in sig_name: + k_low = sig_name.index("(self: ") + len('(self') + k_high = len(sig_name) + if '->' in sig_name: k_high = sig_name.index('->', k_low, k_high) + k_high = sig_name.index(", " if ", " in sig_name[k_low:k_high] else ")", k_low, k_high) + sig_name = sig_name[:k_low] + sig_name[k_high:] + if not sig_handled: + is_static = '(self' not in sig_name and inspect.isclass(parent) + if is_static: + out_obj.lines.append("@staticmethod") + sig_name = sig_name.replace(': handle', ': Any') + sig_name = sig_name.replace('numpy.', 'np.') + if new_args_name is not None: + sig_name = sig_name.replace('*args', new_args_name) + text = "\n".join(splay_signature(f"def {sig_name}:")) + return text, has_setter, doc, sig_name + + +def print_doc(*, full_name: str, parent: object, obj: object, level: int) -> DescribedObject | None: + out_obj = DescribedObject() + out_obj.full_name = full_name + out_obj.level = level + doc = getattr(obj, "__doc__", None) or "" + doc = normalize_doc_string(doc) + if full_name.endswith("__") and len(doc.splitlines()) <= 2: + return None + + term_name = full_name.split(".")[-1] + is_property = isinstance(obj, property) + is_method = doc.startswith(term_name) + has_setter = False + is_normal_method = isinstance(obj, types.FunctionType) + sig_name = '' + if 'sinter' in full_name and is_normal_method: + text = '' + if term_name in getattr(parent, '__abstractmethods__', []): + text += '@abc.abstractmethod\n' + sig_name = f'{term_name}{inspect.signature(obj)}' + text += "\n".join(splay_signature(f"def {sig_name}:")) + text = text.replace('''ForwardRef('sinter.TaskStats')''', 'sinter.TaskStats') + text = text.replace('''ForwardRef('sinter.Task')''', 'sinter.Task') + text = text.replace('''ForwardRef('sinter.Progress')''', 'sinter.Progress') + text = text.replace('''ForwardRef('sinter.Decoder')''', 'sinter.Decoder') + text = text.replace("'AnonTaskStats'", "sinter.AnonTaskStats") + text = text.replace('sinter._decoding_decoder_class.CompiledDecoder', 'sinter.CompiledDecoder') + text = text.replace("'AnonTaskStats'", "sinter.AnonTaskStats") + text = text.replace("'stim.Circuit'", "stim.Circuit") + text = text.replace("'stim.DetectorErrorModel'", "stim.DetectorErrorModel") + text = text.replace("'sinter.CollectionOptions'", "sinter.CollectionOptions") + text = text.replace("'sinter.Fit'", 'sinter.Fit') + + # Replace default value lambdas with their source. + if 'lambda' in str(text): + for name, param in inspect.signature(obj).parameters.items(): + if 'lambda' in str(param.default): + _, lambda_src = inspect.getsource(param.default).split('lambda ') + lambda_src = lambda_src.strip() + assert lambda_src.endswith(',') + lambda_src = 'lambda ' + lambda_src[:-1] + text = text.replace(str(param.default), lambda_src) + + text = text.replace('numpy.', 'np.') + elif is_method or is_property: + text, has_setter, doc, sig_name = _handle_pybind_method( + obj=obj, + is_property=is_property, + out_obj=out_obj, + parent=parent, + full_name=full_name, + ) + elif isinstance(obj, (int, str)): + text = f"{term_name}: {type(obj).__name__} = {obj!r}" + doc = '' + else: + text = f"class {term_name}" + if inspect.isabstract(obj): + text += '(metaclass=abc.ABCMeta)' + text += ':' + if doc: + if text: + text += "\n" + text += indented(paragraph=f"\"\"\"{doc.rstrip()}\n\"\"\"", + indentation=" ") + + dataclass_fields = getattr(obj, "__dataclass_fields__", []) + if dataclass_fields: + dataclass_prop ='@dataclasses.dataclass' + if getattr(obj, '__dataclass_params__').frozen: + dataclass_prop += '(frozen=True)' + out_obj.lines.append(dataclass_prop) + + out_obj.lines.append(text.replace('._stim_avx2', '').replace('._stim_sse2', '')) + if has_setter: + if '->' in sig_name: + setter_type = sig_name[sig_name.index('->') + 2:].strip().replace('._stim_avx2', '') + else: + setter_type = 'Any' + out_obj.lines.append(f"@{term_name}.setter") + out_obj.lines.append(f"def {term_name}(self, value: {setter_type}):") + out_obj.lines.append(f" pass") + + if dataclass_fields: + for f in dataclasses.fields(obj): + if str(f.type).startswith('typing'): + t = str(f.type).replace('typing.', '') + else: + t = f.type.__name__ + t = t.replace('''Union[Dict[str, ForwardRef('JSON_TYPE')], List[ForwardRef('JSON_TYPE')], str, int, float]''', 'Any') + if f.default is dataclasses.MISSING: + out_obj.lines.append(f' {f.name}: {t}') + else: + out_obj.lines.append(f' {f.name}: {t} = {f.default}') + + return out_obj + + +def generate_documentation(*, obj: object, level: int, full_name: str) -> Iterator[DescribedObject]: + + if full_name.endswith("__"): + return + if not inspect.ismodule(obj) and not inspect.isclass(obj): + return + + for sub_name in dir(obj): + if sub_name in getattr(obj, '__dataclass_fields__', []): + continue + if sub_name in skip: + continue + if sub_name.startswith("__pybind11"): + continue + if sub_name.startswith('_') and not sub_name.startswith('__'): + continue + if sub_name.endswith("__") and sub_name not in keep: + raise ValueError("Need to classify " + sub_name + " as keep or skip.") + sub_full_name = full_name + "." + sub_name + sub_obj = getattr(obj, sub_name) + v = print_doc(full_name=sub_full_name, obj=sub_obj, level=level + 1, parent=obj) + if v is not None: + yield v + yield from generate_documentation( + obj=sub_obj, + level=level + 1, + full_name=sub_full_name)