diff --git a/.github/workflows/build-with-nix.yml b/.github/workflows/build-with-nix.yml index 08ac988e19..7695852d03 100644 --- a/.github/workflows/build-with-nix.yml +++ b/.github/workflows/build-with-nix.yml @@ -1,9 +1,14 @@ name: build with nix + on: + pull_request: + branches: + - main schedule: # 01:00 every Sunday morning - cron: '0 1 * * 0' workflow_dispatch: {} + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -11,11 +16,11 @@ jobs: build_and_test: strategy: matrix: - os: ['ubuntu-22.04', 'macos-14'] + os: ['ubuntu-24.04', 'macos-14'] runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@v26 + - uses: cachix/install-nix-action@V27 - uses: cachix/cachix-action@v14 with: name: tket diff --git a/.github/workflows/build-without-conan.yml b/.github/workflows/build-without-conan.yml index b734a2a5b1..75ae4a33ce 100644 --- a/.github/workflows/build-without-conan.yml +++ b/.github/workflows/build-without-conan.yml @@ -9,7 +9,7 @@ concurrency: cancel-in-progress: true jobs: build_and_test: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 env: INSTALL_DIR: "/home/runner/local" TMP_DIR: "/home/runner/tmp" @@ -22,7 +22,7 @@ jobs: - name: ccache uses: hendrikmuhs/ccache-action@v1.2 with: - key: no-conan-build-ubuntu-22.04 + key: no-conan-build-ubuntu-24.04 - name: install ninja run: | sudo apt update @@ -30,9 +30,9 @@ jobs: - name: Install boost run: | cd ${TMP_DIR} - wget -O boost_1_84_0.tar.gz https://sourceforge.net/projects/boost/files/boost/1.84.0/boost_1_84_0.tar.gz/download - tar xzvf boost_1_84_0.tar.gz - cd boost_1_84_0/ + wget -O boost_1_85_0.tar.gz https://sourceforge.net/projects/boost/files/boost/1.85.0/boost_1_85_0.tar.gz/download + tar xzvf boost_1_85_0.tar.gz + cd boost_1_85_0/ ./bootstrap.sh --prefix=${INSTALL_DIR} ./b2 ./b2 install @@ -74,9 +74,9 @@ jobs: - name: Install catch2 run: | cd ${TMP_DIR} - wget https://github.com/catchorg/Catch2/archive/refs/tags/v3.5.4.tar.gz - tar xzvf v3.5.4.tar.gz - cd Catch2-3.5.4/ + wget https://github.com/catchorg/Catch2/archive/refs/tags/v3.6.0.tar.gz + tar xzvf v3.6.0.tar.gz + cd Catch2-3.6.0/ mkdir build cd build cmake -GNinja -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} .. @@ -104,9 +104,9 @@ jobs: - name: Install pybind11_json run: | cd ${TMP_DIR} - wget https://github.com/pybind/pybind11_json/archive/refs/tags/0.2.13.tar.gz - tar xzvf 0.2.13.tar.gz - cd pybind11_json-0.2.13/ + wget https://github.com/pybind/pybind11_json/archive/refs/tags/0.2.14.tar.gz + tar xzvf 0.2.14.tar.gz + cd pybind11_json-0.2.14/ mkdir build cd build cmake -GNinja -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} .. diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index f3e17720c9..7e29e31506 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -4,10 +4,9 @@ on: pull_request: branches: - main - - develop push: branches: - - develop + - main schedule: # 03:00 every Saturday morning - cron: '0 3 * * 6' @@ -20,7 +19,7 @@ concurrency: jobs: check_changes: name: Check tket library version - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 outputs: tket_or_workflow_changed: ${{ steps.filter.outputs.tket_or_workflow }} tket_changed: ${{ steps.filter.outputs.tket }} @@ -30,7 +29,8 @@ jobs: tket_package_exists: ${{ steps.tket_package_exists.outputs.tket_package_exists }} steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - name: Select Python 3.12 + uses: actions/setup-python@v5 with: python-version: '3.12' - uses: dorny/paths-filter@v3.0.2 @@ -63,14 +63,14 @@ jobs: tket_package_exists=`conan search -r tket-libs "tket/${{ steps.tket_ver.outputs.tket_ver }}@tket/stable" | grep "not found" > /dev/null 2>&1 && echo false || echo true` echo "tket_package_exists=${tket_package_exists}" >> $GITHUB_OUTPUT - name: Check tket version bump - if: github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'develop' && steps.filter.outputs.tket == 'true' && steps.test_package_exists.outputs.tket_package_exists == 'true' + if: github.event_name == 'pull_request' && steps.filter.outputs.tket == 'true' && steps.test_package_exists.outputs.tket_package_exists == 'true' run: exit 1 check_docs_tket: name: Check documentation build needs: check_changes if: needs.check_changes.outputs.tket_or_workflow_changed == 'true' || needs.check_changes.outputs.doxyfile_or_workflow_changed == 'true' - runs-on: 'ubuntu-22.04' + runs-on: 'ubuntu-24.04' steps: - uses: actions/checkout@v4 - name: Check doxygen @@ -89,7 +89,8 @@ jobs: run: | brew update brew install clang-format@18 - git ls-files "*.cpp" "*.hpp" | xargs clang-format -style=file --dry-run --Werror + git ls-files "*.cpp" "*.hpp" | xargs clang-format -style=file -i + git diff --exit-code build_test_tket: name: Build and test (tket) @@ -97,18 +98,17 @@ jobs: if: needs.check_changes.outputs.tket_or_workflow_changed == 'true' strategy: matrix: - os: ['ubuntu-22.04', 'macos-12', 'macos-14'] + os: ['ubuntu-24.04', 'macos-12', 'macos-14'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: apt update - if: matrix.os == 'ubuntu-22.04' + if: matrix.os == 'ubuntu-24.04' run: sudo apt update - - name: Select Python 3.11 - # otherwise turtlebrowser/get-conan@v1.2 fails on macos-12 + - name: Select Python 3.12 uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan @@ -120,7 +120,7 @@ jobs: cp ${PROFILE_PATH} ${DEFAULT_PROFILE_PATH} conan remote add tket-libs https://quantinuumsw.jfrog.io/artifactory/api/conan/tket1-libs --index 0 - name: Install runtime test requirements - if: matrix.os == 'ubuntu-22.04' && github.event_name == 'schedule' + if: matrix.os == 'ubuntu-24.04' && github.event_name == 'schedule' run: | sudo apt install texlive texlive-latex-extra latexmk mkdir -p ~/texmf/tex/latex @@ -138,7 +138,7 @@ jobs: - name: Build tket run: conan create tket -s build_type=Release --user=tket --channel=stable -o boost/*:header_only=True -o with_all_tests=True - name: Upload package - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' + if: github.event_name == 'push' run: | ccache --set-config namespace=WITHOUT_TESTS conan create tket --user=tket --channel=stable -o boost/*:header_only=True @@ -155,6 +155,10 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 + - name: Select Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan @@ -207,7 +211,7 @@ jobs: conan build tket --user=tket --channel=stable -o boost/*:header_only=True -o with_all_tests=True -c tools.cmake.cmaketoolchain:generator=Ninja conan export-pkg tket --user=tket --channel=stable -o boost/*:header_only=True -o with_all_tests=True -c tools.cmake.cmaketoolchain:generator=Ninja - name: Upload package - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' + if: github.event_name == 'push' run: | ccache --set-config namespace=WITHOUT_TESTS conan build tket --user=tket --channel=stable -o boost/*:header_only=True @@ -223,23 +227,27 @@ jobs: name: Build and test pytket (ubuntu) needs: check_changes if: needs.check_changes.outputs.tket_or_workflow_changed == 'true' || needs.check_changes.outputs.pytket_or_workflow_changed == 'true' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + - name: Select Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan run: | conan profile detect DEFAULT_PROFILE_PATH=`conan profile path default` - PROFILE_PATH=./conan-profiles/ubuntu-22.04 + PROFILE_PATH=./conan-profiles/ubuntu-24.04 diff ${DEFAULT_PROFILE_PATH} ${PROFILE_PATH} || true cp ${PROFILE_PATH} ${DEFAULT_PROFILE_PATH} conan remote add tket-libs https://quantinuumsw.jfrog.io/artifactory/api/conan/tket1-libs --index 0 - name: ccache uses: hendrikmuhs/ccache-action@v1.2 with: - key: tket-dynamic-ubuntu-22.04 + key: tket-dynamic-ubuntu-24.04 - name: further ccache config run: | ccache --set-config base_dir=${HOME} @@ -257,7 +265,7 @@ jobs: - name: Install pytket requirements run: | conan create recipes/pybind11 - conan create recipes/pybind11_json/all --version 0.2.13 + conan create recipes/pybind11_json/all --version 0.2.14 - name: Set up Python (pull request) if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' uses: actions/setup-python@v5 @@ -319,7 +327,7 @@ jobs: name: pytket_test_coverage path: pytket/tests/htmlcov - name: Upload package - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' && needs.check_changes.outputs.tket_changed == 'true' + if: github.event_name == 'push' && needs.check_changes.outputs.tket_changed == 'true' run: | conan remote login -p ${{ secrets.JFROG_ARTIFACTORY_TOKEN_3 }} tket-libs ${{ secrets.JFROG_ARTIFACTORY_USER_3 }} conan upload tket/${{ needs.check_changes.outputs.tket_ver }}@tket/stable -r=tket-libs @@ -334,11 +342,10 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - - name: Select Python 3.11 - # otherwise turtlebrowser/get-conan@v1.2 fails on macos-12 + - name: Select Python 3.12 uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan @@ -370,7 +377,7 @@ jobs: - name: Install pytket requirements run: | conan create recipes/pybind11 - conan create recipes/pybind11_json/all --version 0.2.13 + conan create recipes/pybind11_json/all --version 0.2.14 - name: Set up Python (pull request) if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' uses: actions/setup-python@v5 @@ -410,7 +417,7 @@ jobs: git diff --quiet pytket/_tket && echo "Stubs are up-to-date" || exit 1 # fail if stubs change after regeneration python -m mypy --config-file=mypy.ini --no-incremental -p pytket -p tests - name: Upload package - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' && needs.check_changes.outputs.tket_changed == 'true' + if: github.event_name == 'push' && needs.check_changes.outputs.tket_changed == 'true' run: | conan remote login -p ${{ secrets.JFROG_ARTIFACTORY_TOKEN_3 }} tket-libs ${{ secrets.JFROG_ARTIFACTORY_USER_3 }} conan upload tket/${{ needs.check_changes.outputs.tket_ver }}@tket/stable -r=tket-libs @@ -422,6 +429,10 @@ jobs: runs-on: windows-2022 steps: - uses: actions/checkout@v4 + - name: Select Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan @@ -491,7 +502,7 @@ jobs: - name: Install pytket requirements run: | conan create recipes/pybind11 - conan create recipes/pybind11_json/all --version 0.2.13 + conan create recipes/pybind11_json/all --version 0.2.14 - name: Set up Python 3.10 if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' uses: actions/setup-python@v5 @@ -528,7 +539,7 @@ jobs: pip install -r requirements.txt pytest --ignore=simulator/ - name: Upload package - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' && needs.check_changes.outputs.tket_changed == 'true' + if: github.event_name == 'push' && needs.check_changes.outputs.tket_changed == 'true' run: | conan remote login -p ${{ secrets.JFROG_ARTIFACTORY_TOKEN_3 }} tket-libs ${{ secrets.JFROG_ARTIFACTORY_USER_3 }} conan upload tket/${{ needs.check_changes.outputs.tket_ver }}@tket/stable -r=tket-libs @@ -541,8 +552,8 @@ jobs: name: Publish pytket coverage needs: build_test_pytket_ubuntu concurrency: gh_pages - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' - runs-on: ubuntu-22.04 + if: github.event_name == 'push' + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: @@ -569,8 +580,8 @@ jobs: check_pytket_coverage: name: Check pytket line and branch coverage needs: build_test_pytket_ubuntu - if: (github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'develop') || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-22.04 + if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Download artefact @@ -578,7 +589,7 @@ jobs: with: name: pytket_test_coverage path: pytket-test-coverage/ - - name: Compare with latest report from develop + - name: Compare with latest report from main run: | wget https://cqcl.github.io/tket/pytket/test-coverage/cov.xml -O oldcov.xml ./.github/workflows/compare-pytket-coverage oldcov.xml pytket-test-coverage/cov.xml @@ -598,7 +609,7 @@ jobs: - publish_pytket_coverage - check_pytket_coverage if: always() - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - shell: python name: Check job results diff --git a/.github/workflows/build_libs.yml b/.github/workflows/build_libs.yml index 735058d515..af717d470b 100644 --- a/.github/workflows/build_libs.yml +++ b/.github/workflows/build_libs.yml @@ -2,15 +2,15 @@ name: build libraries on: push: branches: - - develop + - main pull_request: branches: - - develop + - main workflow_dispatch: {} jobs: changes: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 outputs: tklog: ${{ steps.filter.outputs.tklog }} tkassert: ${{ steps.filter.outputs.tkassert }} @@ -46,7 +46,7 @@ jobs: if: ${{ needs.changes.outputs.libs != '[]' && needs.changes.outputs.libs != '' }} strategy: matrix: - os: ['ubuntu-22.04', 'macos-12', 'windows-2022', 'macos-14'] + os: ['ubuntu-24.04', 'macos-12', 'windows-2022', 'macos-14'] lib: ${{ fromJson(needs.changes.outputs.libs) }} build_type: ['Release', 'Debug'] runs-on: ${{ matrix.os }} @@ -63,10 +63,10 @@ jobs: $normalized_file = [IO.File]::ReadAllText($f) -replace "`r`n", "`n" [IO.File]::WriteAllText($f, $normalized_file) } - - name: Set up Python 3.11 + - name: Select Python 3.12 uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan @@ -97,7 +97,7 @@ jobs: name: build library (manylinux) needs: changes if: ${{ needs.changes.outputs.libs != '[]' && needs.changes.outputs.libs != '' }} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: lib: ${{ fromJson(needs.changes.outputs.libs) }} diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 59dea72bb4..edf65fdaf6 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -3,10 +3,10 @@ name: Analyse tket C++ test coverage on: pull_request: branches: - - develop + - main push: branches: - - develop + - main schedule: # 03:00 every Saturday morning - cron: '0 3 * * 6' @@ -19,7 +19,7 @@ concurrency: jobs: changes: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 outputs: tket: ${{ steps.filter.outputs.tket }} steps: @@ -37,16 +37,20 @@ jobs: name: Generate coverage report needs: changes if: needs.changes.outputs.tket == 'true' || github.event_name == 'schedule' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + - name: Select Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan run: | conan profile detect DEFAULT_PROFILE_PATH=`conan profile path default` - PROFILE_PATH=./conan-profiles/ubuntu-22.04 + PROFILE_PATH=./conan-profiles/ubuntu-24.04 diff ${DEFAULT_PROFILE_PATH} ${PROFILE_PATH} || true cp ${PROFILE_PATH} ${DEFAULT_PROFILE_PATH} conan remote add tket-libs https://quantinuumsw.jfrog.io/artifactory/api/conan/tket1-libs --index 0 @@ -91,7 +95,7 @@ jobs: name: Check coverage needs: generate_coverage if: ((github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') && needs.changes.outputs.tket == 'true') || github.event_name == 'schedule' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Download artefact @@ -99,12 +103,12 @@ jobs: with: name: test_coverage path: test-coverage/ - - name: Compare with latest report from develop (short tests) + - name: Compare with latest report from main (short tests) if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' run: | wget https://cqcl.github.io/tket/tket/test-coverage-short/summary.txt ./.github/workflows/compare-coverage summary.txt test-coverage/summary.txt - - name: Compare with latest report from develop (full suite) + - name: Compare with latest report from main (full suite) if: github.event_name == 'schedule' run: | wget https://cqcl.github.io/tket/tket/test-coverage/summary.txt @@ -115,7 +119,7 @@ jobs: needs: generate_coverage concurrency: gh_pages if: github.event_name == 'push' && needs.changes.outputs.tket == 'true' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: @@ -144,7 +148,7 @@ jobs: needs: check_coverage concurrency: gh_pages if: github.event_name == 'schedule' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d661c5743d..81d502deb6 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,13 +3,13 @@ name: Deploy tket C++ documentation on: push: branches: - - develop + - main paths: - 'tket/src/**' jobs: build_docs: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Install Doxygen @@ -24,7 +24,7 @@ jobs: publish_docs: needs: build_docs concurrency: gh_pages - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/issue-to-project.yml b/.github/workflows/issue-to-project.yml new file mode 100644 index 0000000000..f55a9f0610 --- /dev/null +++ b/.github/workflows/issue-to-project.yml @@ -0,0 +1,16 @@ +name: Add issues to project + +on: + issues: + types: + - opened + +jobs: + add-to-project: + name: Add issue to project + runs-on: ubuntu-latest + steps: + - uses: actions/add-to-project@v1.0.1 + with: + project-url: https://github.com/orgs/CQCL-DEV/projects/19 + github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} diff --git a/.github/workflows/issue.yml b/.github/workflows/issue.yml deleted file mode 100644 index b694b63bbd..0000000000 --- a/.github/workflows/issue.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: New issue - -on: - issues: - types: [opened] - -jobs: - jira_issue: - name: Create Jira issue - runs-on: ubuntu-22.04 - steps: - - name: Login - uses: atlassian/gajira-login@v3.0.1 - env: - JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} - JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} - JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} - - name: Create Bug - uses: atlassian/gajira-create@v3.0.1 - if: contains(github.event.issue.labels.*.name, 'bug') - with: - project: TKET - issuetype: Bug - summary: «${{ github.event.issue.title }}» - description: ${{ github.event.issue.html_url }} - - name: Create Task - uses: atlassian/gajira-create@v3.0.1 - if: "! contains(github.event.issue.labels.*.name, 'bug')" - with: - project: TKET - issuetype: Task - summary: «${{ github.event.issue.title }}» - description: ${{ github.event.issue.html_url }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ae68a0fd58..db16cda435 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,7 +7,7 @@ on: jobs: lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/linuxbuildwheel b/.github/workflows/linuxbuildwheel index b79de7f6c5..1b75adae19 100755 --- a/.github/workflows/linuxbuildwheel +++ b/.github/workflows/linuxbuildwheel @@ -42,7 +42,7 @@ mkdir /tket/pytket/audited # Install pybind11 and pybind11_json ${CONAN_CMD} create recipes/pybind11 -${CONAN_CMD} create recipes/pybind11_json/all --version 0.2.13 +${CONAN_CMD} create recipes/pybind11_json/all --version 0.2.14 # build pytket cd pytket diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index d1b91ea09e..9a5980aee1 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -17,17 +17,16 @@ jobs: name: Build strategy: matrix: - os: ['ubuntu-22.04', 'macos-12', 'windows-2022', 'macos-14'] + os: ['ubuntu-24.04', 'macos-12', 'windows-2022', 'macos-14'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - - name: Select Python 3.11 - # otherwise turtlebrowser/get-conan@v1.2 fails on macos-12 + - name: Select Python 3.12 uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 @@ -51,7 +50,7 @@ jobs: build_manylinux_x86_64: name: Build on manylinux (x86_64) - runs-on: 'ubuntu-22.04' + runs-on: 'ubuntu-24.04' steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pytket_benchmarking.yml b/.github/workflows/pytket_benchmarking.yml new file mode 100644 index 0000000000..afae4750b2 --- /dev/null +++ b/.github/workflows/pytket_benchmarking.yml @@ -0,0 +1,107 @@ +name: Automated Benchmarks + +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + + build_wheels: + name: Build macos wheels + runs-on: macos-14 + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: '0' + + - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: 3.11 + + - name: Install conan + uses: turtlebrowser/get-conan@v1.2 + + - name: Set up conan + run: | + conan profile detect + DEFAULT_PROFILE_PATH=`conan profile path default` + PROFILE_PATH=./conan-profiles/macos-14 + diff ${DEFAULT_PROFILE_PATH} ${PROFILE_PATH} || true + cp ${PROFILE_PATH} ${DEFAULT_PROFILE_PATH} + conan remote add tket-libs https://quantinuumsw.jfrog.io/artifactory/api/conan/tket1-libs --index 0 + + - name: Build tket C++ + run: conan create tket --user tket --channel stable --build=missing -o boost/*:header_only=True -o tklog/*:shared=True -o tket/*:shared=True -tf "" + + - name: Build wheel + run: | + conan create recipes/pybind11 + conan create recipes/pybind11_json/all --version 0.2.14 + cd pytket + # Ensure wheels are compatible with MacOS 12.0 and later: + export WHEEL_PLAT_NAME=macosx_12_0_arm64 + python3.11 -m pip install -U pip build delocate + python3.11 -m build + delocate-wheel -v -w "$GITHUB_WORKSPACE/wheelhouse/" "dist/pytket-"*".whl" + + - name: Save Wheel + uses: actions/upload-artifact@v4 + with: + name: pytket_wheel + path: wheelhouse/ + + compile-and-compare: + name: Compile and compare + runs-on: macos-14 + needs: build_wheels + + steps: + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Download wheel + uses: actions/download-artifact@v4 + with: + name: pytket_wheel + + - name: Install dependencies + run: | + pip install pytket-*.whl + pip install --pre --index-url https://github_actions:${{ secrets.PRIVATE_PYPI_PASS }}@cqcpythonrepository.azurewebsites.net/simple/ pytket_benchmarking + + - name: Checkout pytket-benchmarking-store + uses: actions/checkout@v4 + with: + repository: CQCL/pytket-benchmarking-store + path: pytket-benchmarking-store + + - name: Perform Compilation + run: | + pytket_benchmarking compile QiskitIBMQ pytket-benchmarking-store/benchmarking_circuits/quantum_volume automated_benchmarks_compiled + pytket_benchmarking compile PytketIBMQ pytket-benchmarking-store/benchmarking_circuits/quantum_volume automated_benchmarks_compiled + + - name: Save compiled circuits + uses: actions/upload-artifact@v4 + with: + name: automated_benchmarks_compiled + path: automated_benchmarks_compiled/ + + - name: Calculate percentage better + run: echo "RETURN_TEST=$(pytket_benchmarking percentage-better pytket-benchmarking-store/benchmarking_circuits/quantum_volume automated_benchmarks_compiled PytketIBMQ)" >> $GITHUB_ENV + + - name: Create comment + uses: peter-evans/create-or-update-comment@v4 + with: + issue-number: ${{ github.event.pull_request.number }} + body: '${{ env.RETURN_TEST }}' + env: + RETURN_TEST: ${{ env.RETURN_TEST }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 269c9b0d28..8762bc989f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ on: jobs: build_Linux_wheels: name: Build manylinux - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: python3-version: ['10', '11', '12'] @@ -92,7 +92,7 @@ jobs: - name: Build wheel run: | conan create recipes/pybind11 - conan create recipes/pybind11_json/all --version 0.2.13 + conan create recipes/pybind11_json/all --version 0.2.14 cd pytket # Ensure wheels are compatible with MacOS 12.0 and later: export WHEEL_PLAT_NAME=macosx_12_0_x86_64 @@ -107,6 +107,8 @@ jobs: build_macos_arm64_wheels: name: Build macos arm64 wheels runs-on: macos-14 + env: + MACOSX_DEPLOYMENT_TARGET: '12.0' strategy: matrix: python-version: ['3.10', '3.11', '3.12'] @@ -130,16 +132,15 @@ jobs: cp ${PROFILE_PATH} ${DEFAULT_PROFILE_PATH} conan remote add tket-libs https://quantinuumsw.jfrog.io/artifactory/api/conan/tket1-libs --index 0 - name: Build tket C++ - run: conan create tket --user tket --channel stable --build=missing -o boost/*:header_only=True -o tklog/*:shared=True -o tket/*:shared=True -tf "" + run: conan create tket --user tket --channel stable --build="*" -o boost/*:header_only=True -o tklog/*:shared=True -o tket/*:shared=True -tf "" - name: Build wheel run: | conan create recipes/pybind11 - conan create recipes/pybind11_json/all --version 0.2.13 + conan create recipes/pybind11_json/all --version 0.2.14 cd pytket # Ensure wheels are compatible with MacOS 12.0 and later: export WHEEL_PLAT_NAME=macosx_12_0_arm64 - python${{ matrix.python-version }} -m pip install -U pip build - python${{ matrix.python-version }} -m pip install delocate~=0.10.7 + python${{ matrix.python-version }} -m pip install -U pip build delocate python${{ matrix.python-version }} -m build delocate-wheel -v -w "$GITHUB_WORKSPACE/wheelhouse/" "dist/pytket-"*".whl" - uses: actions/upload-artifact@v4 @@ -158,6 +159,10 @@ jobs: with: fetch-depth: '0' - run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* + - name: Select Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan @@ -171,14 +176,10 @@ jobs: conan remote add tket-libs https://quantinuumsw.jfrog.io/artifactory/api/conan/tket1-libs --index 0 - name: Build tket run: conan create tket --user tket --channel stable --build=missing -o boost/*:header_only=True -o tklog/*:shared=True -o tket/*:shared=True -tf "" - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - name: Build wheel run: | conan create recipes/pybind11 - conan create recipes/pybind11_json/all --version 0.2.13 + conan create recipes/pybind11_json/all --version 0.2.14 cd pytket python -m pip install -U pip build python -m build --outdir "${{ github.workspace }}/wheelhouse" @@ -190,7 +191,7 @@ jobs: test_linux_wheels: name: Test linux wheels needs: build_Linux_wheels - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: python3-version: ['10', '11', '12'] @@ -216,7 +217,7 @@ jobs: - name: Run tests run: cd tket/pytket/tests && pytest --ignore=simulator/ - test_Linux_aarch64_wheels: + test_linux_aarch64_wheels: name: Test linux aarch64 wheels needs: build_Linux_aarch64_wheels runs-on: 'buildjet-4vcpu-ubuntu-2204-arm' @@ -347,7 +348,7 @@ jobs: name: Publish to pypi if: github.event_name == 'release' needs: [test_linux_wheels, test_linux_aarch64_wheels, test_macos_x86_wheels, test_macos_arm64_wheels, test_Windows_wheels] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Download all wheels uses: actions/download-artifact@v4 diff --git a/.github/workflows/test-args b/.github/workflows/test-args deleted file mode 100755 index 36f072ac27..0000000000 --- a/.github/workflows/test-args +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -# ./test-args - -set -evx - -OS=$1 -ET=$2 - -if [[ $OS = "Linux" ]]; then - if [[ $ET = "schedule" ]]; then - echo "[long],~[long]" - fi -else - if [[ $ET = "schedule" ]]; then - echo "[long]~[latex],~[long]~[latex]" - else - echo "~[latex]" - fi -fi diff --git a/.github/workflows/test_libs.yml b/.github/workflows/test_libs.yml index abe72ad419..d8caee4c07 100644 --- a/.github/workflows/test_libs.yml +++ b/.github/workflows/test_libs.yml @@ -2,17 +2,17 @@ name: test libraries on: push: branches: - - develop + - main pull_request: branches: - - develop + - main workflow_dispatch: {} env: ALL_LIBS: '["tklog", "tkassert", "tkrng", "tktokenswap", "tkwsm"]' jobs: changes: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 outputs: tklog: ${{ steps.filter.outputs.tklog }} tkassert: ${{ steps.filter.outputs.tkassert }} @@ -40,7 +40,7 @@ jobs: set_libs_matrix: name: Set the libs strategy matrix needs: changes - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 outputs: libs: ${{ steps.set-matrix.outputs.matrix }} steps: @@ -63,15 +63,15 @@ jobs: strategy: fail-fast: false matrix: - os: ['ubuntu-22.04', 'macos-12', 'windows-2022', 'macos-14'] + os: ['ubuntu-24.04', 'macos-12', 'windows-2022', 'macos-14'] lib: ${{ fromJson(needs.set_libs_matrix.outputs.libs) }} runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - - name: Set up Python 3.11 + - name: Select Python 3.12 uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan @@ -100,16 +100,20 @@ jobs: strategy: matrix: lib: ${{ fromJson(needs.set_libs_matrix.outputs.libs) }} - runs-on: 'ubuntu-22.04' + runs-on: 'ubuntu-24.04' steps: - uses: actions/checkout@v4 + - name: Select Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan run: | conan profile detect DEFAULT_PROFILE_PATH=`conan profile path default` - PROFILE_PATH=./conan-profiles/ubuntu-22.04 + PROFILE_PATH=./conan-profiles/ubuntu-24.04 diff ${DEFAULT_PROFILE_PATH} ${PROFILE_PATH} || true cp ${PROFILE_PATH} ${DEFAULT_PROFILE_PATH} conan remote add tket-libs https://quantinuumsw.jfrog.io/artifactory/api/conan/tket1-libs --index 0 @@ -135,7 +139,7 @@ jobs: with: name: ${{ matrix.lib }}_coverage path: ${{ matrix.lib }}-coverage/ - - name: check coverage against latest published data from develop + - name: check coverage against latest published data from main if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' run: | # File may not exist if this is the very first time, so don't error. @@ -146,12 +150,12 @@ jobs: publish_coverage: name: Publish coverage needs: [set_libs_matrix, generate_coverage] - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && needs.set_libs_matrix.outputs.libs != '[]' && needs.set_libs_matrix.outputs.libs != '' }} + if: ${{ github.event_name == 'push' && needs.set_libs_matrix.outputs.libs != '[]' && needs.set_libs_matrix.outputs.libs != '' }} strategy: matrix: lib: ${{ fromJson(needs.set_libs_matrix.outputs.libs) }} concurrency: gh_pages - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/test_libs_all.yml b/.github/workflows/test_libs_all.yml index 3421d87374..a66e28f5b6 100644 --- a/.github/workflows/test_libs_all.yml +++ b/.github/workflows/test_libs_all.yml @@ -10,15 +10,15 @@ jobs: name: test library strategy: matrix: - os: ['ubuntu-22.04', 'macos-12', 'windows-2022', 'macos-14'] + os: ['ubuntu-24.04', 'macos-12', 'windows-2022', 'macos-14'] lib: ['tklog', 'tkassert', 'tkrng', 'tktokenswap', 'tkwsm'] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - - name: Set up Python 3.11 + - name: Select Python 3.12 uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml index 8b2159e081..68f20741a9 100644 --- a/.github/workflows/valgrind.yml +++ b/.github/workflows/valgrind.yml @@ -2,7 +2,7 @@ name: valgrind check on: pull_request: branches: - - develop + - main workflow_dispatch: {} schedule: @@ -14,7 +14,7 @@ concurrency: cancel-in-progress: true jobs: changes: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 outputs: tket: ${{ steps.filter.outputs.tket }} steps: @@ -28,20 +28,24 @@ jobs: - 'tket/**' - '.github/workflows/valgrind.yml' check: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: changes if: needs.changes.outputs.tket == 'true' steps: - uses: actions/checkout@v4 - name: apt update run: sudo apt update + - name: Select Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' - name: Install conan uses: turtlebrowser/get-conan@v1.2 - name: Set up conan run: | conan profile detect DEFAULT_PROFILE_PATH=`conan profile path default` - PROFILE_PATH=./conan-profiles/ubuntu-22.04 + PROFILE_PATH=./conan-profiles/ubuntu-24.04 diff ${DEFAULT_PROFILE_PATH} ${PROFILE_PATH} || true cp ${PROFILE_PATH} ${DEFAULT_PROFILE_PATH} conan remote add tket-libs https://quantinuumsw.jfrog.io/artifactory/api/conan/tket1-libs --index 0 @@ -58,13 +62,19 @@ jobs: ccache -p - name: build tket run: conan create tket --user=tket --channel=stable -o boost/*:header_only=True -o with_test=True --format json > tket.json - - name: Install runtime test requirements + - name: Run tests under valgrind (long) if: github.event_name == 'schedule' run: | sudo apt install texlive texlive-latex-extra latexmk mkdir -p ~/texmf/tex/latex wget http://mirrors.ctan.org/graphics/pgf/contrib/quantikz/tikzlibraryquantikz.code.tex -P ~/texmf/tex/latex - - name: Run tests under valgrind + PKGPATH=`./rootpath tket.json tket` + # realloc of size 0 used (intentionally?) in eigen + cd ${PKGPATH}/bin && valgrind --error-exitcode=1 --show-realloc-size-zero=no ./test-tket [long],~[long] + - name: Run tests under valgrind (basic) + if: github.event_name != 'schedule' run: | PKGPATH=`./rootpath tket.json tket` - cd ${PKGPATH}/bin && valgrind --error-exitcode=1 ./test-tket `./github/workflows/test-args ${{ matrix.os }} ${{ github.event_name }}` + # realloc of size 0 used (intentionally?) in eigen + cd ${PKGPATH}/bin && valgrind --error-exitcode=1 --show-realloc-size-zero=no ./test-tket + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b6bb21e212..c420c90c0f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Contributing to TKET Pull requests are welcome. To make a PR, first fork the repo, make your proposed -changes on the `develop` branch, and open a PR from your fork. If it passes +changes on the `main` branch, and open a PR from your fork. If it passes tests and is accepted after review, it will be merged in. When adding a new feature, please add tests for it. When fixing a bug, please @@ -9,11 +9,11 @@ add a test that demonstrates the fix. If you make a change to one of the libraries in the `libs` directory, please increase the version number and make a PR with that change only: the component -will then be tested on the CI, and on merge to `develop` the new version will be +will then be tested on the CI, and on merge to `main` the new version will be uploaded. Then it will be possible to update conan requirements to use the new version. -A new version of TKET is uploaded to our conan repo with each push to `develop` +A new version of TKET is uploaded to our conan repo with each push to `main` that changes the core library. This process is managed by CI workflows. If you are making changes only to TKET tests or pytket, you do not need to build TKET locally: the right version should be downloaded automatically from the conan @@ -80,7 +80,7 @@ If you make any changes in `tket/src`, you should bump the version number of `tket` in `recipes/tket/conanfile.py`, and also the `tket` versions in the `requires` field in `recipes/tket-test/conanfile.py`, `recipes/tket-proptests/conanfile.py` and `pytket/conanfile.txt` so that they -match the new version. (This is checked on the CI for all PRs to `develop`.) +match the new version. (This is checked on the CI for all PRs to `main`.) Follow the "semantic versioning" convention: any backwards-incompatible changes to the C++ API require a major version bump; new API features that maintain backwards compatibility require a minor version bump; internal improvements and @@ -92,21 +92,21 @@ bugfixes require a patch version bump. The code coverage of the `tket` tests is reported [here](https://cqcl.github.io/tket/tket/test-coverage/index.html). This report -is generated weekly from the `develop` branch. +is generated weekly from the `main` branch. The libraries' coverage (from their own unit tests) is also reported: for example [tklog](https://cqcl.github.io/tket/tket/tklog-coverage/index.html). (For other libraries, just replace "tklog" with the library name in the URL.) -In both cases, PRs to `develop` check that the coverage has not decreased, and +In both cases, PRs to `main` check that the coverage has not decreased, and merging is blocked until the coverage is at least as good as before. ### pytket The code coverage of the `pytket` tests is reported [here](https://cqcl.github.io/tket/pytket/test-coverage/index.html). This report -reflects the coverage of the `develop` branch, and is updated with every push. +reflects the coverage of the `main` branch, and is updated with every push. The same report can be found in XML format [here](https://cqcl.github.io/tket/pytket/test-coverage/cov.xml). -Lines and branch coverage results are also checked with every PR to `develop`. +Lines and branch coverage results are also checked with every PR to `main`. diff --git a/README.md b/README.md index d00fb29554..07f63fc3e8 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,8 @@ The codebase is split into two main projects: The following compiler toolchains are used to build tket on the CI and are therefore known to work: -* Linux: gcc-11 -* MacOS: apple-clang 14 +* Linux: gcc-13 +* MacOS: apple-clang 15 * Windows: MSVC 19 It is recommended that you use these versions to build locally, as code may diff --git a/build-without-conan.md b/build-without-conan.md index 5a40b5d2c4..16668345b4 100644 --- a/build-without-conan.md +++ b/build-without-conan.md @@ -22,9 +22,9 @@ The versions should match the current requirements as specified in the relevant ``` cd ${TMP_DIR} -wget -O boost_1_84_0.tar.gz https://sourceforge.net/projects/boost/files/boost/1.84.0/boost_1_84_0.tar.gz/download -tar xzvf boost_1_84_0.tar.gz -cd boost_1_84_0/ +wget -O boost_1_85_0.tar.gz https://sourceforge.net/projects/boost/files/boost/1.85.0/boost_1_85_0.tar.gz/download +tar xzvf boost_1_85_0.tar.gz +cd boost_1_85_0/ ./bootstrap.sh --prefix=${INSTALL_DIR} ./b2 ./b2 install @@ -91,9 +91,9 @@ cmake --install . ``` cd ${TMP_DIR} -wget https://github.com/catchorg/Catch2/archive/refs/tags/v3.5.4.tar.gz -tar xzvf v3.5.4.tar.gz -cd Catch2-3.5.4/ +wget https://github.com/catchorg/Catch2/archive/refs/tags/v3.6.0.tar.gz +tar xzvf v3.6.0.tar.gz +cd Catch2-3.6.0/ mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} .. @@ -133,9 +133,9 @@ cmake --install . ``` cd ${TMP_DIR} -wget https://github.com/pybind/pybind11_json/archive/refs/tags/0.2.13.tar.gz -tar xzvf 0.2.13.tar.gz -cd pybind11_json-0.2.13/ +wget https://github.com/pybind/pybind11_json/archive/refs/tags/0.2.14.tar.gz +tar xzvf 0.2.14.tar.gz +cd pybind11_json-0.2.14/ mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} .. diff --git a/conan-profiles/ubuntu-24.04 b/conan-profiles/ubuntu-24.04 new file mode 100644 index 0000000000..8976420b03 --- /dev/null +++ b/conan-profiles/ubuntu-24.04 @@ -0,0 +1,8 @@ +[settings] +arch=x86_64 +build_type=Release +compiler=gcc +compiler.cppstd=gnu17 +compiler.libcxx=libstdc++11 +compiler.version=13 +os=Linux diff --git a/libs/tkassert/test/conanfile.py b/libs/tkassert/test/conanfile.py index c3fc9af371..d92e5450b7 100644 --- a/libs/tkassert/test/conanfile.py +++ b/libs/tkassert/test/conanfile.py @@ -60,4 +60,4 @@ def package(self): def requirements(self): self.requires("tkassert/0.3.4") - self.requires("catch2/3.5.4") + self.requires("catch2/3.6.0") diff --git a/libs/tklog/src/TketLog.cpp b/libs/tklog/src/TketLog.cpp index 4d8cbe2444..7dc53059b0 100644 --- a/libs/tklog/src/TketLog.cpp +++ b/libs/tklog/src/TketLog.cpp @@ -63,8 +63,8 @@ void Logger::log(const char *levstr, const std::string &s, std::ostream &os) { #else plt = std::localtime(&t); #endif - os << "[" << std::put_time(plt, "%Y-%m-%d %H:%M:%S") << "]" << " [tket] [" - << levstr << "] " << s << std::endl; + os << "[" << std::put_time(plt, "%Y-%m-%d %H:%M:%S") << "]" + << " [tket] [" << levstr << "] " << s << std::endl; } void Logger::set_level(LogLevel lev) { level = lev; } diff --git a/libs/tklog/test/conanfile.py b/libs/tklog/test/conanfile.py index b250a0bbbd..007d315926 100644 --- a/libs/tklog/test/conanfile.py +++ b/libs/tklog/test/conanfile.py @@ -60,4 +60,4 @@ def package(self): def requirements(self): self.requires("tklog/0.3.3") - self.requires("catch2/3.5.4") + self.requires("catch2/3.6.0") diff --git a/libs/tkrng/test/conanfile.py b/libs/tkrng/test/conanfile.py index eea5bec9f4..bcec0b0f04 100644 --- a/libs/tkrng/test/conanfile.py +++ b/libs/tkrng/test/conanfile.py @@ -60,4 +60,4 @@ def package(self): def requirements(self): self.requires("tkrng/0.3.3") - self.requires("catch2/3.5.4") + self.requires("catch2/3.6.0") diff --git a/libs/tktokenswap/conanfile.py b/libs/tktokenswap/conanfile.py index db0d5a6d1a..3c3410586c 100644 --- a/libs/tktokenswap/conanfile.py +++ b/libs/tktokenswap/conanfile.py @@ -19,7 +19,7 @@ class TktokenswapConan(ConanFile): name = "tktokenswap" - version = "0.3.7" + version = "0.3.8" package_type = "library" license = "Apache 2" url = "https://github.com/CQCL/tket" @@ -73,4 +73,4 @@ def requirements(self): self.requires("tklog/0.3.3@tket/stable") self.requires("tkassert/0.3.4@tket/stable", transitive_headers=True) self.requires("tkrng/0.3.3@tket/stable") - self.requires("boost/1.84.0", transitive_libs=False) + self.requires("boost/1.85.0", transitive_libs=False) diff --git a/libs/tktokenswap/test/conanfile.py b/libs/tktokenswap/test/conanfile.py index ec9cdaf165..180daf55bb 100644 --- a/libs/tktokenswap/test/conanfile.py +++ b/libs/tktokenswap/test/conanfile.py @@ -59,6 +59,6 @@ def package(self): cmake.install() def requirements(self): - self.requires("tktokenswap/0.3.7") + self.requires("tktokenswap/0.3.8") self.requires("tkrng/0.3.3@tket/stable") - self.requires("catch2/3.5.4") + self.requires("catch2/3.6.0") diff --git a/libs/tkwsm/conanfile.py b/libs/tkwsm/conanfile.py index 613655278d..ed1190d48b 100644 --- a/libs/tkwsm/conanfile.py +++ b/libs/tkwsm/conanfile.py @@ -19,7 +19,7 @@ class TkwsmConan(ConanFile): name = "tkwsm" - version = "0.3.7" + version = "0.3.8" package_type = "library" license = "Apache 2" url = "https://github.com/CQCL/tket" @@ -72,4 +72,4 @@ def package_info(self): def requirements(self): self.requires("tkassert/0.3.4@tket/stable") self.requires("tkrng/0.3.3@tket/stable") - self.requires("boost/1.84.0", transitive_headers=True, transitive_libs=False) + self.requires("boost/1.85.0", transitive_headers=True, transitive_libs=False) diff --git a/libs/tkwsm/test/conanfile.py b/libs/tkwsm/test/conanfile.py index 89a0e3b97a..ab74d320ad 100644 --- a/libs/tkwsm/test/conanfile.py +++ b/libs/tkwsm/test/conanfile.py @@ -59,7 +59,7 @@ def package(self): cmake.install() def requirements(self): - self.requires("tkwsm/0.3.7") + self.requires("tkwsm/0.3.8") self.requires("tkassert/0.3.4@tket/stable") self.requires("tkrng/0.3.3@tket/stable") - self.requires("catch2/3.5.4") + self.requires("catch2/3.6.0") diff --git a/nix-support/pytket.nix b/nix-support/pytket.nix index 6368ac7a1f..5291e423af 100644 --- a/nix-support/pytket.nix +++ b/nix-support/pytket.nix @@ -39,7 +39,7 @@ in { inherit version; propagatedBuildInputs = with super.python3.pkgs; [ self.binders - super.lark-parser + super.lark super.types-pkg_resources super.qwasm graphviz diff --git a/nix-support/third-party-python-packages.nix b/nix-support/third-party-python-packages.nix index b462a4c0b7..6349663014 100644 --- a/nix-support/third-party-python-packages.nix +++ b/nix-support/third-party-python-packages.nix @@ -4,8 +4,8 @@ self: super: { src = super.fetchFromGitHub { owner = "pybind"; repo = "pybind11_json"; - rev = "0.2.13"; - sha256 = "sha256:Kl/QflV2bBoH72/LW03K8JDlhBF+DYYXL47A5s1nmTw="; + rev = "0.2.14"; + sha256 = "sha256-6L675DsfafzRv0mRR3b0eUFFjUpll3jCPoBAAffk7U0="; }; nativeBuildInputs = [ super.cmake ]; buildInputs = [ super.python3Packages.pybind11 super.nlohmann_json ]; @@ -19,15 +19,17 @@ self: super: { sha256 = "sha256:g/QA5CpAR3exRDgVQMnXGIH8bEGtwGFBjjSblbdXRkU="; }; }; - lark-parser = super.python3.pkgs.buildPythonPackage { - pname = "lark-parser"; - version = "0.12.0"; + lark = super.python3.pkgs.buildPythonPackage { + pname = "lark"; + version = "1.1.9"; + format = "pyproject"; src = super.fetchFromGitHub { owner = "lark-parser"; repo = "lark"; - rev = "refs/tags/0.12.0"; - hash = "sha256-zcMGCn3ixD3dJg3GlC/ijs+U1JN1BodHLTXZc/5UR7Y="; + rev = "refs/tags/1.1.9"; + hash = "sha256:pWLKjELy10VNumpBHjBYCO2TltKsZx1GhQcGMHsYJNk="; }; + nativeBuildInputs = with super.python3Packages; [ setuptools ]; doCheck = false; }; types-pkg_resources = let diff --git a/pytket/CMakeLists.txt b/pytket/CMakeLists.txt index 455fc2d297..9b66d5c6c2 100644 --- a/pytket/CMakeLists.txt +++ b/pytket/CMakeLists.txt @@ -61,10 +61,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") # remove -Wno-deprecated-declarations once https://github.com/boostorg/boost/issues/688 is resolved endif() -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - # Suppress warnings coming from headers in pybind11_json/0.2.13: - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-redundant-move") -endif() if (UNIX) # Allow binder libraries to load other shared libraries from same directory. diff --git a/pytket/README.md b/pytket/README.md index aae8a9e915..31c8a1b5a1 100644 --- a/pytket/README.md +++ b/pytket/README.md @@ -23,7 +23,7 @@ It is also currently necessary to use the local `pybind11_json` recipe, since the recipe on the `conan-center` is not yet compatible with conan 2: ```shell -conan create recipes/pybind11_json/all --version=0.2.13 +conan create recipes/pybind11_json/all --version=0.2.14 ``` Then build the pytket module: diff --git a/pytket/binders/circuit/Circuit/add_op.cpp b/pytket/binders/circuit/Circuit/add_op.cpp index c26e0d7614..20447d429d 100644 --- a/pytket/binders/circuit/Circuit/add_op.cpp +++ b/pytket/binders/circuit/Circuit/add_op.cpp @@ -1333,7 +1333,7 @@ void init_circuit_add_op(py::class_> &c) { [](Circuit *circ, const Expr &angle, unsigned qb, const py::kwargs &kwargs) { return add_gate_method_oneparam( - circ, OpType::GPI, angle, {qb}, kwargs); + circ, OpType::GPI2, angle, {qb}, kwargs); }, "Appends a GPI2 gate with a possibly symbolic angle " "(specified in half-turns)." diff --git a/pytket/binders/circuit/main.cpp b/pytket/binders/circuit/main.cpp index 2687745a63..2214622f9e 100644 --- a/pytket/binders/circuit/main.cpp +++ b/pytket/binders/circuit/main.cpp @@ -439,10 +439,18 @@ PYBIND11_MODULE(circuit, m) { ":math:`(\\alpha, \\beta) \\mapsto \\mathrm{PhasedX}(\\alpha, \\beta)" "^{\\otimes n}` (n-qubit gate composed of identical PhasedX in " "parallel.") + .value( + "CnRx", OpType::CnRx, + ":math:`(\\alpha)` := n-controlled " + ":math:`\\mathrm{Rx}(\\alpha)` gate.") .value( "CnRy", OpType::CnRy, ":math:`(\\alpha)` := n-controlled " ":math:`\\mathrm{Ry}(\\alpha)` gate.") + .value( + "CnRz", OpType::CnRz, + ":math:`(\\alpha)` := n-controlled " + ":math:`\\mathrm{Rz}(\\alpha)` gate.") .value("CnX", OpType::CnX, "n-controlled X gate.") .value("CnY", OpType::CnY, "n-controlled Y gate.") .value("CnZ", OpType::CnZ, "n-controlled Z gate.") diff --git a/pytket/binders/circuit_library.cpp b/pytket/binders/circuit_library.cpp index 0fcf6706c7..61a879f2ba 100644 --- a/pytket/binders/circuit_library.cpp +++ b/pytket/binders/circuit_library.cpp @@ -294,5 +294,32 @@ PYBIND11_MODULE(circuit_library, library_m) { library_m.def( "TK1_to_TK1", &CircPool::tk1_to_tk1, "A circuit of a single tk1 gate with given parameters"); + library_m.def( + "Rx_using_GPI", &CircPool::Rx_using_GPI, + "Equivalent to Rx, using GPI and GPI2 gates"); + library_m.def( + "Ry_using_GPI", &CircPool::Ry_using_GPI, + "Equivalent to Ry, using GPI and GPI2 gates"); + library_m.def( + "Rz_using_GPI", &CircPool::Rz_using_GPI, + "Equivalent to Rz, using GPI gates"); + library_m.def( + "XXPhase_using_AAMS", &CircPool::XXPhase_using_AAMS, + "Equivalent to XXPhase, using AAMS gates"); + library_m.def( + "YYPhase_using_AAMS", &CircPool::YYPhase_using_AAMS, + "Equivalent to YYPhase, using AAMS gates"); + library_m.def( + "ZZPhase_using_AAMS", &CircPool::ZZPhase_using_AAMS, + "Equivalent to ZZPhase, using AAMS, GPI and GPI2 gates"); + library_m.def( + "CX_using_AAMS", &CircPool::CX_using_AAMS, + "Equivalent to CX, using AAMS, GPI and GPI2 gates"); + library_m.def( + "TK1_using_GPI", &CircPool::TK1_using_GPI, + "Equivalent to TK1, using GPI and GPI2 gates"); + library_m.def( + "TK2_using_AAMS", &CircPool::TK2_using_AAMS, + "Equivalent to TK2, using AAMS, GPI and GPI2 gates"); } } // namespace tket diff --git a/pytket/binders/include/UnitRegister.hpp b/pytket/binders/include/UnitRegister.hpp index 32c7fed8b5..0db7009179 100644 --- a/pytket/binders/include/UnitRegister.hpp +++ b/pytket/binders/include/UnitRegister.hpp @@ -30,7 +30,7 @@ template class UnitRegister { public: UnitRegister(const std::string &name, const std::size_t size) - : name_(name), size_(size){}; + : name_(name), size_(size) {}; std::string name() const { return name_; } std::size_t size() const { return size_; } diff --git a/pytket/binders/passes.cpp b/pytket/binders/passes.cpp index 22f07ff06f..8bed732bc1 100644 --- a/pytket/binders/passes.cpp +++ b/pytket/binders/passes.cpp @@ -453,7 +453,7 @@ PYBIND11_MODULE(passes, m) { m.def( "DecomposeArbitrarilyControlledGates", &DecomposeArbitrarilyControlledGates, - "Decomposes CCX, CnX, CnY, CnZ, and CnRy gates into " + "Decomposes CCX, CnX, CnY, CnZ, CnRy, CnRz and CnRx gates into " "CX and single-qubit gates."); m.def( "DecomposeBoxes", &DecomposeBoxes, @@ -902,6 +902,19 @@ PYBIND11_MODULE(passes, m) { "\n:return: a pass to perform the simplification", py::arg("strat") = Transforms::PauliSynthStrat::Sets, py::arg("cx_config") = CXConfigType::Snake); + m.def( + "GreedyPauliSimp", &gen_greedy_pauli_simp, + "Construct a pass that converts a circuit into a graph of Pauli " + "gadgets to account for commutation and phase folding, and " + "resynthesises them using a greedy algorithm adapted from " + "arxiv.org/abs/2103.08602. The method for synthesising the " + "final Clifford operator is adapted from " + "arxiv.org/abs/2305.10966." + "\n\n:param discount_rate: Rate used to discount the cost impact from " + "gadgets that are further away. Default to 0.7." + "\n:param depth_weight: Degree of depth optimisation. Default to 0.3." + "\n:return: a pass to perform the simplification", + py::arg("discount_rate") = 0.7, py::arg("depth_weight") = 0.3); m.def( "PauliSquash", &PauliSquash, "Applies :py:meth:`PauliSimp` followed by " diff --git a/pytket/binders/placement.cpp b/pytket/binders/placement.cpp index f89e4543fb..a3107dcb52 100644 --- a/pytket/binders/placement.cpp +++ b/pytket/binders/placement.cpp @@ -39,10 +39,11 @@ void place_fully_connected( "Circuit has more qubits than the FullyConnected graph has nodes"); } std::map qmap; - unsigned index = 0; - for (const Qubit &q : circ.all_qubits()) { - qmap[q] = Node("fcNode", index); - index++; + std::vector qubits = circ.all_qubits(); + std::vector nodes = fully_connected.get_all_nodes_vec(); + TKET_ASSERT(nodes.size() >= qubits.size()); + for (unsigned i = 0; i < qubits.size(); i++) { + qmap[qubits[i]] = nodes[i]; } place_with_map(circ, qmap); } diff --git a/pytket/binders/transform.cpp b/pytket/binders/transform.cpp index 91a1c12276..8c074c3a1e 100644 --- a/pytket/binders/transform.cpp +++ b/pytket/binders/transform.cpp @@ -26,6 +26,7 @@ #include "tket/Transformations/Combinator.hpp" #include "tket/Transformations/ContextualReduction.hpp" #include "tket/Transformations/Decomposition.hpp" +#include "tket/Transformations/GreedyPauliOptimisation.hpp" #include "tket/Transformations/OptimisationPass.hpp" #include "tket/Transformations/PauliOptimisation.hpp" #include "tket/Transformations/Rebase.hpp" @@ -151,6 +152,10 @@ PYBIND11_MODULE(transform, m) { "Rebase from any gate set into the gate set supported by " "ProjectQ (Rx, Ry, Rz, X, Y, Z, S, T, V, H, CX, CZ, CRz, " "SWAP).") + .def_static( + "RebaseToIonQ", &Transforms::rebase_ionq, + "Rebase from any gate set into the gate set supported by " + "IonQ (GPI, GPI2, AAMS).") .def_static( "DecomposeCCX", &Transforms::decomp_CCX, "Decomposes all 3-qubit Toffoli (CCX) gates into " @@ -407,6 +412,21 @@ PYBIND11_MODULE(transform, m) { "provides them.", py::arg("synth_strat") = Transforms::PauliSynthStrat::Sets, py::arg("cx_config") = CXConfigType::Snake) + .def_static( + "GreedyPauliSimp", &Transforms::greedy_pauli_optimisation, + "Convert a circuit into a graph of Pauli " + "gadgets to account for commutation and phase folding, and " + "resynthesises them using a greedy algorithm adapted from " + "arxiv.org/abs/2103.08602. The method for synthesising the " + "final Clifford operator is adapted from " + "arxiv.org/abs/2305.10966." + "\n\n:param discount_rate: Rate used to discount the cost impact " + "from " + "gadgets that are further away. Default to 0.7." + "\n:param depth_weight: Degree of depth optimisation. Default to " + "0.3." + "\n:return: a pass to perform the simplification", + py::arg("discount_rate") = 0.7, py::arg("depth_weight") = 0.3) .def_static( "ZZPhaseToRz", &Transforms::ZZPhase_to_Rz, "Fixes all ZZPhase gate angles to [-1, 1) half turns.") diff --git a/pytket/conanfile.py b/pytket/conanfile.py index 0f2b30f322..04ceca9ea9 100644 --- a/pytket/conanfile.py +++ b/pytket/conanfile.py @@ -32,14 +32,14 @@ def package(self): cmake.install() def requirements(self): - self.requires("tket/1.2.117@tket/stable") + self.requires("tket/1.3.1@tket/stable") self.requires("tklog/0.3.3@tket/stable") self.requires("tkrng/0.3.3@tket/stable") self.requires("tkassert/0.3.4@tket/stable") - self.requires("tkwsm/0.3.7@tket/stable") - self.requires("tktokenswap/0.3.7@tket/stable") + self.requires("tkwsm/0.3.8@tket/stable") + self.requires("tktokenswap/0.3.8@tket/stable") self.requires("symengine/0.11.2") self.requires("gmp/6.3.0") self.requires("pybind11/2.12.0") self.requires("nlohmann_json/3.11.3") - self.requires("pybind11_json/0.2.13") + self.requires("pybind11_json/0.2.14") diff --git a/pytket/docs/changelog.rst b/pytket/docs/changelog.rst index 29ea0efdf9..8609320ff4 100644 --- a/pytket/docs/changelog.rst +++ b/pytket/docs/changelog.rst @@ -1,6 +1,36 @@ Changelog ========= +1.28.0 (May 2024) +----------------- + +Features: + +* Add ``OpType.CnRx`` and ``OpType.CnRz``. + +Fixes: + +* Allow barriers when dagger or transpose a circuit. + + +1.28.0 (May 2024) +----------------- + +Features: + +* Update to pytket-circuit-renderer 0.8. +* Add two new status values for circuits on backends: "CANCELLING" and "RETRYING". +* Use `lark` package instead of deprecated `lark-parser`. +* Add ``GreedyPauliSimp`` optimisation pass. +* Add ``BitWiseOp.ZERO`` and ``BitWiseOp.ONE`` to allow construction of constant + conditional expressions. +* Add target gateset ``(GPI, GPI2, AAMS)`` to ``auto_rebase_pass``. +* Add ``RebaseToIonQ`` transform. + +Fixes: + +* Escape underscores in qubit and bit names when converting to latex. + 1.27.0 (April 2024) ------------------- diff --git a/pytket/docs/conf.py b/pytket/docs/conf.py index 9d4e85b76d..b29825325d 100644 --- a/pytket/docs/conf.py +++ b/pytket/docs/conf.py @@ -38,9 +38,9 @@ author = "Quantinuum" # The short X.Y version -version = "1.27" +version = "1.28" # The full version, including alpha/beta/rc tags -release = "1.27.0" +release = "1.28.0" # -- General configuration --------------------------------------------------- diff --git a/pytket/docs/extensions.rst b/pytket/docs/extensions.rst index 9f305762a9..ab9ef929d2 100644 --- a/pytket/docs/extensions.rst +++ b/pytket/docs/extensions.rst @@ -2,7 +2,7 @@ pytket extensions ================= The pytket extensions are separate python modules which allow pytket to interface with backends from a range of providers including quantum devices from Quantinuum and IBM. -In pytket a ``Backend`` represents a connection to a QPU (Quantum Processing Unit) or simulator for processing quantum circuits. One can also access additional quantum devices and simulators via the cloud through the extensions for `Azure `_ and `Braket `_ . +In pytket a ``Backend`` represents a connection to a QPU (Quantum Processing Unit) or simulator for processing quantum circuits. One can also access additional quantum devices and simulators via the cloud through the extensions for `Braket `_ . Additionally, the extensions allow pytket to cross-compile circuits from different quantum computing libraries with the extensions for `qiskit `_, `cirq `_ and `pennylane `_ . This enables pytket's compilation features to be used in conjunction with other software tools. @@ -48,9 +48,6 @@ QPUs Cloud Access ------------ -`AzureBackend `_ -- Backend for running circuits remotely using Azure Quantum devices and simulators. - `BraketBackend `_ - Interface to Amazon Braket service. @@ -119,13 +116,6 @@ Other `QulacsBackend `_ - Backend for running simulations of variational quantum circuits on the Qulacs simulator. -`QsharpSimulatorBackend `_ -- Backend for simulating a circuit using the QDK. - -`QsharpToffoliSimulatorBackend `_ -- Backend for simulating a Toffoli circuit using the QDK. - - .. toctree:: :caption: Extensions: :maxdepth: 0 @@ -141,7 +131,6 @@ Other pytket-pyzx pytket-qir pytket-qiskit - pytket-qsharp pytket-quantinuum pytket-cutensornet pytket-qulacs @@ -157,4 +146,4 @@ Other .. _AerUnitaryBackend: https://tket.quantinuum.com/extensions/pytket-qiskit/api.html#pytket.extensions.qiskit.AerUnitaryBackend .. _CirqDensityMatrixSampleBackend: https://tket.quantinuum.com/extensions/pytket-cirq/api.html#pytket.extensions.cirq.CirqDensityMatrixSampleBackend .. _SimplexBackend: https://tket.quantinuum.com/extensions/pytket-pysimplex/api.html#pytket.extensions.pysimplex.SimplexBackend -.. _QulacsBackend: https://tket.quantinuum.com/extensions/pytket-qulacs/api.html#pytket.extensions.qulacs.QulacsBackend \ No newline at end of file +.. _QulacsBackend: https://tket.quantinuum.com/extensions/pytket-qulacs/api.html#pytket.extensions.qulacs.QulacsBackend diff --git a/pytket/package.md b/pytket/package.md index 5bd7ee3317..1d253af59c 100644 --- a/pytket/package.md +++ b/pytket/package.md @@ -35,7 +35,7 @@ For worked examples using TKET see our [notebook examples](https://tket.quantinu For bugs and feature requests we recommend creating an issue on the [github repository](https://github.com/CQCL/tket). -User support: tket-support@cambridgequantum.com +User support: tket-support@quantinuum.com For discussion, join the public slack channel [here](https://join.slack.com/t/tketusers/shared_invite/zt-18qmsamj9-UqQFVdkRzxnXCcKtcarLRA). diff --git a/pytket/pytket/_tket/circuit.pyi b/pytket/pytket/_tket/circuit.pyi index 163ac46444..eb0e7f8de3 100644 --- a/pytket/pytket/_tket/circuit.pyi +++ b/pytket/pytket/_tket/circuit.pyi @@ -3250,8 +3250,12 @@ class OpType: NPhasedX : :math:`(\\alpha, \\beta) \\mapsto \\mathrm{PhasedX}(\\alpha, \\beta)^{\\otimes n}` (n-qubit gate composed of identical PhasedX in parallel. + CnRx : :math:`(\\alpha)` := n-controlled :math:`\\mathrm{Rx}(\\alpha)` gate. + CnRy : :math:`(\\alpha)` := n-controlled :math:`\\mathrm{Ry}(\\alpha)` gate. + CnRz : :math:`(\\alpha)` := n-controlled :math:`\\mathrm{Rz}(\\alpha)` gate. + CnX : n-controlled X gate. CnY : n-controlled Y gate. @@ -3319,22 +3323,24 @@ class OpType: CX: typing.ClassVar[OpType] # value = CY: typing.ClassVar[OpType] # value = CZ: typing.ClassVar[OpType] # value = - CircBox: typing.ClassVar[OpType] # value = - ClassicalExpBox: typing.ClassVar[OpType] # value = + CircBox: typing.ClassVar[OpType] # value = + ClassicalExpBox: typing.ClassVar[OpType] # value = ClassicalTransform: typing.ClassVar[OpType] # value = + CnRx: typing.ClassVar[OpType] # value = CnRy: typing.ClassVar[OpType] # value = - CnX: typing.ClassVar[OpType] # value = - CnY: typing.ClassVar[OpType] # value = - CnZ: typing.ClassVar[OpType] # value = - Conditional: typing.ClassVar[OpType] # value = - ConjugationBox: typing.ClassVar[OpType] # value = + CnRz: typing.ClassVar[OpType] # value = + CnX: typing.ClassVar[OpType] # value = + CnY: typing.ClassVar[OpType] # value = + CnZ: typing.ClassVar[OpType] # value = + Conditional: typing.ClassVar[OpType] # value = + ConjugationBox: typing.ClassVar[OpType] # value = CopyBits: typing.ClassVar[OpType] # value = - CustomGate: typing.ClassVar[OpType] # value = - DiagonalBox: typing.ClassVar[OpType] # value = - DummyBox: typing.ClassVar[OpType] # value = + CustomGate: typing.ClassVar[OpType] # value = + DiagonalBox: typing.ClassVar[OpType] # value = + DummyBox: typing.ClassVar[OpType] # value = ECR: typing.ClassVar[OpType] # value = ESWAP: typing.ClassVar[OpType] # value = - ExpBox: typing.ClassVar[OpType] # value = + ExpBox: typing.ClassVar[OpType] # value = ExplicitModifier: typing.ClassVar[OpType] # value = ExplicitPredicate: typing.ClassVar[OpType] # value = FSim: typing.ClassVar[OpType] # value = @@ -3347,19 +3353,19 @@ class OpType: Label: typing.ClassVar[OpType] # value = Measure: typing.ClassVar[OpType] # value = MultiBit: typing.ClassVar[OpType] # value = - MultiplexedRotationBox: typing.ClassVar[OpType] # value = - MultiplexedTensoredU2Box: typing.ClassVar[OpType] # value = - MultiplexedU2Box: typing.ClassVar[OpType] # value = - MultiplexorBox: typing.ClassVar[OpType] # value = + MultiplexedRotationBox: typing.ClassVar[OpType] # value = + MultiplexedTensoredU2Box: typing.ClassVar[OpType] # value = + MultiplexedU2Box: typing.ClassVar[OpType] # value = + MultiplexorBox: typing.ClassVar[OpType] # value = NPhasedX: typing.ClassVar[OpType] # value = - PauliExpBox: typing.ClassVar[OpType] # value = - PauliExpCommutingSetBox: typing.ClassVar[OpType] # value = - PauliExpPairBox: typing.ClassVar[OpType] # value = + PauliExpBox: typing.ClassVar[OpType] # value = + PauliExpCommutingSetBox: typing.ClassVar[OpType] # value = + PauliExpPairBox: typing.ClassVar[OpType] # value = Phase: typing.ClassVar[OpType] # value = - PhasePolyBox: typing.ClassVar[OpType] # value = + PhasePolyBox: typing.ClassVar[OpType] # value = PhasedISWAP: typing.ClassVar[OpType] # value = PhasedX: typing.ClassVar[OpType] # value = - QControlBox: typing.ClassVar[OpType] # value = + QControlBox: typing.ClassVar[OpType] # value = RangePredicate: typing.ClassVar[OpType] # value = Reset: typing.ClassVar[OpType] # value = Rx: typing.ClassVar[OpType] # value = @@ -3371,21 +3377,21 @@ class OpType: SXdg: typing.ClassVar[OpType] # value = Sdg: typing.ClassVar[OpType] # value = SetBits: typing.ClassVar[OpType] # value = - StatePreparationBox: typing.ClassVar[OpType] # value = + StatePreparationBox: typing.ClassVar[OpType] # value = Stop: typing.ClassVar[OpType] # value = Sycamore: typing.ClassVar[OpType] # value = T: typing.ClassVar[OpType] # value = TK1: typing.ClassVar[OpType] # value = TK2: typing.ClassVar[OpType] # value = Tdg: typing.ClassVar[OpType] # value = - TermSequenceBox: typing.ClassVar[OpType] # value = - ToffoliBox: typing.ClassVar[OpType] # value = + TermSequenceBox: typing.ClassVar[OpType] # value = + ToffoliBox: typing.ClassVar[OpType] # value = U1: typing.ClassVar[OpType] # value = U2: typing.ClassVar[OpType] # value = U3: typing.ClassVar[OpType] # value = - Unitary1qBox: typing.ClassVar[OpType] # value = - Unitary2qBox: typing.ClassVar[OpType] # value = - Unitary3qBox: typing.ClassVar[OpType] # value = + Unitary1qBox: typing.ClassVar[OpType] # value = + Unitary2qBox: typing.ClassVar[OpType] # value = + Unitary3qBox: typing.ClassVar[OpType] # value = V: typing.ClassVar[OpType] # value = Vdg: typing.ClassVar[OpType] # value = WASM: typing.ClassVar[OpType] # value = @@ -3397,7 +3403,7 @@ class OpType: Z: typing.ClassVar[OpType] # value = ZZMax: typing.ClassVar[OpType] # value = ZZPhase: typing.ClassVar[OpType] # value = - __members__: typing.ClassVar[dict[str, OpType]] # value = {'Phase': , 'Z': , 'X': , 'Y': , 'S': , 'Sdg': , 'T': , 'Tdg': , 'V': , 'Vdg': , 'SX': , 'SXdg': , 'H': , 'Rx': , 'Ry': , 'Rz': , 'U1': , 'U2': , 'U3': , 'GPI': , 'GPI2': , 'AAMS': , 'TK1': , 'TK2': , 'CX': , 'CY': , 'CZ': , 'CH': , 'CV': , 'CVdg': , 'CSX': , 'CSXdg': , 'CS': , 'CSdg': , 'CRz': , 'CRx': , 'CRy': , 'CU1': , 'CU3': , 'CCX': , 'ECR': , 'SWAP': , 'CSWAP': , 'noop': , 'Barrier': , 'Label': , 'Branch': , 'Goto': , 'Stop': , 'BRIDGE': , 'Measure': , 'Reset': , 'CircBox': , 'PhasePolyBox': , 'Unitary1qBox': , 'Unitary2qBox': , 'Unitary3qBox': , 'ExpBox': , 'PauliExpBox': , 'PauliExpPairBox': , 'PauliExpCommutingSetBox': , 'TermSequenceBox': , 'QControlBox': , 'ToffoliBox': , 'ConjugationBox': , 'DummyBox': , 'CustomGate': , 'Conditional': , 'ISWAP': , 'PhasedISWAP': , 'XXPhase': , 'YYPhase': , 'ZZPhase': , 'XXPhase3': , 'PhasedX': , 'NPhasedX': , 'CnRy': , 'CnX': , 'CnY': , 'CnZ': , 'ZZMax': , 'ESWAP': , 'FSim': , 'Sycamore': , 'ISWAPMax': , 'ClassicalTransform': , 'WASM': , 'SetBits': , 'CopyBits': , 'RangePredicate': , 'ExplicitPredicate': , 'ExplicitModifier': , 'MultiBit': , 'ClassicalExpBox': , 'MultiplexorBox': , 'MultiplexedRotationBox': , 'MultiplexedU2Box': , 'MultiplexedTensoredU2Box': , 'StatePreparationBox': , 'DiagonalBox': } + __members__: typing.ClassVar[dict[str, OpType]] # value = {'Phase': , 'Z': , 'X': , 'Y': , 'S': , 'Sdg': , 'T': , 'Tdg': , 'V': , 'Vdg': , 'SX': , 'SXdg': , 'H': , 'Rx': , 'Ry': , 'Rz': , 'U1': , 'U2': , 'U3': , 'GPI': , 'GPI2': , 'AAMS': , 'TK1': , 'TK2': , 'CX': , 'CY': , 'CZ': , 'CH': , 'CV': , 'CVdg': , 'CSX': , 'CSXdg': , 'CS': , 'CSdg': , 'CRz': , 'CRx': , 'CRy': , 'CU1': , 'CU3': , 'CCX': , 'ECR': , 'SWAP': , 'CSWAP': , 'noop': , 'Barrier': , 'Label': , 'Branch': , 'Goto': , 'Stop': , 'BRIDGE': , 'Measure': , 'Reset': , 'CircBox': , 'PhasePolyBox': , 'Unitary1qBox': , 'Unitary2qBox': , 'Unitary3qBox': , 'ExpBox': , 'PauliExpBox': , 'PauliExpPairBox': , 'PauliExpCommutingSetBox': , 'TermSequenceBox': , 'QControlBox': , 'ToffoliBox': , 'ConjugationBox': , 'DummyBox': , 'CustomGate': , 'Conditional': , 'ISWAP': , 'PhasedISWAP': , 'XXPhase': , 'YYPhase': , 'ZZPhase': , 'XXPhase3': , 'PhasedX': , 'NPhasedX': , 'CnRx': , 'CnRy': , 'CnRz': , 'CnX': , 'CnY': , 'CnZ': , 'ZZMax': , 'ESWAP': , 'FSim': , 'Sycamore': , 'ISWAPMax': , 'ClassicalTransform': , 'WASM': , 'SetBits': , 'CopyBits': , 'RangePredicate': , 'ExplicitPredicate': , 'ExplicitModifier': , 'MultiBit': , 'ClassicalExpBox': , 'MultiplexorBox': , 'MultiplexedRotationBox': , 'MultiplexedU2Box': , 'MultiplexedTensoredU2Box': , 'StatePreparationBox': , 'DiagonalBox': } noop: typing.ClassVar[OpType] # value = @staticmethod def from_name(arg0: str) -> OpType: diff --git a/pytket/pytket/_tket/circuit_library.pyi b/pytket/pytket/_tket/circuit_library.pyi index 92d11c805b..66d86bf18a 100644 --- a/pytket/pytket/_tket/circuit_library.pyi +++ b/pytket/pytket/_tket/circuit_library.pyi @@ -2,7 +2,7 @@ from __future__ import annotations import pytket._tket.circuit import sympy import typing -__all__ = ['BRIDGE', 'BRIDGE_using_CX_0', 'BRIDGE_using_CX_1', 'C3X_normal_decomp', 'C4X_normal_decomp', 'CCX', 'CCX_modulo_phase_shift', 'CCX_normal_decomp', 'CH_using_CX', 'CRx_using_CX', 'CRx_using_TK2', 'CRy_using_CX', 'CRy_using_TK2', 'CRz_using_CX', 'CRz_using_TK2', 'CSWAP_using_CX', 'CSX_using_CX', 'CSXdg_using_CX', 'CS_using_CX', 'CSdg_using_CX', 'CU1_using_CX', 'CU1_using_TK2', 'CU3_using_CX', 'CV_using_CX', 'CVdg_using_CX', 'CX', 'CX_S_CX_reduced', 'CX_S_V_XC_reduced', 'CX_VS_CX_reduced', 'CX_V_CX_reduced', 'CX_V_S_XC_reduced', 'CX_XC_reduced', 'CX_using_ECR', 'CX_using_TK2', 'CX_using_XXPhase_0', 'CX_using_XXPhase_1', 'CX_using_ZZMax', 'CX_using_ZZPhase', 'CX_using_flipped_CX', 'CY_using_CX', 'CZ_using_CX', 'ECR_using_CX', 'ESWAP_using_CX', 'ESWAP_using_TK2', 'FSim_using_CX', 'FSim_using_TK2', 'H_CZ_H', 'ISWAP_using_CX', 'ISWAP_using_TK2', 'NPhasedX_using_PhasedX', 'PhasedISWAP_using_CX', 'PhasedISWAP_using_TK2', 'SWAP_using_CX_0', 'SWAP_using_CX_1', 'TK1_to_PhasedXRz', 'TK1_to_RzH', 'TK1_to_RzRx', 'TK1_to_RzSX', 'TK1_to_TK1', 'TK2_using_3xCX', 'TK2_using_CX', 'TK2_using_CX_and_swap', 'TK2_using_TK2_or_swap', 'TK2_using_ZZMax', 'TK2_using_ZZMax_and_swap', 'TK2_using_ZZPhase', 'TK2_using_ZZPhase_and_swap', 'TK2_using_normalised_TK2', 'X', 'X1_CX', 'XXPhase3_using_CX', 'XXPhase3_using_TK2', 'XXPhase_using_CX', 'XXPhase_using_TK2', 'YYPhase_using_CX', 'YYPhase_using_TK2', 'Z0_CX', 'ZZMax_using_CX', 'ZZPhase_using_CX', 'ZZPhase_using_TK2', 'approx_TK2_using_1xCX', 'approx_TK2_using_1xZZPhase', 'approx_TK2_using_2xCX', 'approx_TK2_using_2xZZPhase', 'ladder_down', 'ladder_down_2', 'ladder_up'] +__all__ = ['BRIDGE', 'BRIDGE_using_CX_0', 'BRIDGE_using_CX_1', 'C3X_normal_decomp', 'C4X_normal_decomp', 'CCX', 'CCX_modulo_phase_shift', 'CCX_normal_decomp', 'CH_using_CX', 'CRx_using_CX', 'CRx_using_TK2', 'CRy_using_CX', 'CRy_using_TK2', 'CRz_using_CX', 'CRz_using_TK2', 'CSWAP_using_CX', 'CSX_using_CX', 'CSXdg_using_CX', 'CS_using_CX', 'CSdg_using_CX', 'CU1_using_CX', 'CU1_using_TK2', 'CU3_using_CX', 'CV_using_CX', 'CVdg_using_CX', 'CX', 'CX_S_CX_reduced', 'CX_S_V_XC_reduced', 'CX_VS_CX_reduced', 'CX_V_CX_reduced', 'CX_V_S_XC_reduced', 'CX_XC_reduced', 'CX_using_AAMS', 'CX_using_ECR', 'CX_using_TK2', 'CX_using_XXPhase_0', 'CX_using_XXPhase_1', 'CX_using_ZZMax', 'CX_using_ZZPhase', 'CX_using_flipped_CX', 'CY_using_CX', 'CZ_using_CX', 'ECR_using_CX', 'ESWAP_using_CX', 'ESWAP_using_TK2', 'FSim_using_CX', 'FSim_using_TK2', 'H_CZ_H', 'ISWAP_using_CX', 'ISWAP_using_TK2', 'NPhasedX_using_PhasedX', 'PhasedISWAP_using_CX', 'PhasedISWAP_using_TK2', 'Rx_using_GPI', 'Ry_using_GPI', 'Rz_using_GPI', 'SWAP_using_CX_0', 'SWAP_using_CX_1', 'TK1_to_PhasedXRz', 'TK1_to_RzH', 'TK1_to_RzRx', 'TK1_to_RzSX', 'TK1_to_TK1', 'TK1_using_GPI', 'TK2_using_3xCX', 'TK2_using_AAMS', 'TK2_using_CX', 'TK2_using_CX_and_swap', 'TK2_using_TK2_or_swap', 'TK2_using_ZZMax', 'TK2_using_ZZMax_and_swap', 'TK2_using_ZZPhase', 'TK2_using_ZZPhase_and_swap', 'TK2_using_normalised_TK2', 'X', 'X1_CX', 'XXPhase3_using_CX', 'XXPhase3_using_TK2', 'XXPhase_using_AAMS', 'XXPhase_using_CX', 'XXPhase_using_TK2', 'YYPhase_using_AAMS', 'YYPhase_using_CX', 'YYPhase_using_TK2', 'Z0_CX', 'ZZMax_using_CX', 'ZZPhase_using_AAMS', 'ZZPhase_using_CX', 'ZZPhase_using_TK2', 'approx_TK2_using_1xCX', 'approx_TK2_using_1xZZPhase', 'approx_TK2_using_2xCX', 'approx_TK2_using_2xZZPhase', 'ladder_down', 'ladder_down_2', 'ladder_up'] def BRIDGE() -> pytket._tket.circuit.Circuit: """ Just a BRIDGE[0,1,2] gate @@ -131,6 +131,10 @@ def CX_XC_reduced() -> pytket._tket.circuit.Circuit: """ CX-reduced form of CX/XC """ +def CX_using_AAMS() -> pytket._tket.circuit.Circuit: + """ + Equivalent to CX, using AAMS, GPI and GPI2 gates + """ def CX_using_ECR() -> pytket._tket.circuit.Circuit: """ Equivalent to CX, using only ECR, Rx and U3 gates @@ -211,6 +215,18 @@ def PhasedISWAP_using_TK2(arg0: sympy.Expr | float, arg1: sympy.Expr | float) -> """ Equivalent to PhasedISWAP, using a TK2 and Rz gates """ +def Rx_using_GPI(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit: + """ + Equivalent to Rx, using GPI and GPI2 gates + """ +def Ry_using_GPI(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit: + """ + Equivalent to Ry, using GPI and GPI2 gates + """ +def Rz_using_GPI(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit: + """ + Equivalent to Rz, using GPI gates + """ def SWAP_using_CX_0() -> pytket._tket.circuit.Circuit: """ Equivalent to SWAP, using three CX, outer CX have control on qubit 0 @@ -239,12 +255,20 @@ def TK1_to_TK1(arg0: sympy.Expr | float, arg1: sympy.Expr | float, arg2: sympy.E """ A circuit of a single tk1 gate with given parameters """ +def TK1_using_GPI(arg0: sympy.Expr | float, arg1: sympy.Expr | float, arg2: sympy.Expr | float) -> pytket._tket.circuit.Circuit: + """ + Equivalent to TK1, using GPI and GPI2 gates + """ def TK2_using_3xCX(arg0: sympy.Expr | float, arg1: sympy.Expr | float, arg2: sympy.Expr | float) -> pytket._tket.circuit.Circuit: """ Given expressions α, β and γ, return circuit equivalent to TK2(α, β, γ) using 3 CX and single-qubit gates. Prefer using `_TK2_using_CX` unless you wish to explicitly use 3 CX or if α, β and γ are not normalised to the Weyl chamber. """ +def TK2_using_AAMS(arg0: sympy.Expr | float, arg1: sympy.Expr | float, arg2: sympy.Expr | float) -> pytket._tket.circuit.Circuit: + """ + Equivalent to TK2, using AAMS, GPI and GPI2 gates + """ def TK2_using_CX(arg0: sympy.Expr | float, arg1: sympy.Expr | float, arg2: sympy.Expr | float) -> pytket._tket.circuit.Circuit: """ Given expressions α, β and γ, return circuit equivalent to TK2(α, β, γ) using up to 3 CX and single-qubit gates. @@ -297,6 +321,10 @@ def XXPhase3_using_TK2(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit """ Equivalent to XXPhase3, using three TK2 gates """ +def XXPhase_using_AAMS(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit: + """ + Equivalent to XXPhase, using AAMS gates + """ def XXPhase_using_CX(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit: """ Equivalent to XXPhase, using CX and U3 gates @@ -305,6 +333,10 @@ def XXPhase_using_TK2(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit: """ Equivalent to XXPhase, using a TK2 gate """ +def YYPhase_using_AAMS(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit: + """ + Equivalent to YYPhase, using AAMS gates + """ def YYPhase_using_CX(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit: """ Equivalent to YYPhase, using two CX gates and one Ry, one Sdg and one S gate. @@ -321,6 +353,10 @@ def ZZMax_using_CX() -> pytket._tket.circuit.Circuit: """ Equivalent to ZZMax, using CX, Rz and U3 gates """ +def ZZPhase_using_AAMS(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit: + """ + Equivalent to ZZPhase, using AAMS, GPI and GPI2 gates + """ def ZZPhase_using_CX(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit: """ Equivalent to ZZPhase, using CX and Rz gates diff --git a/pytket/pytket/_tket/passes.pyi b/pytket/pytket/_tket/passes.pyi index 22bc51873e..e945877d50 100644 --- a/pytket/pytket/_tket/passes.pyi +++ b/pytket/pytket/_tket/passes.pyi @@ -9,7 +9,7 @@ import pytket._tket.transform import pytket._tket.unit_id import sympy import typing -__all__ = ['AASRouting', 'Audit', 'BasePass', 'CNotSynthType', 'CXMappingPass', 'CliffordPushThroughMeasures', 'CliffordResynthesis', 'CliffordSimp', 'CnXPairwiseDecomposition', 'CommuteThroughMultis', 'ComposePhasePolyBoxes', 'ContextSimp', 'CustomPass', 'CustomRoutingPass', 'DecomposeArbitrarilyControlledGates', 'DecomposeBoxes', 'DecomposeClassicalExp', 'DecomposeMultiQubitsCX', 'DecomposeSingleQubitsTK1', 'DecomposeSwapsToCXs', 'DecomposeSwapsToCircuit', 'DecomposeTK2', 'Default', 'DefaultMappingPass', 'DelayMeasures', 'EulerAngleReduction', 'FlattenRegisters', 'FlattenRelabelRegistersPass', 'FullMappingPass', 'FullPeepholeOptimise', 'GlobalisePhasedX', 'GuidedPauliSimp', 'HamPath', 'KAKDecomposition', 'NaivePlacementPass', 'NormaliseTK2', 'OptimisePhaseGadgets', 'PauliExponentials', 'PauliSimp', 'PauliSquash', 'PeepholeOptimise2Q', 'PlacementPass', 'RebaseCustom', 'RebaseTket', 'Rec', 'RemoveBarriers', 'RemoveDiscarded', 'RemoveImplicitQubitPermutation', 'RemoveRedundancies', 'RenameQubitsPass', 'RepeatPass', 'RepeatUntilSatisfiedPass', 'RepeatWithMetricPass', 'RoundAngles', 'RoutingPass', 'SWAP', 'SafetyMode', 'SequencePass', 'SimplifyInitial', 'SimplifyMeasured', 'SquashCustom', 'SquashRzPhasedX', 'SquashTK1', 'SynthesiseOQC', 'SynthesiseTK', 'SynthesiseTket', 'SynthesiseUMD', 'ThreeQubitSquash', 'ZXGraphlikeOptimisation', 'ZZPhaseToRz'] +__all__ = ['AASRouting', 'Audit', 'BasePass', 'CNotSynthType', 'CXMappingPass', 'CliffordPushThroughMeasures', 'CliffordResynthesis', 'CliffordSimp', 'CnXPairwiseDecomposition', 'CommuteThroughMultis', 'ComposePhasePolyBoxes', 'ContextSimp', 'CustomPass', 'CustomRoutingPass', 'DecomposeArbitrarilyControlledGates', 'DecomposeBoxes', 'DecomposeClassicalExp', 'DecomposeMultiQubitsCX', 'DecomposeSingleQubitsTK1', 'DecomposeSwapsToCXs', 'DecomposeSwapsToCircuit', 'DecomposeTK2', 'Default', 'DefaultMappingPass', 'DelayMeasures', 'EulerAngleReduction', 'FlattenRegisters', 'FlattenRelabelRegistersPass', 'FullMappingPass', 'FullPeepholeOptimise', 'GlobalisePhasedX', 'GreedyPauliSimp', 'GuidedPauliSimp', 'HamPath', 'KAKDecomposition', 'NaivePlacementPass', 'NormaliseTK2', 'OptimisePhaseGadgets', 'PauliExponentials', 'PauliSimp', 'PauliSquash', 'PeepholeOptimise2Q', 'PlacementPass', 'RebaseCustom', 'RebaseTket', 'Rec', 'RemoveBarriers', 'RemoveDiscarded', 'RemoveImplicitQubitPermutation', 'RemoveRedundancies', 'RenameQubitsPass', 'RepeatPass', 'RepeatUntilSatisfiedPass', 'RepeatWithMetricPass', 'RoundAngles', 'RoutingPass', 'SWAP', 'SafetyMode', 'SequencePass', 'SimplifyInitial', 'SimplifyMeasured', 'SquashCustom', 'SquashRzPhasedX', 'SquashTK1', 'SynthesiseOQC', 'SynthesiseTK', 'SynthesiseTket', 'SynthesiseUMD', 'ThreeQubitSquash', 'ZXGraphlikeOptimisation', 'ZZPhaseToRz'] class BasePass: """ Base class for passes. @@ -291,7 +291,7 @@ def CustomRoutingPass(arc: pytket._tket.architecture.Architecture, config: typin """ def DecomposeArbitrarilyControlledGates() -> BasePass: """ - Decomposes CCX, CnX, CnY, CnZ, and CnRy gates into CX and single-qubit gates. + Decomposes CCX, CnX, CnY, CnZ, CnRy, CnRz and CnRx gates into CX and single-qubit gates. """ def DecomposeBoxes(excluded_types: set[pytket._tket.circuit.OpType] = set(), excluded_opgroups: set[str] = set()) -> BasePass: """ @@ -404,6 +404,14 @@ def GlobalisePhasedX(squash: bool = True) -> BasePass: It is not recommended to use this pass with symbolic expressions, as in certain cases a blow-up in symbolic expression sizes may occur. """ +def GreedyPauliSimp(discount_rate: float = 0.7, depth_weight: float = 0.3) -> BasePass: + """ + Construct a pass that converts a circuit into a graph of Pauli gadgets to account for commutation and phase folding, and resynthesises them using a greedy algorithm adapted from arxiv.org/abs/2103.08602. The method for synthesising the final Clifford operator is adapted from arxiv.org/abs/2305.10966. + + :param discount_rate: Rate used to discount the cost impact from gadgets that are further away. Default to 0.7. + :param depth_weight: Degree of depth optimisation. Default to 0.3. + :return: a pass to perform the simplification + """ def GuidedPauliSimp(strat: pytket._tket.transform.PauliSynthStrat = pytket._tket.transform.PauliSynthStrat.Sets, cx_config: pytket._tket.circuit.CXConfigType = pytket._tket.circuit.CXConfigType.Snake) -> BasePass: """ Applies the ``PauliSimp`` optimisation pass to any region of the circuit contained within a :py:class:`CircBox`. This can be useful to focus the synthesis to target specific sets of commuting operations, rather than the default greedy approach. diff --git a/pytket/pytket/_tket/transform.pyi b/pytket/pytket/_tket/transform.pyi index a3b2e88c29..0795f97cbf 100644 --- a/pytket/pytket/_tket/transform.pyi +++ b/pytket/pytket/_tket/transform.pyi @@ -159,6 +159,15 @@ class Transform: It is not recommended to use this transformation with symbolic expressions, as in certain cases a blow-up in symbolic expression sizes may occur. """ @staticmethod + def GreedyPauliSimp(discount_rate: float = 0.7, depth_weight: float = 0.3) -> Transform: + """ + Convert a circuit into a graph of Pauli gadgets to account for commutation and phase folding, and resynthesises them using a greedy algorithm adapted from arxiv.org/abs/2103.08602. The method for synthesising the final Clifford operator is adapted from arxiv.org/abs/2305.10966. + + :param discount_rate: Rate used to discount the cost impact from gadgets that are further away. Default to 0.7. + :param depth_weight: Degree of depth optimisation. Default to 0.3. + :return: a pass to perform the simplification + """ + @staticmethod @typing.overload def KAKDecomposition(target_2qb_gate: pytket._tket.circuit.OpType = pytket._tket.circuit.OpType.CX, cx_fidelity: float = 1.0, allow_swaps: bool = True) -> Transform: """ @@ -238,6 +247,11 @@ class Transform: Replace all single-qubit unitary gates outside the set {Z, X, S, V} that are recognized as Clifford operations with an equivalent sequence of gates from that set. """ @staticmethod + def RebaseToIonQ() -> Transform: + """ + Rebase from any gate set into the gate set supported by IonQ (GPI, GPI2, AAMS). + """ + @staticmethod def RebaseToProjectQ() -> Transform: """ Rebase from any gate set into the gate set supported by ProjectQ (Rx, Ry, Rz, X, Y, Z, S, T, V, H, CX, CZ, CRz, SWAP). diff --git a/pytket/pytket/backends/status.py b/pytket/pytket/backends/status.py index 880bb95145..022f6387d6 100644 --- a/pytket/pytket/backends/status.py +++ b/pytket/pytket/backends/status.py @@ -26,6 +26,8 @@ class StatusEnum(Enum): QUEUED = "Circuit is queued." SUBMITTED = "Circuit has been submitted." RUNNING = "Circuit is running." + RETRYING = "Circuit is being retried." + CANCELLING = "Cancellation has been requested." CANCELLED = "Circuit has been cancelled." ERROR = "Circuit has errored. Check CircuitStatus.message for error message." diff --git a/pytket/pytket/circuit/display/static/head_imports.html b/pytket/pytket/circuit/display/static/head_imports.html index d560b50085..b72cacdb86 100644 --- a/pytket/pytket/circuit/display/static/head_imports.html +++ b/pytket/pytket/circuit/display/static/head_imports.html @@ -1,5 +1,5 @@ - - + + diff --git a/pytket/pytket/circuit/logic_exp.py b/pytket/pytket/circuit/logic_exp.py index e2b288a3e6..3c74473471 100644 --- a/pytket/pytket/circuit/logic_exp.py +++ b/pytket/pytket/circuit/logic_exp.py @@ -51,6 +51,8 @@ class BitWiseOp(Enum): EQ = "==" NEQ = "!=" NOT = "~" + ZERO = "0" + ONE = "1" class RegWiseOp(Enum): @@ -110,6 +112,10 @@ def factory(cls, op: Ops) -> Type["LogicExp"]: return BitEq if op == BitWiseOp.NEQ: return BitNeq + if op == BitWiseOp.ZERO: + return BitZero + if op == BitWiseOp.ONE: + return BitOne if op == RegWiseOp.AND: return RegAnd if op == RegWiseOp.OR: @@ -368,6 +374,13 @@ def __str__(self) -> str: return f"({self.op.value} {self.args[0]})" +class NullaryOp(LogicExp): + """Expression for operation on no arguments (i.e. constant).""" + + def __str__(self) -> str: + return f"({self.op.value})" + + class And(BinaryOp): @staticmethod def _const_eval(args: List[Constant]) -> Constant: @@ -426,6 +439,26 @@ def _const_eval(args: List[Constant]) -> Constant: return 1 - args[0] +class BitZero(NullaryOp, BitLogicExp): + def __init__(self) -> None: + self.op = BitWiseOp.ZERO + self.args = [] + + @staticmethod + def _const_eval(args: List[Constant]) -> Constant: + return 0 + + +class BitOne(NullaryOp, BitLogicExp): + def __init__(self) -> None: + self.op = BitWiseOp.ONE + self.args = [] + + @staticmethod + def _const_eval(args: List[Constant]) -> Constant: + return 1 + + class RegAnd(And, RegLogicExp): def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None: self.op = RegWiseOp.AND @@ -647,6 +680,12 @@ def create_bit_logic_exp(op: BitWiseOp, args: Sequence[BitArgType]) -> BitLogicE if op == BitWiseOp.NEQ: assert len(args) == 2 return BitNeq(args[0], args[1]) + if op == BitWiseOp.ZERO: + assert len(args) == 0 + return BitZero() + if op == BitWiseOp.ONE: + assert len(args) == 0 + return BitOne() def create_reg_logic_exp(op: RegWiseOp, args: Sequence[RegArgType]) -> RegLogicExp: diff --git a/pytket/pytket/circuit_library/__init__.py b/pytket/pytket/circuit_library/__init__.py index 114cfe5020..1cd3275f1e 100644 --- a/pytket/pytket/circuit_library/__init__.py +++ b/pytket/pytket/circuit_library/__init__.py @@ -27,6 +27,7 @@ CX_using_ZZPhase, CX_using_XXPhase_0, CX_using_XXPhase_1, + CX_using_AAMS, CX_VS_CX_reduced, CX_V_CX_reduced, CX_S_CX_reduced, @@ -100,4 +101,12 @@ TK1_to_RzH, TK1_to_RzSX, TK1_to_TK1, + Rx_using_GPI, + Ry_using_GPI, + Rz_using_GPI, + XXPhase_using_AAMS, + YYPhase_using_AAMS, + ZZPhase_using_AAMS, + TK1_using_GPI, + TK2_using_AAMS, ) diff --git a/pytket/pytket/passes/auto_rebase.py b/pytket/pytket/passes/auto_rebase.py index 4998963198..5cc5db4e4d 100644 --- a/pytket/pytket/passes/auto_rebase.py +++ b/pytket/pytket/passes/auto_rebase.py @@ -31,6 +31,7 @@ class NoAutoRebase(Exception): OpType.XXPhase: _library.CX_using_XXPhase_0, OpType.ECR: _library.CX_using_ECR, OpType.CZ: _library.H_CZ_H, + OpType.AAMS: _library.CX_using_AAMS, } @@ -43,6 +44,7 @@ def _TK2_using_TK2(a: Param, b: Param, c: Param) -> Circuit: OpType.ZZPhase: _library.TK2_using_ZZPhase, OpType.CX: _library.TK2_using_CX, OpType.ZZMax: _library.TK2_using_ZZMax, + OpType.AAMS: _library.TK2_using_AAMS, } _TK2_CIRCS_WIRE_SWAP: Dict[OpType, Callable[[Param, Param, Param], "Circuit"]] = { @@ -101,6 +103,7 @@ def get_tk2_decomposition( frozenset({OpType.Rz, OpType.SX}): _TK1_to_X_SX_Rz, frozenset({OpType.Rz, OpType.SX}): _library.TK1_to_RzSX, frozenset({OpType.U3}): _TK1_to_U, + frozenset({OpType.GPI, OpType.GPI2}): _library.TK1_using_GPI, } diff --git a/pytket/pytket/qasm/qasm.py b/pytket/pytket/qasm/qasm.py index 68847d5481..07965b7e4b 100644 --- a/pytket/pytket/qasm/qasm.py +++ b/pytket/pytket/qasm/qasm.py @@ -793,7 +793,7 @@ def assign(self, tree: List) -> Iterable[CommandDict]: else: raise QASMParseError(f"Unexpected expression in assignment {exp}", line) - def extern(self, tree: List[Any]) -> Type[Discard]: + def extern(self, tree: List[Any]) -> Any: # TODO parse extern defs return Discard @@ -899,7 +899,7 @@ def gdef(self, tree: List) -> None: opaq = gdef - def oqasm(self, tree: List) -> Type[Discard]: + def oqasm(self, tree: List) -> Any: return Discard def incl(self, tree: List[Token]) -> None: diff --git a/pytket/pytket/quipper/quipper.py b/pytket/pytket/quipper/quipper.py index 30543bd275..5c0d4d8328 100644 --- a/pytket/pytket/quipper/quipper.py +++ b/pytket/pytket/quipper/quipper.py @@ -183,6 +183,7 @@ class Subroutine_Control(Enum): ) Start = NamedTuple("Start", [("circuit", Program), ("subroutines", List[Subroutine])]) + # Transformer class QuipperTransformer(Transformer): def int(self, t: List) -> int: @@ -285,17 +286,17 @@ def cdiscard(self, t: List) -> CDiscard: def subroutine_call(self, t: List) -> SubroutineCall: repetitions = 1 - if isinstance(t[0], int): + if t[0] is not None: + assert isinstance(t[0], int) repetitions = t[0] - t.pop(0) return SubroutineCall( repetitions=repetitions, - name=t[0], - shape=t[1], - inverted=len(t[2].children) > 0, - inputs=t[3], - outputs=t[4], - control=t[5], + name=t[1], + shape=t[2], + inverted=len(t[3].children) > 0, + inputs=t[4], + outputs=t[5], + control=t[6], ) def comment(self, t: List) -> Comment: diff --git a/pytket/pytket/utils/symbolic.py b/pytket/pytket/utils/symbolic.py index 26b839fadb..a0d0926344 100644 --- a/pytket/pytket/utils/symbolic.py +++ b/pytket/pytket/utils/symbolic.py @@ -252,6 +252,48 @@ def symb_fsim(params: ParamsType) -> ImmutableMatrix: ) +def symb_gpi(params: ParamsType) -> ImmutableMatrix: + t = sympy.exp(I * sympy.pi * params[0]) + + return ImmutableMatrix( # type: ignore + [ + [0, 1 / t], + [t, 0], + ] + ) + + +def symb_gpi2(params: ParamsType) -> ImmutableMatrix: + t = sympy.exp(I * sympy.pi * params[0]) + c = 1 / sympy.sqrt(2) # type: ignore + + return c * ImmutableMatrix( # type: ignore + [ + [1, -I / t], + [-I * t, 1], + ] + ) + + +def symb_aams(params: ParamsType) -> ImmutableMatrix: + alpha, beta, gamma = params + c = sympy.cos(sympy.pi / 2 * alpha) + s = sympy.sin(sympy.pi / 2 * alpha) + s1 = -I * sympy.exp(I * sympy.pi * (-beta - gamma)) * s + s2 = -I * sympy.exp(I * sympy.pi * (-beta + gamma)) * s + s3 = -I * sympy.exp(I * sympy.pi * (beta - gamma)) * s + s4 = -I * sympy.exp(I * sympy.pi * (beta + gamma)) * s + + return ImmutableMatrix( # type: ignore + [ + [c, 0, 0, s1], + [0, c, s2, 0], + [0, s3, c, 0], + [s4, 0, 0, c], + ] + ) + + # end symbolic matrix definitions @@ -282,6 +324,9 @@ class SymGateRegister: OpType.PhasedX: symb_phasedx, OpType.ESWAP: symb_eswap, OpType.FSim: symb_fsim, + OpType.GPI: symb_gpi, + OpType.GPI2: symb_gpi2, + OpType.AAMS: symb_aams, } @classmethod diff --git a/pytket/setup.py b/pytket/setup.py index bd9ff5d8dd..243e3c43fe 100755 --- a/pytket/setup.py +++ b/pytket/setup.py @@ -177,7 +177,7 @@ def finalize_options(self): setup( name="pytket", author="TKET development team", - author_email="tket-support@cambridgequantum.com", + author_email="tket-support@quantinuum.com", python_requires=">=3.10", project_urls={ "Documentation": "https://tket.quantinuum.com/api-docs/index.html", @@ -192,7 +192,7 @@ def finalize_options(self): install_requires=[ "sympy ~=1.6", "numpy >=1.21.4, <2.0", - "lark-parser ~=0.7", + "lark ~=1.1", "scipy ~=1.13", "networkx >= 2.8.8", "graphviz ~= 0.14", diff --git a/pytket/tests/circuit_test.py b/pytket/tests/circuit_test.py index 19eb6157b9..614e34e083 100644 --- a/pytket/tests/circuit_test.py +++ b/pytket/tests/circuit_test.py @@ -141,6 +141,15 @@ def test_circuit_dagger() -> None: assert commands[1].op.get_matrix().all() == u.conj().transpose().all() +def test_circuit_dagger_transpose_with_barriers() -> None: + c = Circuit(2).S(0).add_barrier([0, 1]).CX(0, 1) + c_d = c.dagger() + assert c_d == Circuit(2).CX(0, 1).add_barrier([0, 1]).Sdg(0) + c = Circuit(2).Ry(0.3, 0).add_barrier([0, 1]).CX(0, 1) + c_t = c.transpose() + assert c_t == Circuit(2).CX(0, 1).add_barrier([0, 1]).Ry(-0.3, 0) + + # TKET-1365 bug def test_cnx_dagger() -> None: c = Circuit(2) @@ -1527,6 +1536,21 @@ def test_pickle_bit() -> None: assert b == pickle.loads(pickle.dumps(b)) +def test_cnrx_cnrz() -> None: + c1rx = Circuit(2) + c1rx.add_gate(OpType.CnRx, 0.3, [0, 1]) + crx = Circuit(2) + crx.add_gate(OpType.CRx, 0.3, [0, 1]) + + c1rz = Circuit(2) + c1rz.add_gate(OpType.CnRz, 0.3, [0, 1]) + crz = Circuit(2) + crz.add_gate(OpType.CRz, 0.3, [0, 1]) + + assert np.allclose(c1rz.get_unitary(), crz.get_unitary()) + assert np.allclose(c1rx.get_unitary(), crx.get_unitary()) + + if __name__ == "__main__": test_circuit_gen() test_symbolic_ops() @@ -1542,3 +1566,4 @@ def test_pickle_bit() -> None: test_multi_controlled_gates() test_counting_n_qubit_gates() test_pauliexp_pair_box_serialisation() + test_cnrx_cnrz() diff --git a/pytket/tests/classical_test.py b/pytket/tests/classical_test.py index 1c5cd4c81a..63bfad4cae 100644 --- a/pytket/tests/classical_test.py +++ b/pytket/tests/classical_test.py @@ -56,6 +56,7 @@ RegPow, RegWiseOp, UnaryOp, + NullaryOp, reg_eq, reg_geq, reg_gt, @@ -763,14 +764,16 @@ def primitive_bit_logic_exps( bits: SearchStrategy[Bit] = bits(), ) -> BitLogicExp: op = draw(ops) - args = [draw(bits)] + args = [] exp_type = LogicExp.factory(op) - if issubclass(exp_type, BinaryOp): - if issubclass(exp_type, PredicateExp): - const_compare = draw(binary_digits) - args.append(Bit(const_compare)) - else: - args.append(draw(bits)) + if not issubclass(exp_type, NullaryOp): + args.append(draw(bits)) + if issubclass(exp_type, BinaryOp): + if issubclass(exp_type, PredicateExp): + const_compare = draw(binary_digits) + args.append(Bit(const_compare)) + else: + args.append(draw(bits)) exp = create_bit_logic_exp(op, args) assert isinstance(exp, BitLogicExp) return exp @@ -798,6 +801,8 @@ def test_bit_exp(bit_exp: BitLogicExp, constants: Tuple[int, int]) -> None: BitWiseOp.NOT: operator.not_, BitWiseOp.EQ: operator.eq, BitWiseOp.NEQ: operator.ne, + BitWiseOp.ZERO: lambda: 0, + BitWiseOp.ONE: lambda: 1, } op_map = {key: overflow_wrapper(val, 2) for key, val in op_map.items()} eval_val = bit_exp.eval_vals() diff --git a/pytket/tests/passes_serialisation_test.py b/pytket/tests/passes_serialisation_test.py index 07b0cab816..e4c389c2ac 100644 --- a/pytket/tests/passes_serialisation_test.py +++ b/pytket/tests/passes_serialisation_test.py @@ -41,6 +41,7 @@ DefaultMappingPass, AASRouting, SquashCustom, + GreedyPauliSimp, ) from pytket.mapping import ( LexiLabellingMethod, @@ -289,6 +290,9 @@ def nonparam_predicate_dict(name: str) -> Dict[str, Any]: "RoundAngles": standard_pass_dict( {"name": "RoundAngles", "n": 6, "only_zeros": False} ), + "GreedyPauliSimp": standard_pass_dict( + {"name": "GreedyPauliSimp", "discount_rate": 0.4, "depth_weight": 0.5} + ), } # non-parametrized passes that satisfy pass.from_dict(d).to_dict()==d diff --git a/pytket/tests/placement_test.py b/pytket/tests/placement_test.py index 035087b44d..346d1861aa 100644 --- a/pytket/tests/placement_test.py +++ b/pytket/tests/placement_test.py @@ -191,6 +191,15 @@ def test_place_fully_connected() -> None: assert qbs[3].reg_name == "fcNode" assert qbs[4].reg_name == "fcNode" + fc5 = FullyConnected(5, "fcNodetest") + place_fully_connected(c, fc5) + qbs = c.qubits + assert qbs[0].reg_name == "fcNodetest" + assert qbs[1].reg_name == "fcNodetest" + assert qbs[2].reg_name == "fcNodetest" + assert qbs[3].reg_name == "fcNodetest" + assert qbs[4].reg_name == "fcNodetest" + def test_big_placement() -> None: # TKET-1275 diff --git a/pytket/tests/predicates_test.py b/pytket/tests/predicates_test.py index 2afc1d625b..8dc46ad3f0 100644 --- a/pytket/tests/predicates_test.py +++ b/pytket/tests/predicates_test.py @@ -74,6 +74,7 @@ CliffordSimp, SynthesiseOQC, ZXGraphlikeOptimisation, + GreedyPauliSimp, ) from pytket.predicates import ( GateSetPredicate, @@ -1047,6 +1048,20 @@ def test_clifford_push_through_measures() -> None: assert coms[7].op.type == OpType.CopyBits +def greedy_pauli_synth() -> None: + circ = Circuit(4, name="test") + rega = circ.add_q_register("a", 2) + regb = circ.add_q_register("b", 2) + d = circ.copy() + circ.Rz(0, rega[0]).H(regb[1]).CX(rega[0], rega[1]).Ry(0.3, rega[0]).S(regb[1]).CZ( + rega[0], regb[0] + ).SWAP(regb[1], rega[0]) + pss = GreedyPauliSimp(0.5, 0.5) + assert pss.apply(d) + assert np.allclose(circ.get_unitary(), d.get_unitary()) + assert d.name == "test" + + def test_SynthesiseOQC_deprecation(capfd: Any) -> None: logging.set_level(logging.level.warn) p = SynthesiseOQC() diff --git a/pytket/tests/qasm_test.py b/pytket/tests/qasm_test.py index 93e55912d1..e05c287374 100644 --- a/pytket/tests/qasm_test.py +++ b/pytket/tests/qasm_test.py @@ -37,6 +37,7 @@ CustomGate, ) from pytket.circuit.decompose_classical import DecomposeClassicalError +from pytket.circuit.logic_exp import BitWiseOp, create_bit_logic_exp from pytket.qasm import ( circuit_from_qasm, circuit_to_qasm, @@ -932,6 +933,28 @@ def test_conditional_nonstandard_gates() -> None: assert "if(c==1) zzmax q[0],q[1];" in qasm +def test_const_condition() -> None: + # https://github.com/CQCL/tket/issues/1383 + circ = Circuit(1, 1) + exp = create_bit_logic_exp(BitWiseOp.ONE, []) + circ.H(0, condition=exp) + circ.measure_all() + qasm = circuit_to_qasm_str(circ, header="hqslib1") + assert ( + qasm + == """OPENQASM 2.0; +include "hqslib1.inc"; + +qreg q[1]; +creg c[1]; +creg tk_SCRATCH_BIT[1]; +tk_SCRATCH_BIT[0] = (1); +if(tk_SCRATCH_BIT[0]==1) h q[0]; +measure q[0] -> c[0]; +""" + ) + + if __name__ == "__main__": test_qasm_correct() test_qasm_qubit() diff --git a/pytket/tests/transform_test.py b/pytket/tests/transform_test.py index 850b8fadd3..e6212c3f5a 100644 --- a/pytket/tests/transform_test.py +++ b/pytket/tests/transform_test.py @@ -1074,6 +1074,16 @@ def test_auto_rebase() -> None: _library.CX(), _library.TK1_to_TK1, ), + ( + {OpType.GPI, OpType.GPI2, OpType.AAMS}, + _library.CX_using_AAMS(), + _library.TK1_using_GPI, + ), + ( + {OpType.GPI, OpType.GPI2, OpType.AAMS}, + _library.TK2_using_AAMS, + _library.TK1_using_GPI, + ), ] circ = get_test_circuit() diff --git a/recipes/pybind11_json/all/conandata.yml b/recipes/pybind11_json/all/conandata.yml index 58e86b8427..bbb34dfcf9 100644 --- a/recipes/pybind11_json/all/conandata.yml +++ b/recipes/pybind11_json/all/conandata.yml @@ -1,4 +1,7 @@ sources: + "0.2.14": + url: "https://github.com/pybind/pybind11_json/archive/0.2.14.tar.gz" + sha256: "bc4ad7e308add59886a961c21f3ba431e43fe7faa2ef5bd9925c66d042d28cde" "0.2.13": url: "https://github.com/pybind/pybind11_json/archive/0.2.13.tar.gz" sha256: "6b12ddb4930a3135322890318fc15c4a69134f21120ea82163827c11411107a3" diff --git a/recipes/pybind11_json/config.yml b/recipes/pybind11_json/config.yml index d889e66f48..53c6e6ca1f 100644 --- a/recipes/pybind11_json/config.yml +++ b/recipes/pybind11_json/config.yml @@ -1,4 +1,6 @@ versions: + "0.2.14": + folder: all "0.2.13": folder: all "0.2.12": diff --git a/schemas/compiler_pass_v1.json b/schemas/compiler_pass_v1.json index 404e19f954..0720c6c157 100644 --- a/schemas/compiler_pass_v1.json +++ b/schemas/compiler_pass_v1.json @@ -163,7 +163,8 @@ "DecomposeTK2", "CnXPairwiseDecomposition", "RemoveImplicitQubitPermutation", - "RoundAngles" + "RoundAngles", + "GreedyPauliSimp" ], "description": "The name of the compiler pass. Matches the name of the pytket method used to generate it. List all the passes as enum." }, @@ -334,6 +335,14 @@ "type": "string" }, "description": "opgroups excluded in \"DecomposeBoxes\"" + }, + "discount_rate": { + "type": "number", + "definition": "parameter controlling cost discount in \"GreedyPauliSimp\"" + }, + "depth_weight": { + "type": "number", + "definition": "parameter controlling the degree of depth optimisation in \"GreedyPauliSimp\"" } }, "required": [ @@ -818,6 +827,22 @@ "maxProperties": 3 } }, + { + "if": { + "properties": { + "name": { + "const": "GreedyPauliSimp" + } + } + }, + "then": { + "required": [ + "discount_rate", + "depth_weight" + ], + "maxProperties": 3 + } + }, { "if": { "properties": { diff --git a/tket/CMakeLists.txt b/tket/CMakeLists.txt index 0185f4ece6..2d5a40a0d3 100644 --- a/tket/CMakeLists.txt +++ b/tket/CMakeLists.txt @@ -268,6 +268,7 @@ target_sources(tket src/Transformations/OptimisationPass.cpp src/Transformations/PhaseOptimisation.cpp src/Transformations/Decomposition.cpp + src/Transformations/GreedyPauliOptimisation.cpp src/Transformations/Replacement.cpp src/Transformations/MeasurePass.cpp src/Transformations/ContextualReduction.cpp @@ -409,6 +410,8 @@ target_sources(tket include/tket/Transformations/Combinator.hpp include/tket/Transformations/ContextualReduction.hpp include/tket/Transformations/Decomposition.hpp + include/tket/Transformations/GreedyPauliOptimisation.hpp + include/tket/Transformations/GreedyPauliOptimisationLookupTables.hpp include/tket/Transformations/MeasurePass.hpp include/tket/Transformations/OptimisationPass.hpp include/tket/Transformations/PauliOptimisation.hpp diff --git a/tket/conanfile.py b/tket/conanfile.py index cb0f27dcba..c53a41f49a 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "1.2.117" + version = "1.3.1" package_type = "library" license = "Apache 2" homepage = "https://github.com/CQCL/tket" @@ -111,17 +111,17 @@ def package_info(self): def requirements(self): # libraries installed from remote: # https://quantinuumsw.jfrog.io/artifactory/api/conan/tket1-libs - self.requires("boost/1.84.0", transitive_headers=True) + self.requires("boost/1.85.0", transitive_headers=True) self.requires("symengine/0.11.2", transitive_headers=True) self.requires("eigen/3.4.0", transitive_headers=True) self.requires("nlohmann_json/3.11.3", transitive_headers=True) self.requires("tklog/0.3.3@tket/stable") self.requires("tkassert/0.3.4@tket/stable", transitive_headers=True) self.requires("tkrng/0.3.3@tket/stable") - self.requires("tktokenswap/0.3.7@tket/stable") - self.requires("tkwsm/0.3.7@tket/stable") + self.requires("tktokenswap/0.3.8@tket/stable") + self.requires("tkwsm/0.3.8@tket/stable") if self.build_test(): - self.test_requires("catch2/3.5.4") + self.test_requires("catch2/3.6.0") if self.build_proptest(): self.test_requires("rapidcheck/cci.20230815") diff --git a/tket/include/tket/Characterisation/Cycles.hpp b/tket/include/tket/Characterisation/Cycles.hpp index e62533baec..4ceb70d544 100644 --- a/tket/include/tket/Characterisation/Cycles.hpp +++ b/tket/include/tket/Characterisation/Cycles.hpp @@ -90,7 +90,7 @@ struct CycleHistory { class CycleFinder { public: CycleFinder(const Circuit& _circ, const OpTypeSet& _cycle_types) - : circ(_circ), cycle_types_(_cycle_types){}; + : circ(_circ), cycle_types_(_cycle_types) {}; // Cycles are sub-circuits of circ where every gate has OpType in cycle_types_ // get_cycles() returns the minimum number of cycles such that every diff --git a/tket/include/tket/Circuit/CircPool.hpp b/tket/include/tket/Circuit/CircPool.hpp index 461e909f0f..f84346bf20 100644 --- a/tket/include/tket/Circuit/CircPool.hpp +++ b/tket/include/tket/Circuit/CircPool.hpp @@ -49,6 +49,9 @@ const Circuit &CX_using_XXPhase_0(); /** Equivalent to CX, using only XXPhase, Rx and Rz gates */ const Circuit &CX_using_XXPhase_1(); +/** Equivalent to CX, using only AAMS, GPI and GPI2 gates */ +const Circuit &CX_using_AAMS(); + /** * CX-reduced form of CX/V,S/CX * @@ -504,6 +507,10 @@ Circuit CnX_gray_decomp(unsigned n); Circuit CnRy_normal_decomp(const Op_ptr op, unsigned arity); +Circuit CnRx_normal_decomp(const Op_ptr op, unsigned arity); + +Circuit CnRz_normal_decomp(const Op_ptr op, unsigned arity); + /** * @brief Given a 2x2 numerical unitary matrix U and the number of control * qubits n return the decomposed CnU gate @@ -536,6 +543,30 @@ Circuit CnU_gray_code_decomp(unsigned n, const Gate_ptr &gate); Circuit CnSU2_linear_decomp( unsigned n, const Expr &alpha, const Expr &theta, const Expr &beta); +/** Equivalent to Rx, using GPI and GPI2 gates */ +Circuit Rx_using_GPI(const Expr &theta); + +/** Equivalent to Ry, using GPI and GPI2 gates */ +Circuit Ry_using_GPI(const Expr &theta); + +/** Equivalent to Rz, using GPI gates */ +Circuit Rz_using_GPI(const Expr &theta); + +/** Equivalent to XXPhase, using AAMS gates */ +Circuit XXPhase_using_AAMS(const Expr &theta); + +/** Equivalent to YYPhase, using AAMS gates */ +Circuit YYPhase_using_AAMS(const Expr &theta); + +/** Equivalent to ZZPhase, using AAMS, GPI and GPI2 gates */ +Circuit ZZPhase_using_AAMS(const Expr &theta); + +/** Equivalent to TK1, using GPI and GPI2 gates */ +Circuit TK1_using_GPI(const Expr &alpha, const Expr &beta, const Expr &gamma); + +/** Equivalent to TK2, using AAMS, GPI and GPI2 gates */ +Circuit TK2_using_AAMS(const Expr &alpha, const Expr &beta, const Expr &gamma); + } // namespace CircPool } // namespace tket diff --git a/tket/include/tket/Circuit/ClassicalExpBox.hpp b/tket/include/tket/Circuit/ClassicalExpBox.hpp index f4dcc7c839..d3cbc96309 100644 --- a/tket/include/tket/Circuit/ClassicalExpBox.hpp +++ b/tket/include/tket/Circuit/ClassicalExpBox.hpp @@ -81,7 +81,7 @@ class ClassicalExpBox : public ClassicalExpBoxBase { n_io_(other.n_io_), n_o_(other.n_o_), exp_(other.exp_), - sig_(other.sig_){}; + sig_(other.sig_) {}; ~ClassicalExpBox() override {} Op_ptr symbol_substitution( diff --git a/tket/include/tket/Gate/GateUnitaryMatrixImplementations.hpp b/tket/include/tket/Gate/GateUnitaryMatrixImplementations.hpp index e04e14998d..248599cf1e 100644 --- a/tket/include/tket/Gate/GateUnitaryMatrixImplementations.hpp +++ b/tket/include/tket/Gate/GateUnitaryMatrixImplementations.hpp @@ -117,6 +117,10 @@ struct GateUnitaryMatrixImplementations { // to have a sparse version. static Eigen::MatrixXcd CnRy(unsigned int number_of_qubits, double alpha); + static Eigen::MatrixXcd CnRx(unsigned int number_of_qubits, double alpha); + + static Eigen::MatrixXcd CnRz(unsigned int number_of_qubits, double alpha); + static Eigen::MatrixXcd CnX(unsigned int number_of_qubits); static Eigen::MatrixXcd CnZ(unsigned int number_of_qubits); diff --git a/tket/include/tket/Mapping/AASLabelling.hpp b/tket/include/tket/Mapping/AASLabelling.hpp index 23179ae9e4..27b88d6f65 100644 --- a/tket/include/tket/Mapping/AASLabelling.hpp +++ b/tket/include/tket/Mapping/AASLabelling.hpp @@ -25,7 +25,7 @@ class AASLabellingMethod : public RoutingMethod { * Checking and Routing methods redefined for dynamically assigning qubits to * some Architecture. */ - AASLabellingMethod(){}; + AASLabellingMethod() {}; /** * will place all the qubits of the given circuit that are not placed at the diff --git a/tket/include/tket/Mapping/LexiLabelling.hpp b/tket/include/tket/Mapping/LexiLabelling.hpp index bb57248e71..ef49e08f40 100644 --- a/tket/include/tket/Mapping/LexiLabelling.hpp +++ b/tket/include/tket/Mapping/LexiLabelling.hpp @@ -25,7 +25,7 @@ class LexiLabellingMethod : public RoutingMethod { * Checking and Routing methods redefined for dynamically assigning qubits to * some Architecture. */ - LexiLabellingMethod(){}; + LexiLabellingMethod() {}; /** * @param mapping_frontier Contains boundary of routed/unrouted circuit for diff --git a/tket/include/tket/Mapping/RoutingMethod.hpp b/tket/include/tket/Mapping/RoutingMethod.hpp index d9181eb774..365f81c05d 100644 --- a/tket/include/tket/Mapping/RoutingMethod.hpp +++ b/tket/include/tket/Mapping/RoutingMethod.hpp @@ -21,7 +21,7 @@ namespace tket { class RoutingMethod { public: - RoutingMethod(){}; + RoutingMethod() {}; virtual ~RoutingMethod() {} /** diff --git a/tket/include/tket/OpType/OpType.hpp b/tket/include/tket/OpType/OpType.hpp index 6be6ed96d5..e1b6c8fa5a 100644 --- a/tket/include/tket/OpType/OpType.hpp +++ b/tket/include/tket/OpType/OpType.hpp @@ -608,6 +608,20 @@ enum class OpType { */ CnRy, + /** + * Multiply-controlled \ref OpType::Rx + * + * The phase parameter is defined modulo \f$ 4 \f$. + */ + CnRx, + + /** + * Multiply-controlled \ref OpType::Rz + * + * The phase parameter is defined modulo \f$ 4 \f$. + */ + CnRz, + /** * Multiply-controlled \ref OpType::X */ diff --git a/tket/include/tket/Placement/Placement.hpp b/tket/include/tket/Placement/Placement.hpp index bc6d9f287a..fa918c57cf 100644 --- a/tket/include/tket/Placement/Placement.hpp +++ b/tket/include/tket/Placement/Placement.hpp @@ -27,7 +27,7 @@ class Placement { explicit Placement(const Architecture& _architecture); - Placement(){}; + Placement() {}; /** * Reassigns some UnitID in circ_ as UnitID in architecture_ @@ -90,7 +90,7 @@ class Placement { */ const Architecture& get_architecture_ref() { return architecture_; } - virtual ~Placement(){}; + virtual ~Placement() {}; static const std::string& unplaced_reg(); diff --git a/tket/include/tket/Predicates/CompilerPass.hpp b/tket/include/tket/Predicates/CompilerPass.hpp index 26ac7def6c..4b266b7d92 100644 --- a/tket/include/tket/Predicates/CompilerPass.hpp +++ b/tket/include/tket/Predicates/CompilerPass.hpp @@ -132,7 +132,7 @@ class BasePass { static Guarantee get_guarantee( const std::type_index& ti, const PassConditions& conditions); - virtual ~BasePass(){}; + virtual ~BasePass() {}; protected: BasePass(const PredicatePtrMap& precons, const PostConditions& postcons) diff --git a/tket/include/tket/Predicates/PassGenerators.hpp b/tket/include/tket/Predicates/PassGenerators.hpp index 55c17bd55c..6bd2d7a7c4 100644 --- a/tket/include/tket/Predicates/PassGenerators.hpp +++ b/tket/include/tket/Predicates/PassGenerators.hpp @@ -325,6 +325,15 @@ PassPtr gen_special_UCC_synthesis( Transforms::PauliSynthStrat strat = Transforms::PauliSynthStrat::Sets, CXConfigType cx_config = CXConfigType::Snake); +/** + * @brief Greedy synthesis for Pauli graphs. + * + * @param discount_rate + * @param depth_weight + * @return PassPtr + */ +PassPtr gen_greedy_pauli_simp(double discount_rate, double depth_weight); + /** * Generate a pass to simplify the circuit where it acts on known basis states. * diff --git a/tket/include/tket/Predicates/Predicates.hpp b/tket/include/tket/Predicates/Predicates.hpp index e03e1d0db8..cad531ed29 100644 --- a/tket/include/tket/Predicates/Predicates.hpp +++ b/tket/include/tket/Predicates/Predicates.hpp @@ -60,7 +60,7 @@ class Predicate { virtual bool implies(const Predicate& other) const = 0; virtual PredicatePtr meet(const Predicate& other) const = 0; virtual std::string to_string() const = 0; - virtual ~Predicate(){}; // satisfy compiler + virtual ~Predicate() {}; // satisfy compiler }; // all Predicate subclasses must inherit from `Predicate` diff --git a/tket/include/tket/Transformations/Decomposition.hpp b/tket/include/tket/Transformations/Decomposition.hpp index 91af43f824..ba44f8c172 100644 --- a/tket/include/tket/Transformations/Decomposition.hpp +++ b/tket/include/tket/Transformations/Decomposition.hpp @@ -241,7 +241,7 @@ Transform decomp_CCX(); Transform decomp_controlled_Rys(); // does not use ancillae -// Expects: CCX, CnX, CnY, CnZ, CnRy and any other gates +// Expects: CCX, CnX, CnY, CnZ, CnRy, CnRx, CnRz, and any other gates // returns CX and single-qubit gate + any previous gates Transform decomp_arbitrary_controlled_gates(); diff --git a/tket/include/tket/Transformations/GreedyPauliOptimisation.hpp b/tket/include/tket/Transformations/GreedyPauliOptimisation.hpp new file mode 100644 index 0000000000..a8c05934e9 --- /dev/null +++ b/tket/include/tket/Transformations/GreedyPauliOptimisation.hpp @@ -0,0 +1,216 @@ +// Copyright 2019-2024 Cambridge Quantum Computing +// +// 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. + +#pragma once + +#include "Transform.hpp" +#include "tket/Circuit/Circuit.hpp" + +namespace tket { + +namespace Transforms { + +namespace GreedyPauliSimp { + +/** + * @brief Types of 2-qubit entangled Clifford gates + * + */ +enum class TQEType : unsigned { + XX, + XY, + XZ, + YX, + YY, + YZ, + ZX, + ZY, + ZZ, +}; + +/** + * @brief Local Clifford + * + */ +enum class LocalCliffordType { + H, + S, + V, +}; + +/** + * @brief Type for 2-qubit entangled Clifford gates + * + */ +using TQE = std::tuple; + +/** + * @brief A Pauli exponential described by its commutation relations + * with the rows in a reference Clifford tableau. + * We store the commutation relations using an n-dimensional + * vector with entries in {0,1,2,3}, where + * 0: commute with ith Z row and ith X row + * 1: commute with ith Z row and anti-commute with ith X row + * 2: anti-commute with ith Z row and commute with ith X row + * 3: anti-commute with ith Z row and anti-commute with ith X row + * We call such vector a support vector + */ +class PauliExpNode { + public: + /** + * @brief Construct a new PauliExpNode object. + * + * @param support_vec the support vector + * @param theta the rotation angle in half-turns + */ + PauliExpNode(std::vector support_vec, Expr theta); + + /** + * @brief Number of TQEs required to reduce the weight to 1 + * + * @return unsigned + */ + unsigned tqe_cost() const { return tqe_cost_; } + + /** + * @brief Number of TQEs would required to reduce the weight to 1 + * after the given TQE is applied + * + * @return unsigned + */ + int tqe_cost_increase(const TQE& tqe) const; + + /** + * @brief Update the support vector with a TQE gate + * + * @param tqe + */ + void update(const TQE& tqe); + + Expr theta() const { return theta_; }; + + /** + * @brief Return all possible TQE gates that will reduce the tqe cost by 1 + * + * @return std::vector> + */ + std::vector reduction_tqes() const; + + /** + * @brief Return the index and value of the first support + * + * @return std::pair + */ + std::pair first_support() const; + + private: + std::vector support_vec_; + Expr theta_; + unsigned tqe_cost_; +}; + +/** + * @brief Each row of a Clifford tableau consists a pair of anti-commuting + * Pauli strings (p0,p1). Similar to the PauliExpNode, such pairs can be + * alternatively described by their commutation relations with the rows in a + * reference Clifford tableau. Let Xi and Zi be the ith X row and the ith Z row + * in a reference Tableau T, then the commutation relation between (p0, p1) and + * the ith row of T is defined by how p0, p1 commute with Xi and Zi. That's 4 + * bits of information. We store such information using an n-dimensional vector + * with entries in {0,1,2,...,15}. The 4 bits from the most significant to the + * least are: f(p0, Xi), f(p0,Zi), f(q,Xi), f(q,Zi) where f(p,q)==1 if p,q + * anti-commute and 0 otherwise + */ +class TableauRowNode { + public: + /** + * @brief Construct a new TableauRowNode object. + * + * @param support_vec the support vector + */ + TableauRowNode(std::vector support_vec); + + /** + * @brief Number of TQEs required to reduce the weight to 1 + * + * @return unsigned + */ + unsigned tqe_cost() const { return tqe_cost_; }; + + /** + * @brief Number of TQEs would required to reduce the weight to 1 + * after the given TQE is applied + * + * @return unsigned + */ + int tqe_cost_increase(const TQE& tqe) const; + + /** + * @brief Update the support vector with a TQE gate + * + * @param tqe + */ + void update(const TQE& tqe); + + /** + * @brief Return all possible TQE gates that will reduce the tqe cost + * + * @return std::vector> + */ + std::vector reduction_tqes() const; + + /** + * @brief Return the index and value of the first support + */ + std::pair first_support() const; + + private: + std::vector support_vec_; + unsigned n_weaks_; + unsigned n_strongs_; + unsigned tqe_cost_; +}; + +/** + * @brief The commutation relation between a TableauRowNode (p0,p1) and the ith + * row of the reference Tableau can be further classified as Strong, Weak or + * No-support. + */ +enum class SupportType : unsigned { + Strong, + Weak, + No, +}; + +/** + * @brief Given a circuit consists of PauliExpBoxes followed by clifford gates, + * and end-of-circuit measurements, implement the PauliExpBoxes and the final + * clifford subcircuit by applying Clifford gates and single qubit rotations in + * a greedy fashion. + * + * @param circ + * @param discount_rate + * @param depth_weight + * @return Circuit + */ +Circuit greedy_pauli_graph_synthesis( + const Circuit& circ, double discount_rate = 0.7, double depth_weight = 0.3); +} // namespace GreedyPauliSimp + +Transform greedy_pauli_optimisation( + double discount_rate = 0.7, double depth_weight = 0.3); + +} // namespace Transforms + +} // namespace tket diff --git a/tket/include/tket/Transformations/GreedyPauliOptimisationLookupTables.hpp b/tket/include/tket/Transformations/GreedyPauliOptimisationLookupTables.hpp new file mode 100644 index 0000000000..2445513636 --- /dev/null +++ b/tket/include/tket/Transformations/GreedyPauliOptimisationLookupTables.hpp @@ -0,0 +1,1569 @@ +// Copyright 2019-2024 Cambridge Quantum Computing +// +// 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. + +#pragma once + +#include "GreedyPauliOptimisation.hpp" + +namespace tket { + +namespace Transforms { + +namespace GreedyPauliSimp { + +struct hash_tuple { + size_t operator()(const std::tuple& t) const { + return static_cast(std::get<0>(t)) * 10000 + + (std::get<1>(t) + 1) * 100 + std::get<2>(t); + } +}; + +struct hash_pair { + size_t operator()(const std::pair& pair) const { + return pair.first * 100 + pair.second; + } +}; + +/** + * @brief These are pre-calculated based on some property of the 2x2 matrix + * (i.e. local support matrix) defined by f(p0,Xi), f(p0,Zi), f(q,Xi), f(q,Zi) + * arxiv.org/abs/2305.10966 eq.27 + */ +const static std::unordered_map FACTOR_WEAKNESS_MAP = { + {0, SupportType::No}, {1, SupportType::Weak}, + {2, SupportType::Weak}, {3, SupportType::Weak}, + {4, SupportType::Weak}, {5, SupportType::Weak}, + {6, SupportType::Strong}, {7, SupportType::Strong}, + {8, SupportType::Weak}, {9, SupportType::Strong}, + {10, SupportType::Weak}, {11, SupportType::Strong}, + {12, SupportType::Weak}, {13, SupportType::Strong}, + {14, SupportType::Strong}, {15, SupportType::Weak}}; + +/** + * @brief Given a strong support in a factor support vector, returns the local + * clifford gates that turn it into an identity (i.e. 9). + */ +const static std::unordered_map> + FACTOR_STRONG_TO_LOCALS = { + {9, {}}, + {6, {LocalCliffordType::H}}, + {11, {LocalCliffordType::S}}, + {13, {LocalCliffordType::V}}, + {14, {LocalCliffordType::S, LocalCliffordType::H}}, + {7, {LocalCliffordType::H, LocalCliffordType::S}}, +}; + +/** + * @brief Transform a pair of entries in a singlet support vector using a TQE + */ +const static std::unordered_map< + std::tuple, std::pair, + hash_tuple> + SINGLET_PAIR_TRANSFORMATION_MAP = { + {{TQEType::XX, 2, 2}, {2, 2}}, {{TQEType::XY, 2, 2}, {0, 2}}, + {{TQEType::XZ, 2, 2}, {0, 2}}, {{TQEType::YX, 2, 2}, {2, 0}}, + {{TQEType::YY, 2, 2}, {1, 1}}, {{TQEType::YZ, 2, 2}, {1, 3}}, + {{TQEType::ZX, 2, 2}, {2, 0}}, {{TQEType::ZY, 2, 2}, {3, 1}}, + {{TQEType::ZZ, 2, 2}, {3, 3}}, {{TQEType::XX, 3, 2}, {3, 0}}, + {{TQEType::XY, 3, 2}, {1, 1}}, {{TQEType::XZ, 3, 2}, {1, 3}}, + {{TQEType::YX, 3, 2}, {3, 2}}, {{TQEType::YY, 3, 2}, {0, 2}}, + {{TQEType::YZ, 3, 2}, {0, 2}}, {{TQEType::ZX, 3, 2}, {3, 0}}, + {{TQEType::ZY, 3, 2}, {2, 1}}, {{TQEType::ZZ, 3, 2}, {2, 3}}, + {{TQEType::XX, 1, 2}, {1, 0}}, {{TQEType::XY, 1, 2}, {3, 1}}, + {{TQEType::XZ, 1, 2}, {3, 3}}, {{TQEType::YX, 1, 2}, {1, 0}}, + {{TQEType::YY, 1, 2}, {2, 1}}, {{TQEType::YZ, 1, 2}, {2, 3}}, + {{TQEType::ZX, 1, 2}, {1, 2}}, {{TQEType::ZY, 1, 2}, {0, 2}}, + {{TQEType::ZZ, 1, 2}, {0, 2}}, {{TQEType::XX, 0, 2}, {0, 2}}, + {{TQEType::XY, 0, 2}, {2, 2}}, {{TQEType::XZ, 0, 2}, {2, 2}}, + {{TQEType::YX, 0, 2}, {0, 2}}, {{TQEType::YY, 0, 2}, {3, 2}}, + {{TQEType::YZ, 0, 2}, {3, 2}}, {{TQEType::ZX, 0, 2}, {0, 2}}, + {{TQEType::ZY, 0, 2}, {1, 2}}, {{TQEType::ZZ, 0, 2}, {1, 2}}, + {{TQEType::XX, 2, 3}, {0, 3}}, {{TQEType::XY, 2, 3}, {2, 3}}, + {{TQEType::XZ, 2, 3}, {0, 3}}, {{TQEType::YX, 2, 3}, {1, 1}}, + {{TQEType::YY, 2, 3}, {2, 0}}, {{TQEType::YZ, 2, 3}, {1, 2}}, + {{TQEType::ZX, 2, 3}, {3, 1}}, {{TQEType::ZY, 2, 3}, {2, 0}}, + {{TQEType::ZZ, 2, 3}, {3, 2}}, {{TQEType::XX, 3, 3}, {1, 1}}, + {{TQEType::XY, 3, 3}, {3, 0}}, {{TQEType::XZ, 3, 3}, {1, 2}}, + {{TQEType::YX, 3, 3}, {0, 3}}, {{TQEType::YY, 3, 3}, {3, 3}}, + {{TQEType::YZ, 3, 3}, {0, 3}}, {{TQEType::ZX, 3, 3}, {2, 1}}, + {{TQEType::ZY, 3, 3}, {3, 0}}, {{TQEType::ZZ, 3, 3}, {2, 2}}, + {{TQEType::XX, 1, 3}, {3, 1}}, {{TQEType::XY, 1, 3}, {1, 0}}, + {{TQEType::XZ, 1, 3}, {3, 2}}, {{TQEType::YX, 1, 3}, {2, 1}}, + {{TQEType::YY, 1, 3}, {1, 0}}, {{TQEType::YZ, 1, 3}, {2, 2}}, + {{TQEType::ZX, 1, 3}, {0, 3}}, {{TQEType::ZY, 1, 3}, {1, 3}}, + {{TQEType::ZZ, 1, 3}, {0, 3}}, {{TQEType::XX, 0, 3}, {2, 3}}, + {{TQEType::XY, 0, 3}, {0, 3}}, {{TQEType::XZ, 0, 3}, {2, 3}}, + {{TQEType::YX, 0, 3}, {3, 3}}, {{TQEType::YY, 0, 3}, {0, 3}}, + {{TQEType::YZ, 0, 3}, {3, 3}}, {{TQEType::ZX, 0, 3}, {1, 3}}, + {{TQEType::ZY, 0, 3}, {0, 3}}, {{TQEType::ZZ, 0, 3}, {1, 3}}, + {{TQEType::XX, 2, 1}, {0, 1}}, {{TQEType::XY, 2, 1}, {0, 1}}, + {{TQEType::XZ, 2, 1}, {2, 1}}, {{TQEType::YX, 2, 1}, {1, 3}}, + {{TQEType::YY, 2, 1}, {1, 2}}, {{TQEType::YZ, 2, 1}, {2, 0}}, + {{TQEType::ZX, 2, 1}, {3, 3}}, {{TQEType::ZY, 2, 1}, {3, 2}}, + {{TQEType::ZZ, 2, 1}, {2, 0}}, {{TQEType::XX, 3, 1}, {1, 3}}, + {{TQEType::XY, 3, 1}, {1, 2}}, {{TQEType::XZ, 3, 1}, {3, 0}}, + {{TQEType::YX, 3, 1}, {0, 1}}, {{TQEType::YY, 3, 1}, {0, 1}}, + {{TQEType::YZ, 3, 1}, {3, 1}}, {{TQEType::ZX, 3, 1}, {2, 3}}, + {{TQEType::ZY, 3, 1}, {2, 2}}, {{TQEType::ZZ, 3, 1}, {3, 0}}, + {{TQEType::XX, 1, 1}, {3, 3}}, {{TQEType::XY, 1, 1}, {3, 2}}, + {{TQEType::XZ, 1, 1}, {1, 0}}, {{TQEType::YX, 1, 1}, {2, 3}}, + {{TQEType::YY, 1, 1}, {2, 2}}, {{TQEType::YZ, 1, 1}, {1, 0}}, + {{TQEType::ZX, 1, 1}, {0, 1}}, {{TQEType::ZY, 1, 1}, {0, 1}}, + {{TQEType::ZZ, 1, 1}, {1, 1}}, {{TQEType::XX, 0, 1}, {2, 1}}, + {{TQEType::XY, 0, 1}, {2, 1}}, {{TQEType::XZ, 0, 1}, {0, 1}}, + {{TQEType::YX, 0, 1}, {3, 1}}, {{TQEType::YY, 0, 1}, {3, 1}}, + {{TQEType::YZ, 0, 1}, {0, 1}}, {{TQEType::ZX, 0, 1}, {1, 1}}, + {{TQEType::ZY, 0, 1}, {1, 1}}, {{TQEType::ZZ, 0, 1}, {0, 1}}, + {{TQEType::XX, 2, 0}, {2, 0}}, {{TQEType::XY, 2, 0}, {2, 0}}, + {{TQEType::XZ, 2, 0}, {2, 0}}, {{TQEType::YX, 2, 0}, {2, 2}}, + {{TQEType::YY, 2, 0}, {2, 3}}, {{TQEType::YZ, 2, 0}, {2, 1}}, + {{TQEType::ZX, 2, 0}, {2, 2}}, {{TQEType::ZY, 2, 0}, {2, 3}}, + {{TQEType::ZZ, 2, 0}, {2, 1}}, {{TQEType::XX, 3, 0}, {3, 2}}, + {{TQEType::XY, 3, 0}, {3, 3}}, {{TQEType::XZ, 3, 0}, {3, 1}}, + {{TQEType::YX, 3, 0}, {3, 0}}, {{TQEType::YY, 3, 0}, {3, 0}}, + {{TQEType::YZ, 3, 0}, {3, 0}}, {{TQEType::ZX, 3, 0}, {3, 2}}, + {{TQEType::ZY, 3, 0}, {3, 3}}, {{TQEType::ZZ, 3, 0}, {3, 1}}, + {{TQEType::XX, 1, 0}, {1, 2}}, {{TQEType::XY, 1, 0}, {1, 3}}, + {{TQEType::XZ, 1, 0}, {1, 1}}, {{TQEType::YX, 1, 0}, {1, 2}}, + {{TQEType::YY, 1, 0}, {1, 3}}, {{TQEType::YZ, 1, 0}, {1, 1}}, + {{TQEType::ZX, 1, 0}, {1, 0}}, {{TQEType::ZY, 1, 0}, {1, 0}}, + {{TQEType::ZZ, 1, 0}, {1, 0}}, {{TQEType::XX, 0, 0}, {0, 0}}, + {{TQEType::XY, 0, 0}, {0, 0}}, {{TQEType::XZ, 0, 0}, {0, 0}}, + {{TQEType::YX, 0, 0}, {0, 0}}, {{TQEType::YY, 0, 0}, {0, 0}}, + {{TQEType::YZ, 0, 0}, {0, 0}}, {{TQEType::ZX, 0, 0}, {0, 0}}, + {{TQEType::ZY, 0, 0}, {0, 0}}, {{TQEType::ZZ, 0, 0}, {0, 0}}}; + +/** + * @brief Maps a pair of non-zero entires in a singlet support vector + * to a set of 4 TQE gates that will reduce one of them to 0 + */ +const static std::unordered_map< + std::pair, std::vector, hash_pair> + SINGLET_PAIR_REDUCTION_TQES = { + {{2, 2}, {TQEType::XY, TQEType::XZ, TQEType::YX, TQEType::ZX}}, + {{3, 2}, {TQEType::XX, TQEType::YY, TQEType::YZ, TQEType::ZX}}, + {{1, 2}, {TQEType::XX, TQEType::YX, TQEType::ZY, TQEType::ZZ}}, + {{2, 3}, {TQEType::XX, TQEType::XZ, TQEType::YY, TQEType::ZY}}, + {{3, 3}, {TQEType::XY, TQEType::YX, TQEType::YZ, TQEType::ZY}}, + {{1, 3}, {TQEType::XY, TQEType::YY, TQEType::ZX, TQEType::ZZ}}, + {{2, 1}, {TQEType::XX, TQEType::XY, TQEType::YZ, TQEType::ZZ}}, + {{3, 1}, {TQEType::XZ, TQEType::YX, TQEType::YY, TQEType::ZZ}}, + {{1, 1}, {TQEType::XZ, TQEType::YZ, TQEType::ZX, TQEType::ZY}}}; + +/** + * @brief Transform a pair of entries in a factor support vector using a TQE + */ +const static std::unordered_map< + std::tuple, std::pair, + hash_tuple> + FACTOR_PAIR_TRANSFORMATION_MAP = { + {{TQEType::XX, 7, 5}, {7, 4}}, {{TQEType::XY, 7, 5}, {2, 6}}, + {{TQEType::XZ, 7, 5}, {2, 7}}, {{TQEType::YX, 7, 5}, {7, 1}}, + {{TQEType::YY, 7, 5}, {8, 9}}, {{TQEType::YZ, 7, 5}, {8, 13}}, + {{TQEType::ZX, 7, 5}, {7, 0}}, {{TQEType::ZY, 7, 5}, {13, 10}}, + {{TQEType::ZZ, 7, 5}, {13, 15}}, {{TQEType::XX, 6, 5}, {6, 4}}, + {{TQEType::XY, 6, 5}, {3, 6}}, {{TQEType::XZ, 6, 5}, {3, 7}}, + {{TQEType::YX, 6, 5}, {6, 0}}, {{TQEType::YY, 6, 5}, {9, 10}}, + {{TQEType::YZ, 6, 5}, {9, 15}}, {{TQEType::ZX, 6, 5}, {6, 1}}, + {{TQEType::ZY, 6, 5}, {12, 9}}, {{TQEType::ZZ, 6, 5}, {12, 13}}, + {{TQEType::XX, 5, 7}, {4, 7}}, {{TQEType::XY, 5, 7}, {1, 7}}, + {{TQEType::XZ, 5, 7}, {0, 7}}, {{TQEType::YX, 5, 7}, {6, 2}}, + {{TQEType::YY, 5, 7}, {9, 8}}, {{TQEType::YZ, 5, 7}, {10, 13}}, + {{TQEType::ZX, 5, 7}, {7, 2}}, {{TQEType::ZY, 5, 7}, {13, 8}}, + {{TQEType::ZZ, 5, 7}, {15, 13}}, {{TQEType::XX, 4, 7}, {5, 7}}, + {{TQEType::XY, 4, 7}, {0, 7}}, {{TQEType::XZ, 4, 7}, {1, 7}}, + {{TQEType::YX, 4, 7}, {7, 3}}, {{TQEType::YY, 4, 7}, {8, 11}}, + {{TQEType::YZ, 4, 7}, {11, 15}}, {{TQEType::ZX, 4, 7}, {6, 3}}, + {{TQEType::ZY, 4, 7}, {12, 11}}, {{TQEType::ZZ, 4, 7}, {14, 15}}, + {{TQEType::XX, 5, 6}, {4, 6}}, {{TQEType::XY, 5, 6}, {0, 6}}, + {{TQEType::XZ, 5, 6}, {1, 6}}, {{TQEType::YX, 5, 6}, {6, 3}}, + {{TQEType::YY, 5, 6}, {10, 9}}, {{TQEType::YZ, 5, 6}, {9, 12}}, + {{TQEType::ZX, 5, 6}, {7, 3}}, {{TQEType::ZY, 5, 6}, {15, 9}}, + {{TQEType::ZZ, 5, 6}, {13, 12}}, {{TQEType::XX, 4, 6}, {5, 6}}, + {{TQEType::XY, 4, 6}, {1, 6}}, {{TQEType::XZ, 4, 6}, {0, 6}}, + {{TQEType::YX, 4, 6}, {7, 2}}, {{TQEType::YY, 4, 6}, {11, 10}}, + {{TQEType::YZ, 4, 6}, {8, 14}}, {{TQEType::ZX, 4, 6}, {6, 2}}, + {{TQEType::ZY, 4, 6}, {14, 10}}, {{TQEType::ZZ, 4, 6}, {12, 14}}, + {{TQEType::XX, 7, 4}, {7, 5}}, {{TQEType::XY, 7, 4}, {3, 7}}, + {{TQEType::XZ, 7, 4}, {3, 6}}, {{TQEType::YX, 7, 4}, {7, 0}}, + {{TQEType::YY, 7, 4}, {11, 8}}, {{TQEType::YZ, 7, 4}, {11, 12}}, + {{TQEType::ZX, 7, 4}, {7, 1}}, {{TQEType::ZY, 7, 4}, {15, 11}}, + {{TQEType::ZZ, 7, 4}, {15, 14}}, {{TQEType::XX, 6, 4}, {6, 5}}, + {{TQEType::XY, 6, 4}, {2, 7}}, {{TQEType::XZ, 6, 4}, {2, 6}}, + {{TQEType::YX, 6, 4}, {6, 1}}, {{TQEType::YY, 6, 4}, {10, 11}}, + {{TQEType::YZ, 6, 4}, {10, 14}}, {{TQEType::ZX, 6, 4}, {6, 0}}, + {{TQEType::ZY, 6, 4}, {14, 8}}, {{TQEType::ZZ, 6, 4}, {14, 12}}, + {{TQEType::XX, 5, 5}, {5, 5}}, {{TQEType::XY, 5, 5}, {0, 5}}, + {{TQEType::XZ, 5, 5}, {0, 5}}, {{TQEType::YX, 5, 5}, {5, 0}}, + {{TQEType::YY, 5, 5}, {10, 10}}, {{TQEType::YZ, 5, 5}, {10, 15}}, + {{TQEType::ZX, 5, 5}, {5, 0}}, {{TQEType::ZY, 5, 5}, {15, 10}}, + {{TQEType::ZZ, 5, 5}, {15, 15}}, {{TQEType::XX, 4, 5}, {4, 5}}, + {{TQEType::XY, 4, 5}, {1, 5}}, {{TQEType::XZ, 4, 5}, {1, 5}}, + {{TQEType::YX, 4, 5}, {4, 1}}, {{TQEType::YY, 4, 5}, {11, 9}}, + {{TQEType::YZ, 4, 5}, {11, 13}}, {{TQEType::ZX, 4, 5}, {4, 1}}, + {{TQEType::ZY, 4, 5}, {14, 9}}, {{TQEType::ZZ, 4, 5}, {14, 13}}, + {{TQEType::XX, 7, 7}, {6, 6}}, {{TQEType::XY, 7, 7}, {3, 4}}, + {{TQEType::XZ, 7, 7}, {2, 5}}, {{TQEType::YX, 7, 7}, {4, 3}}, + {{TQEType::YY, 7, 7}, {11, 11}}, {{TQEType::YZ, 7, 7}, {8, 15}}, + {{TQEType::ZX, 7, 7}, {5, 2}}, {{TQEType::ZY, 7, 7}, {15, 8}}, + {{TQEType::ZZ, 7, 7}, {13, 13}}, {{TQEType::XX, 6, 7}, {7, 6}}, + {{TQEType::XY, 6, 7}, {2, 4}}, {{TQEType::XZ, 6, 7}, {3, 5}}, + {{TQEType::YX, 6, 7}, {5, 2}}, {{TQEType::YY, 6, 7}, {10, 8}}, + {{TQEType::YZ, 6, 7}, {9, 13}}, {{TQEType::ZX, 6, 7}, {4, 3}}, + {{TQEType::ZY, 6, 7}, {14, 11}}, {{TQEType::ZZ, 6, 7}, {12, 15}}, + {{TQEType::XX, 7, 6}, {6, 7}}, {{TQEType::XY, 7, 6}, {2, 5}}, + {{TQEType::XZ, 7, 6}, {3, 4}}, {{TQEType::YX, 7, 6}, {4, 2}}, + {{TQEType::YY, 7, 6}, {8, 10}}, {{TQEType::YZ, 7, 6}, {11, 14}}, + {{TQEType::ZX, 7, 6}, {5, 3}}, {{TQEType::ZY, 7, 6}, {13, 9}}, + {{TQEType::ZZ, 7, 6}, {15, 12}}, {{TQEType::XX, 6, 6}, {7, 7}}, + {{TQEType::XY, 6, 6}, {3, 5}}, {{TQEType::XZ, 6, 6}, {2, 4}}, + {{TQEType::YX, 6, 6}, {5, 3}}, {{TQEType::YY, 6, 6}, {9, 9}}, + {{TQEType::YZ, 6, 6}, {10, 12}}, {{TQEType::ZX, 6, 6}, {4, 2}}, + {{TQEType::ZY, 6, 6}, {12, 10}}, {{TQEType::ZZ, 6, 6}, {14, 14}}, + {{TQEType::XX, 5, 4}, {5, 4}}, {{TQEType::XY, 5, 4}, {1, 4}}, + {{TQEType::XZ, 5, 4}, {1, 4}}, {{TQEType::YX, 5, 4}, {5, 1}}, + {{TQEType::YY, 5, 4}, {9, 11}}, {{TQEType::YZ, 5, 4}, {9, 14}}, + {{TQEType::ZX, 5, 4}, {5, 1}}, {{TQEType::ZY, 5, 4}, {13, 11}}, + {{TQEType::ZZ, 5, 4}, {13, 14}}, {{TQEType::XX, 4, 4}, {4, 4}}, + {{TQEType::XY, 4, 4}, {0, 4}}, {{TQEType::XZ, 4, 4}, {0, 4}}, + {{TQEType::YX, 4, 4}, {4, 0}}, {{TQEType::YY, 4, 4}, {8, 8}}, + {{TQEType::YZ, 4, 4}, {8, 12}}, {{TQEType::ZX, 4, 4}, {4, 0}}, + {{TQEType::ZY, 4, 4}, {12, 8}}, {{TQEType::ZZ, 4, 4}, {12, 12}}, + {{TQEType::XX, 13, 5}, {13, 1}}, {{TQEType::XY, 13, 5}, {8, 9}}, + {{TQEType::XZ, 13, 5}, {8, 13}}, {{TQEType::YX, 13, 5}, {13, 4}}, + {{TQEType::YY, 13, 5}, {2, 6}}, {{TQEType::YZ, 13, 5}, {2, 7}}, + {{TQEType::ZX, 13, 5}, {13, 0}}, {{TQEType::ZY, 13, 5}, {7, 10}}, + {{TQEType::ZZ, 13, 5}, {7, 15}}, {{TQEType::XX, 14, 5}, {14, 0}}, + {{TQEType::XY, 14, 5}, {11, 10}}, {{TQEType::XZ, 14, 5}, {11, 15}}, + {{TQEType::YX, 14, 5}, {14, 4}}, {{TQEType::YY, 14, 5}, {1, 6}}, + {{TQEType::YZ, 14, 5}, {1, 7}}, {{TQEType::ZX, 14, 5}, {14, 1}}, + {{TQEType::ZY, 14, 5}, {4, 9}}, {{TQEType::ZZ, 14, 5}, {4, 13}}, + {{TQEType::XX, 15, 7}, {14, 2}}, {{TQEType::XY, 15, 7}, {11, 8}}, + {{TQEType::XZ, 15, 7}, {10, 13}}, {{TQEType::YX, 15, 7}, {12, 7}}, + {{TQEType::YY, 15, 7}, {3, 7}}, {{TQEType::YZ, 15, 7}, {0, 7}}, + {{TQEType::ZX, 15, 7}, {13, 2}}, {{TQEType::ZY, 15, 7}, {7, 8}}, + {{TQEType::ZZ, 15, 7}, {5, 13}}, {{TQEType::XX, 12, 7}, {13, 3}}, + {{TQEType::XY, 12, 7}, {8, 11}}, {{TQEType::XZ, 12, 7}, {9, 15}}, + {{TQEType::YX, 12, 7}, {15, 7}}, {{TQEType::YY, 12, 7}, {0, 7}}, + {{TQEType::YZ, 12, 7}, {3, 7}}, {{TQEType::ZX, 12, 7}, {14, 3}}, + {{TQEType::ZY, 12, 7}, {4, 11}}, {{TQEType::ZZ, 12, 7}, {6, 15}}, + {{TQEType::XX, 15, 6}, {14, 3}}, {{TQEType::XY, 15, 6}, {10, 9}}, + {{TQEType::XZ, 15, 6}, {11, 12}}, {{TQEType::YX, 15, 6}, {12, 6}}, + {{TQEType::YY, 15, 6}, {0, 6}}, {{TQEType::YZ, 15, 6}, {3, 6}}, + {{TQEType::ZX, 15, 6}, {13, 3}}, {{TQEType::ZY, 15, 6}, {5, 9}}, + {{TQEType::ZZ, 15, 6}, {7, 12}}, {{TQEType::XX, 12, 6}, {13, 2}}, + {{TQEType::XY, 12, 6}, {9, 10}}, {{TQEType::XZ, 12, 6}, {8, 14}}, + {{TQEType::YX, 12, 6}, {15, 6}}, {{TQEType::YY, 12, 6}, {3, 6}}, + {{TQEType::YZ, 12, 6}, {0, 6}}, {{TQEType::ZX, 12, 6}, {14, 2}}, + {{TQEType::ZY, 12, 6}, {6, 10}}, {{TQEType::ZZ, 12, 6}, {4, 14}}, + {{TQEType::XX, 13, 4}, {13, 0}}, {{TQEType::XY, 13, 4}, {9, 8}}, + {{TQEType::XZ, 13, 4}, {9, 12}}, {{TQEType::YX, 13, 4}, {13, 5}}, + {{TQEType::YY, 13, 4}, {1, 7}}, {{TQEType::YZ, 13, 4}, {1, 6}}, + {{TQEType::ZX, 13, 4}, {13, 1}}, {{TQEType::ZY, 13, 4}, {5, 11}}, + {{TQEType::ZZ, 13, 4}, {5, 14}}, {{TQEType::XX, 14, 4}, {14, 1}}, + {{TQEType::XY, 14, 4}, {10, 11}}, {{TQEType::XZ, 14, 4}, {10, 14}}, + {{TQEType::YX, 14, 4}, {14, 5}}, {{TQEType::YY, 14, 4}, {2, 7}}, + {{TQEType::YZ, 14, 4}, {2, 6}}, {{TQEType::ZX, 14, 4}, {14, 0}}, + {{TQEType::ZY, 14, 4}, {6, 8}}, {{TQEType::ZZ, 14, 4}, {6, 12}}, + {{TQEType::XX, 15, 5}, {15, 0}}, {{TQEType::XY, 15, 5}, {10, 10}}, + {{TQEType::XZ, 15, 5}, {10, 15}}, {{TQEType::YX, 15, 5}, {15, 5}}, + {{TQEType::YY, 15, 5}, {0, 5}}, {{TQEType::YZ, 15, 5}, {0, 5}}, + {{TQEType::ZX, 15, 5}, {15, 0}}, {{TQEType::ZY, 15, 5}, {5, 10}}, + {{TQEType::ZZ, 15, 5}, {5, 15}}, {{TQEType::XX, 12, 5}, {12, 1}}, + {{TQEType::XY, 12, 5}, {9, 9}}, {{TQEType::XZ, 12, 5}, {9, 13}}, + {{TQEType::YX, 12, 5}, {12, 5}}, {{TQEType::YY, 12, 5}, {3, 5}}, + {{TQEType::YZ, 12, 5}, {3, 5}}, {{TQEType::ZX, 12, 5}, {12, 1}}, + {{TQEType::ZY, 12, 5}, {6, 9}}, {{TQEType::ZZ, 12, 5}, {6, 13}}, + {{TQEType::XX, 13, 7}, {12, 3}}, {{TQEType::XY, 13, 7}, {9, 11}}, + {{TQEType::XZ, 13, 7}, {8, 15}}, {{TQEType::YX, 13, 7}, {14, 6}}, + {{TQEType::YY, 13, 7}, {1, 4}}, {{TQEType::YZ, 13, 7}, {2, 5}}, + {{TQEType::ZX, 13, 7}, {15, 2}}, {{TQEType::ZY, 13, 7}, {5, 8}}, + {{TQEType::ZZ, 13, 7}, {7, 13}}, {{TQEType::XX, 14, 7}, {15, 2}}, + {{TQEType::XY, 14, 7}, {10, 8}}, {{TQEType::XZ, 14, 7}, {11, 13}}, + {{TQEType::YX, 14, 7}, {13, 6}}, {{TQEType::YY, 14, 7}, {2, 4}}, + {{TQEType::YZ, 14, 7}, {1, 5}}, {{TQEType::ZX, 14, 7}, {12, 3}}, + {{TQEType::ZY, 14, 7}, {6, 11}}, {{TQEType::ZZ, 14, 7}, {4, 15}}, + {{TQEType::XX, 13, 6}, {12, 2}}, {{TQEType::XY, 13, 6}, {8, 10}}, + {{TQEType::XZ, 13, 6}, {9, 14}}, {{TQEType::YX, 13, 6}, {14, 7}}, + {{TQEType::YY, 13, 6}, {2, 5}}, {{TQEType::YZ, 13, 6}, {1, 4}}, + {{TQEType::ZX, 13, 6}, {15, 3}}, {{TQEType::ZY, 13, 6}, {7, 9}}, + {{TQEType::ZZ, 13, 6}, {5, 12}}, {{TQEType::XX, 14, 6}, {15, 3}}, + {{TQEType::XY, 14, 6}, {11, 9}}, {{TQEType::XZ, 14, 6}, {10, 12}}, + {{TQEType::YX, 14, 6}, {13, 7}}, {{TQEType::YY, 14, 6}, {1, 5}}, + {{TQEType::YZ, 14, 6}, {2, 4}}, {{TQEType::ZX, 14, 6}, {12, 2}}, + {{TQEType::ZY, 14, 6}, {4, 10}}, {{TQEType::ZZ, 14, 6}, {6, 14}}, + {{TQEType::XX, 15, 4}, {15, 1}}, {{TQEType::XY, 15, 4}, {11, 11}}, + {{TQEType::XZ, 15, 4}, {11, 14}}, {{TQEType::YX, 15, 4}, {15, 4}}, + {{TQEType::YY, 15, 4}, {3, 4}}, {{TQEType::YZ, 15, 4}, {3, 4}}, + {{TQEType::ZX, 15, 4}, {15, 1}}, {{TQEType::ZY, 15, 4}, {7, 11}}, + {{TQEType::ZZ, 15, 4}, {7, 14}}, {{TQEType::XX, 12, 4}, {12, 0}}, + {{TQEType::XY, 12, 4}, {8, 8}}, {{TQEType::XZ, 12, 4}, {8, 12}}, + {{TQEType::YX, 12, 4}, {12, 4}}, {{TQEType::YY, 12, 4}, {0, 4}}, + {{TQEType::YZ, 12, 4}, {0, 4}}, {{TQEType::ZX, 12, 4}, {12, 0}}, + {{TQEType::ZY, 12, 4}, {4, 8}}, {{TQEType::ZZ, 12, 4}, {4, 12}}, + {{TQEType::XX, 9, 5}, {9, 1}}, {{TQEType::XY, 9, 5}, {12, 9}}, + {{TQEType::XZ, 9, 5}, {12, 13}}, {{TQEType::YX, 9, 5}, {9, 0}}, + {{TQEType::YY, 9, 5}, {6, 10}}, {{TQEType::YZ, 9, 5}, {6, 15}}, + {{TQEType::ZX, 9, 5}, {9, 4}}, {{TQEType::ZY, 9, 5}, {3, 6}}, + {{TQEType::ZZ, 9, 5}, {3, 7}}, {{TQEType::XX, 11, 5}, {11, 0}}, + {{TQEType::XY, 11, 5}, {14, 10}}, {{TQEType::XZ, 11, 5}, {14, 15}}, + {{TQEType::YX, 11, 5}, {11, 1}}, {{TQEType::YY, 11, 5}, {4, 9}}, + {{TQEType::YZ, 11, 5}, {4, 13}}, {{TQEType::ZX, 11, 5}, {11, 4}}, + {{TQEType::ZY, 11, 5}, {1, 6}}, {{TQEType::ZZ, 11, 5}, {1, 7}}, + {{TQEType::XX, 10, 7}, {11, 2}}, {{TQEType::XY, 10, 7}, {14, 8}}, + {{TQEType::XZ, 10, 7}, {15, 13}}, {{TQEType::YX, 10, 7}, {9, 2}}, + {{TQEType::YY, 10, 7}, {6, 8}}, {{TQEType::YZ, 10, 7}, {5, 13}}, + {{TQEType::ZX, 10, 7}, {8, 7}}, {{TQEType::ZY, 10, 7}, {2, 7}}, + {{TQEType::ZZ, 10, 7}, {0, 7}}, {{TQEType::XX, 8, 7}, {9, 3}}, + {{TQEType::XY, 8, 7}, {12, 11}}, {{TQEType::XZ, 8, 7}, {13, 15}}, + {{TQEType::YX, 8, 7}, {11, 3}}, {{TQEType::YY, 8, 7}, {4, 11}}, + {{TQEType::YZ, 8, 7}, {7, 15}}, {{TQEType::ZX, 8, 7}, {10, 7}}, + {{TQEType::ZY, 8, 7}, {0, 7}}, {{TQEType::ZZ, 8, 7}, {2, 7}}, + {{TQEType::XX, 10, 6}, {11, 3}}, {{TQEType::XY, 10, 6}, {15, 9}}, + {{TQEType::XZ, 10, 6}, {14, 12}}, {{TQEType::YX, 10, 6}, {9, 3}}, + {{TQEType::YY, 10, 6}, {5, 9}}, {{TQEType::YZ, 10, 6}, {6, 12}}, + {{TQEType::ZX, 10, 6}, {8, 6}}, {{TQEType::ZY, 10, 6}, {0, 6}}, + {{TQEType::ZZ, 10, 6}, {2, 6}}, {{TQEType::XX, 8, 6}, {9, 2}}, + {{TQEType::XY, 8, 6}, {13, 10}}, {{TQEType::XZ, 8, 6}, {12, 14}}, + {{TQEType::YX, 8, 6}, {11, 2}}, {{TQEType::YY, 8, 6}, {7, 10}}, + {{TQEType::YZ, 8, 6}, {4, 14}}, {{TQEType::ZX, 8, 6}, {10, 6}}, + {{TQEType::ZY, 8, 6}, {2, 6}}, {{TQEType::ZZ, 8, 6}, {0, 6}}, + {{TQEType::XX, 9, 4}, {9, 0}}, {{TQEType::XY, 9, 4}, {13, 8}}, + {{TQEType::XZ, 9, 4}, {13, 12}}, {{TQEType::YX, 9, 4}, {9, 1}}, + {{TQEType::YY, 9, 4}, {5, 11}}, {{TQEType::YZ, 9, 4}, {5, 14}}, + {{TQEType::ZX, 9, 4}, {9, 5}}, {{TQEType::ZY, 9, 4}, {1, 7}}, + {{TQEType::ZZ, 9, 4}, {1, 6}}, {{TQEType::XX, 11, 4}, {11, 1}}, + {{TQEType::XY, 11, 4}, {15, 11}}, {{TQEType::XZ, 11, 4}, {15, 14}}, + {{TQEType::YX, 11, 4}, {11, 0}}, {{TQEType::YY, 11, 4}, {7, 8}}, + {{TQEType::YZ, 11, 4}, {7, 12}}, {{TQEType::ZX, 11, 4}, {11, 5}}, + {{TQEType::ZY, 11, 4}, {3, 7}}, {{TQEType::ZZ, 11, 4}, {3, 6}}, + {{TQEType::XX, 10, 5}, {10, 0}}, {{TQEType::XY, 10, 5}, {15, 10}}, + {{TQEType::XZ, 10, 5}, {15, 15}}, {{TQEType::YX, 10, 5}, {10, 0}}, + {{TQEType::YY, 10, 5}, {5, 10}}, {{TQEType::YZ, 10, 5}, {5, 15}}, + {{TQEType::ZX, 10, 5}, {10, 5}}, {{TQEType::ZY, 10, 5}, {0, 5}}, + {{TQEType::ZZ, 10, 5}, {0, 5}}, {{TQEType::XX, 8, 5}, {8, 1}}, + {{TQEType::XY, 8, 5}, {13, 9}}, {{TQEType::XZ, 8, 5}, {13, 13}}, + {{TQEType::YX, 8, 5}, {8, 1}}, {{TQEType::YY, 8, 5}, {7, 9}}, + {{TQEType::YZ, 8, 5}, {7, 13}}, {{TQEType::ZX, 8, 5}, {8, 5}}, + {{TQEType::ZY, 8, 5}, {2, 5}}, {{TQEType::ZZ, 8, 5}, {2, 5}}, + {{TQEType::XX, 9, 7}, {8, 3}}, {{TQEType::XY, 9, 7}, {13, 11}}, + {{TQEType::XZ, 9, 7}, {12, 15}}, {{TQEType::YX, 9, 7}, {10, 2}}, + {{TQEType::YY, 9, 7}, {5, 8}}, {{TQEType::YZ, 9, 7}, {6, 13}}, + {{TQEType::ZX, 9, 7}, {11, 6}}, {{TQEType::ZY, 9, 7}, {1, 4}}, + {{TQEType::ZZ, 9, 7}, {3, 5}}, {{TQEType::XX, 11, 7}, {10, 2}}, + {{TQEType::XY, 11, 7}, {15, 8}}, {{TQEType::XZ, 11, 7}, {14, 13}}, + {{TQEType::YX, 11, 7}, {8, 3}}, {{TQEType::YY, 11, 7}, {7, 11}}, + {{TQEType::YZ, 11, 7}, {4, 15}}, {{TQEType::ZX, 11, 7}, {9, 6}}, + {{TQEType::ZY, 11, 7}, {3, 4}}, {{TQEType::ZZ, 11, 7}, {1, 5}}, + {{TQEType::XX, 9, 6}, {8, 2}}, {{TQEType::XY, 9, 6}, {12, 10}}, + {{TQEType::XZ, 9, 6}, {13, 14}}, {{TQEType::YX, 9, 6}, {10, 3}}, + {{TQEType::YY, 9, 6}, {6, 9}}, {{TQEType::YZ, 9, 6}, {5, 12}}, + {{TQEType::ZX, 9, 6}, {11, 7}}, {{TQEType::ZY, 9, 6}, {3, 5}}, + {{TQEType::ZZ, 9, 6}, {1, 4}}, {{TQEType::XX, 11, 6}, {10, 3}}, + {{TQEType::XY, 11, 6}, {14, 9}}, {{TQEType::XZ, 11, 6}, {15, 12}}, + {{TQEType::YX, 11, 6}, {8, 2}}, {{TQEType::YY, 11, 6}, {4, 10}}, + {{TQEType::YZ, 11, 6}, {7, 14}}, {{TQEType::ZX, 11, 6}, {9, 7}}, + {{TQEType::ZY, 11, 6}, {1, 5}}, {{TQEType::ZZ, 11, 6}, {3, 4}}, + {{TQEType::XX, 10, 4}, {10, 1}}, {{TQEType::XY, 10, 4}, {14, 11}}, + {{TQEType::XZ, 10, 4}, {14, 14}}, {{TQEType::YX, 10, 4}, {10, 1}}, + {{TQEType::YY, 10, 4}, {6, 11}}, {{TQEType::YZ, 10, 4}, {6, 14}}, + {{TQEType::ZX, 10, 4}, {10, 4}}, {{TQEType::ZY, 10, 4}, {2, 4}}, + {{TQEType::ZZ, 10, 4}, {2, 4}}, {{TQEType::XX, 8, 4}, {8, 0}}, + {{TQEType::XY, 8, 4}, {12, 8}}, {{TQEType::XZ, 8, 4}, {12, 12}}, + {{TQEType::YX, 8, 4}, {8, 0}}, {{TQEType::YY, 8, 4}, {4, 8}}, + {{TQEType::YZ, 8, 4}, {4, 12}}, {{TQEType::ZX, 8, 4}, {8, 4}}, + {{TQEType::ZY, 8, 4}, {0, 4}}, {{TQEType::ZZ, 8, 4}, {0, 4}}, + {{TQEType::XX, 1, 7}, {0, 7}}, {{TQEType::XY, 1, 7}, {5, 7}}, + {{TQEType::XZ, 1, 7}, {4, 7}}, {{TQEType::YX, 1, 7}, {2, 6}}, + {{TQEType::YY, 1, 7}, {13, 4}}, {{TQEType::YZ, 1, 7}, {14, 5}}, + {{TQEType::ZX, 1, 7}, {3, 6}}, {{TQEType::ZY, 1, 7}, {9, 4}}, + {{TQEType::ZZ, 1, 7}, {11, 5}}, {{TQEType::XX, 3, 7}, {2, 6}}, + {{TQEType::XY, 3, 7}, {7, 4}}, {{TQEType::XZ, 3, 7}, {6, 5}}, + {{TQEType::YX, 3, 7}, {0, 7}}, {{TQEType::YY, 3, 7}, {15, 7}}, + {{TQEType::YZ, 3, 7}, {12, 7}}, {{TQEType::ZX, 3, 7}, {1, 6}}, + {{TQEType::ZY, 3, 7}, {11, 4}}, {{TQEType::ZZ, 3, 7}, {9, 5}}, + {{TQEType::XX, 2, 7}, {3, 6}}, {{TQEType::XY, 2, 7}, {6, 4}}, + {{TQEType::XZ, 2, 7}, {7, 5}}, {{TQEType::YX, 2, 7}, {1, 6}}, + {{TQEType::YY, 2, 7}, {14, 4}}, {{TQEType::YZ, 2, 7}, {13, 5}}, + {{TQEType::ZX, 2, 7}, {0, 7}}, {{TQEType::ZY, 2, 7}, {10, 7}}, + {{TQEType::ZZ, 2, 7}, {8, 7}}, {{TQEType::XX, 0, 7}, {1, 7}}, + {{TQEType::XY, 0, 7}, {4, 7}}, {{TQEType::XZ, 0, 7}, {5, 7}}, + {{TQEType::YX, 0, 7}, {3, 7}}, {{TQEType::YY, 0, 7}, {12, 7}}, + {{TQEType::YZ, 0, 7}, {15, 7}}, {{TQEType::ZX, 0, 7}, {2, 7}}, + {{TQEType::ZY, 0, 7}, {8, 7}}, {{TQEType::ZZ, 0, 7}, {10, 7}}, + {{TQEType::XX, 1, 6}, {0, 6}}, {{TQEType::XY, 1, 6}, {4, 6}}, + {{TQEType::XZ, 1, 6}, {5, 6}}, {{TQEType::YX, 1, 6}, {2, 7}}, + {{TQEType::YY, 1, 6}, {14, 5}}, {{TQEType::YZ, 1, 6}, {13, 4}}, + {{TQEType::ZX, 1, 6}, {3, 7}}, {{TQEType::ZY, 1, 6}, {11, 5}}, + {{TQEType::ZZ, 1, 6}, {9, 4}}, {{TQEType::XX, 3, 6}, {2, 7}}, + {{TQEType::XY, 3, 6}, {6, 5}}, {{TQEType::XZ, 3, 6}, {7, 4}}, + {{TQEType::YX, 3, 6}, {0, 6}}, {{TQEType::YY, 3, 6}, {12, 6}}, + {{TQEType::YZ, 3, 6}, {15, 6}}, {{TQEType::ZX, 3, 6}, {1, 7}}, + {{TQEType::ZY, 3, 6}, {9, 5}}, {{TQEType::ZZ, 3, 6}, {11, 4}}, + {{TQEType::XX, 2, 6}, {3, 7}}, {{TQEType::XY, 2, 6}, {7, 5}}, + {{TQEType::XZ, 2, 6}, {6, 4}}, {{TQEType::YX, 2, 6}, {1, 7}}, + {{TQEType::YY, 2, 6}, {13, 5}}, {{TQEType::YZ, 2, 6}, {14, 4}}, + {{TQEType::ZX, 2, 6}, {0, 6}}, {{TQEType::ZY, 2, 6}, {8, 6}}, + {{TQEType::ZZ, 2, 6}, {10, 6}}, {{TQEType::XX, 0, 6}, {1, 6}}, + {{TQEType::XY, 0, 6}, {5, 6}}, {{TQEType::XZ, 0, 6}, {4, 6}}, + {{TQEType::YX, 0, 6}, {3, 6}}, {{TQEType::YY, 0, 6}, {15, 6}}, + {{TQEType::YZ, 0, 6}, {12, 6}}, {{TQEType::ZX, 0, 6}, {2, 6}}, + {{TQEType::ZY, 0, 6}, {10, 6}}, {{TQEType::ZZ, 0, 6}, {8, 6}}, + {{TQEType::XX, 1, 5}, {1, 5}}, {{TQEType::XY, 1, 5}, {4, 5}}, + {{TQEType::XZ, 1, 5}, {4, 5}}, {{TQEType::YX, 1, 5}, {1, 4}}, + {{TQEType::YY, 1, 5}, {14, 6}}, {{TQEType::YZ, 1, 5}, {14, 7}}, + {{TQEType::ZX, 1, 5}, {1, 4}}, {{TQEType::ZY, 1, 5}, {11, 6}}, + {{TQEType::ZZ, 1, 5}, {11, 7}}, {{TQEType::XX, 3, 5}, {3, 4}}, + {{TQEType::XY, 3, 5}, {6, 6}}, {{TQEType::XZ, 3, 5}, {6, 7}}, + {{TQEType::YX, 3, 5}, {3, 5}}, {{TQEType::YY, 3, 5}, {12, 5}}, + {{TQEType::YZ, 3, 5}, {12, 5}}, {{TQEType::ZX, 3, 5}, {3, 4}}, + {{TQEType::ZY, 3, 5}, {9, 6}}, {{TQEType::ZZ, 3, 5}, {9, 7}}, + {{TQEType::XX, 2, 5}, {2, 4}}, {{TQEType::XY, 2, 5}, {7, 6}}, + {{TQEType::XZ, 2, 5}, {7, 7}}, {{TQEType::YX, 2, 5}, {2, 4}}, + {{TQEType::YY, 2, 5}, {13, 6}}, {{TQEType::YZ, 2, 5}, {13, 7}}, + {{TQEType::ZX, 2, 5}, {2, 5}}, {{TQEType::ZY, 2, 5}, {8, 5}}, + {{TQEType::ZZ, 2, 5}, {8, 5}}, {{TQEType::XX, 0, 5}, {0, 5}}, + {{TQEType::XY, 0, 5}, {5, 5}}, {{TQEType::XZ, 0, 5}, {5, 5}}, + {{TQEType::YX, 0, 5}, {0, 5}}, {{TQEType::YY, 0, 5}, {15, 5}}, + {{TQEType::YZ, 0, 5}, {15, 5}}, {{TQEType::ZX, 0, 5}, {0, 5}}, + {{TQEType::ZY, 0, 5}, {10, 5}}, {{TQEType::ZZ, 0, 5}, {10, 5}}, + {{TQEType::XX, 1, 4}, {1, 4}}, {{TQEType::XY, 1, 4}, {5, 4}}, + {{TQEType::XZ, 1, 4}, {5, 4}}, {{TQEType::YX, 1, 4}, {1, 5}}, + {{TQEType::YY, 1, 4}, {13, 7}}, {{TQEType::YZ, 1, 4}, {13, 6}}, + {{TQEType::ZX, 1, 4}, {1, 5}}, {{TQEType::ZY, 1, 4}, {9, 7}}, + {{TQEType::ZZ, 1, 4}, {9, 6}}, {{TQEType::XX, 3, 4}, {3, 5}}, + {{TQEType::XY, 3, 4}, {7, 7}}, {{TQEType::XZ, 3, 4}, {7, 6}}, + {{TQEType::YX, 3, 4}, {3, 4}}, {{TQEType::YY, 3, 4}, {15, 4}}, + {{TQEType::YZ, 3, 4}, {15, 4}}, {{TQEType::ZX, 3, 4}, {3, 5}}, + {{TQEType::ZY, 3, 4}, {11, 7}}, {{TQEType::ZZ, 3, 4}, {11, 6}}, + {{TQEType::XX, 2, 4}, {2, 5}}, {{TQEType::XY, 2, 4}, {6, 7}}, + {{TQEType::XZ, 2, 4}, {6, 6}}, {{TQEType::YX, 2, 4}, {2, 5}}, + {{TQEType::YY, 2, 4}, {14, 7}}, {{TQEType::YZ, 2, 4}, {14, 6}}, + {{TQEType::ZX, 2, 4}, {2, 4}}, {{TQEType::ZY, 2, 4}, {10, 4}}, + {{TQEType::ZZ, 2, 4}, {10, 4}}, {{TQEType::XX, 0, 4}, {0, 4}}, + {{TQEType::XY, 0, 4}, {4, 4}}, {{TQEType::XZ, 0, 4}, {4, 4}}, + {{TQEType::YX, 0, 4}, {0, 4}}, {{TQEType::YY, 0, 4}, {12, 4}}, + {{TQEType::YZ, 0, 4}, {12, 4}}, {{TQEType::ZX, 0, 4}, {0, 4}}, + {{TQEType::ZY, 0, 4}, {8, 4}}, {{TQEType::ZZ, 0, 4}, {8, 4}}, + {{TQEType::XX, 5, 13}, {1, 13}}, {{TQEType::XY, 5, 13}, {4, 13}}, + {{TQEType::XZ, 5, 13}, {0, 13}}, {{TQEType::YX, 5, 13}, {9, 8}}, + {{TQEType::YY, 5, 13}, {6, 2}}, {{TQEType::YZ, 5, 13}, {10, 7}}, + {{TQEType::ZX, 5, 13}, {13, 8}}, {{TQEType::ZY, 5, 13}, {7, 2}}, + {{TQEType::ZZ, 5, 13}, {15, 7}}, {{TQEType::XX, 4, 13}, {0, 13}}, + {{TQEType::XY, 4, 13}, {5, 13}}, {{TQEType::XZ, 4, 13}, {1, 13}}, + {{TQEType::YX, 4, 13}, {8, 9}}, {{TQEType::YY, 4, 13}, {7, 1}}, + {{TQEType::YZ, 4, 13}, {11, 5}}, {{TQEType::ZX, 4, 13}, {12, 9}}, + {{TQEType::ZY, 4, 13}, {6, 1}}, {{TQEType::ZZ, 4, 13}, {14, 5}}, + {{TQEType::XX, 7, 15}, {2, 14}}, {{TQEType::XY, 7, 15}, {7, 12}}, + {{TQEType::XZ, 7, 15}, {2, 13}}, {{TQEType::YX, 7, 15}, {8, 11}}, + {{TQEType::YY, 7, 15}, {7, 3}}, {{TQEType::YZ, 7, 15}, {8, 7}}, + {{TQEType::ZX, 7, 15}, {13, 10}}, {{TQEType::ZY, 7, 15}, {7, 0}}, + {{TQEType::ZZ, 7, 15}, {13, 5}}, {{TQEType::XX, 6, 15}, {3, 14}}, + {{TQEType::XY, 6, 15}, {6, 12}}, {{TQEType::XZ, 6, 15}, {3, 13}}, + {{TQEType::YX, 6, 15}, {9, 10}}, {{TQEType::YY, 6, 15}, {6, 0}}, + {{TQEType::YZ, 6, 15}, {9, 5}}, {{TQEType::ZX, 6, 15}, {12, 11}}, + {{TQEType::ZY, 6, 15}, {6, 3}}, {{TQEType::ZZ, 6, 15}, {12, 7}}, + {{TQEType::XX, 5, 14}, {0, 14}}, {{TQEType::XY, 5, 14}, {4, 14}}, + {{TQEType::XZ, 5, 14}, {1, 14}}, {{TQEType::YX, 5, 14}, {10, 11}}, + {{TQEType::YY, 5, 14}, {6, 1}}, {{TQEType::YZ, 5, 14}, {9, 4}}, + {{TQEType::ZX, 5, 14}, {15, 11}}, {{TQEType::ZY, 5, 14}, {7, 1}}, + {{TQEType::ZZ, 5, 14}, {13, 4}}, {{TQEType::XX, 4, 14}, {1, 14}}, + {{TQEType::XY, 4, 14}, {5, 14}}, {{TQEType::XZ, 4, 14}, {0, 14}}, + {{TQEType::YX, 4, 14}, {11, 10}}, {{TQEType::YY, 4, 14}, {7, 2}}, + {{TQEType::YZ, 4, 14}, {8, 6}}, {{TQEType::ZX, 4, 14}, {14, 10}}, + {{TQEType::ZY, 4, 14}, {6, 2}}, {{TQEType::ZZ, 4, 14}, {12, 6}}, + {{TQEType::XX, 7, 12}, {3, 13}}, {{TQEType::XY, 7, 12}, {7, 15}}, + {{TQEType::XZ, 7, 12}, {3, 14}}, {{TQEType::YX, 7, 12}, {11, 8}}, + {{TQEType::YY, 7, 12}, {7, 0}}, {{TQEType::YZ, 7, 12}, {11, 4}}, + {{TQEType::ZX, 7, 12}, {15, 9}}, {{TQEType::ZY, 7, 12}, {7, 3}}, + {{TQEType::ZZ, 7, 12}, {15, 6}}, {{TQEType::XX, 6, 12}, {2, 13}}, + {{TQEType::XY, 6, 12}, {6, 15}}, {{TQEType::XZ, 6, 12}, {2, 14}}, + {{TQEType::YX, 6, 12}, {10, 9}}, {{TQEType::YY, 6, 12}, {6, 3}}, + {{TQEType::YZ, 6, 12}, {10, 6}}, {{TQEType::ZX, 6, 12}, {14, 8}}, + {{TQEType::ZY, 6, 12}, {6, 0}}, {{TQEType::ZZ, 6, 12}, {14, 4}}, + {{TQEType::XX, 7, 13}, {3, 12}}, {{TQEType::XY, 7, 13}, {6, 14}}, + {{TQEType::XZ, 7, 13}, {2, 15}}, {{TQEType::YX, 7, 13}, {11, 9}}, + {{TQEType::YY, 7, 13}, {4, 1}}, {{TQEType::YZ, 7, 13}, {8, 5}}, + {{TQEType::ZX, 7, 13}, {15, 8}}, {{TQEType::ZY, 7, 13}, {5, 2}}, + {{TQEType::ZZ, 7, 13}, {13, 7}}, {{TQEType::XX, 6, 13}, {2, 12}}, + {{TQEType::XY, 6, 13}, {7, 14}}, {{TQEType::XZ, 6, 13}, {3, 15}}, + {{TQEType::YX, 6, 13}, {10, 8}}, {{TQEType::YY, 6, 13}, {5, 2}}, + {{TQEType::YZ, 6, 13}, {9, 7}}, {{TQEType::ZX, 6, 13}, {14, 9}}, + {{TQEType::ZY, 6, 13}, {4, 1}}, {{TQEType::ZZ, 6, 13}, {12, 5}}, + {{TQEType::XX, 5, 15}, {0, 15}}, {{TQEType::XY, 5, 15}, {5, 15}}, + {{TQEType::XZ, 5, 15}, {0, 15}}, {{TQEType::YX, 5, 15}, {10, 10}}, + {{TQEType::YY, 5, 15}, {5, 0}}, {{TQEType::YZ, 5, 15}, {10, 5}}, + {{TQEType::ZX, 5, 15}, {15, 10}}, {{TQEType::ZY, 5, 15}, {5, 0}}, + {{TQEType::ZZ, 5, 15}, {15, 5}}, {{TQEType::XX, 4, 15}, {1, 15}}, + {{TQEType::XY, 4, 15}, {4, 15}}, {{TQEType::XZ, 4, 15}, {1, 15}}, + {{TQEType::YX, 4, 15}, {11, 11}}, {{TQEType::YY, 4, 15}, {4, 3}}, + {{TQEType::YZ, 4, 15}, {11, 7}}, {{TQEType::ZX, 4, 15}, {14, 11}}, + {{TQEType::ZY, 4, 15}, {4, 3}}, {{TQEType::ZZ, 4, 15}, {14, 7}}, + {{TQEType::XX, 7, 14}, {2, 15}}, {{TQEType::XY, 7, 14}, {6, 13}}, + {{TQEType::XZ, 7, 14}, {3, 12}}, {{TQEType::YX, 7, 14}, {8, 10}}, + {{TQEType::YY, 7, 14}, {4, 2}}, {{TQEType::YZ, 7, 14}, {11, 6}}, + {{TQEType::ZX, 7, 14}, {13, 11}}, {{TQEType::ZY, 7, 14}, {5, 1}}, + {{TQEType::ZZ, 7, 14}, {15, 4}}, {{TQEType::XX, 6, 14}, {3, 15}}, + {{TQEType::XY, 6, 14}, {7, 13}}, {{TQEType::XZ, 6, 14}, {2, 12}}, + {{TQEType::YX, 6, 14}, {9, 11}}, {{TQEType::YY, 6, 14}, {5, 1}}, + {{TQEType::YZ, 6, 14}, {10, 4}}, {{TQEType::ZX, 6, 14}, {12, 10}}, + {{TQEType::ZY, 6, 14}, {4, 2}}, {{TQEType::ZZ, 6, 14}, {14, 6}}, + {{TQEType::XX, 5, 12}, {1, 12}}, {{TQEType::XY, 5, 12}, {5, 12}}, + {{TQEType::XZ, 5, 12}, {1, 12}}, {{TQEType::YX, 5, 12}, {9, 9}}, + {{TQEType::YY, 5, 12}, {5, 3}}, {{TQEType::YZ, 5, 12}, {9, 6}}, + {{TQEType::ZX, 5, 12}, {13, 9}}, {{TQEType::ZY, 5, 12}, {5, 3}}, + {{TQEType::ZZ, 5, 12}, {13, 6}}, {{TQEType::XX, 4, 12}, {0, 12}}, + {{TQEType::XY, 4, 12}, {4, 12}}, {{TQEType::XZ, 4, 12}, {0, 12}}, + {{TQEType::YX, 4, 12}, {8, 8}}, {{TQEType::YY, 4, 12}, {4, 0}}, + {{TQEType::YZ, 4, 12}, {8, 4}}, {{TQEType::ZX, 4, 12}, {12, 8}}, + {{TQEType::ZY, 4, 12}, {4, 0}}, {{TQEType::ZZ, 4, 12}, {12, 4}}, + {{TQEType::XX, 15, 13}, {11, 8}}, {{TQEType::XY, 15, 13}, {14, 2}}, + {{TQEType::XZ, 15, 13}, {10, 7}}, {{TQEType::YX, 15, 13}, {3, 13}}, + {{TQEType::YY, 15, 13}, {12, 13}}, {{TQEType::YZ, 15, 13}, {0, 13}}, + {{TQEType::ZX, 15, 13}, {7, 8}}, {{TQEType::ZY, 15, 13}, {13, 2}}, + {{TQEType::ZZ, 15, 13}, {5, 7}}, {{TQEType::XX, 12, 13}, {8, 9}}, + {{TQEType::XY, 12, 13}, {13, 1}}, {{TQEType::XZ, 12, 13}, {9, 5}}, + {{TQEType::YX, 12, 13}, {0, 13}}, {{TQEType::YY, 12, 13}, {15, 13}}, + {{TQEType::YZ, 12, 13}, {3, 13}}, {{TQEType::ZX, 12, 13}, {4, 9}}, + {{TQEType::ZY, 12, 13}, {14, 1}}, {{TQEType::ZZ, 12, 13}, {6, 5}}, + {{TQEType::XX, 13, 15}, {8, 11}}, {{TQEType::XY, 13, 15}, {13, 3}}, + {{TQEType::XZ, 13, 15}, {8, 7}}, {{TQEType::YX, 13, 15}, {2, 14}}, + {{TQEType::YY, 13, 15}, {13, 12}}, {{TQEType::YZ, 13, 15}, {2, 13}}, + {{TQEType::ZX, 13, 15}, {7, 10}}, {{TQEType::ZY, 13, 15}, {13, 0}}, + {{TQEType::ZZ, 13, 15}, {7, 5}}, {{TQEType::XX, 14, 15}, {11, 10}}, + {{TQEType::XY, 14, 15}, {14, 0}}, {{TQEType::XZ, 14, 15}, {11, 5}}, + {{TQEType::YX, 14, 15}, {1, 14}}, {{TQEType::YY, 14, 15}, {14, 12}}, + {{TQEType::YZ, 14, 15}, {1, 13}}, {{TQEType::ZX, 14, 15}, {4, 11}}, + {{TQEType::ZY, 14, 15}, {14, 3}}, {{TQEType::ZZ, 14, 15}, {4, 7}}, + {{TQEType::XX, 15, 14}, {10, 11}}, {{TQEType::XY, 15, 14}, {14, 1}}, + {{TQEType::XZ, 15, 14}, {11, 4}}, {{TQEType::YX, 15, 14}, {0, 14}}, + {{TQEType::YY, 15, 14}, {12, 14}}, {{TQEType::YZ, 15, 14}, {3, 14}}, + {{TQEType::ZX, 15, 14}, {5, 11}}, {{TQEType::ZY, 15, 14}, {13, 1}}, + {{TQEType::ZZ, 15, 14}, {7, 4}}, {{TQEType::XX, 12, 14}, {9, 10}}, + {{TQEType::XY, 12, 14}, {13, 2}}, {{TQEType::XZ, 12, 14}, {8, 6}}, + {{TQEType::YX, 12, 14}, {3, 14}}, {{TQEType::YY, 12, 14}, {15, 14}}, + {{TQEType::YZ, 12, 14}, {0, 14}}, {{TQEType::ZX, 12, 14}, {6, 10}}, + {{TQEType::ZY, 12, 14}, {14, 2}}, {{TQEType::ZZ, 12, 14}, {4, 6}}, + {{TQEType::XX, 13, 12}, {9, 8}}, {{TQEType::XY, 13, 12}, {13, 0}}, + {{TQEType::XZ, 13, 12}, {9, 4}}, {{TQEType::YX, 13, 12}, {1, 13}}, + {{TQEType::YY, 13, 12}, {13, 15}}, {{TQEType::YZ, 13, 12}, {1, 14}}, + {{TQEType::ZX, 13, 12}, {5, 9}}, {{TQEType::ZY, 13, 12}, {13, 3}}, + {{TQEType::ZZ, 13, 12}, {5, 6}}, {{TQEType::XX, 14, 12}, {10, 9}}, + {{TQEType::XY, 14, 12}, {14, 3}}, {{TQEType::XZ, 14, 12}, {10, 6}}, + {{TQEType::YX, 14, 12}, {2, 13}}, {{TQEType::YY, 14, 12}, {14, 15}}, + {{TQEType::YZ, 14, 12}, {2, 14}}, {{TQEType::ZX, 14, 12}, {6, 8}}, + {{TQEType::ZY, 14, 12}, {14, 0}}, {{TQEType::ZZ, 14, 12}, {6, 4}}, + {{TQEType::XX, 13, 13}, {9, 9}}, {{TQEType::XY, 13, 13}, {12, 1}}, + {{TQEType::XZ, 13, 13}, {8, 5}}, {{TQEType::YX, 13, 13}, {1, 12}}, + {{TQEType::YY, 13, 13}, {14, 14}}, {{TQEType::YZ, 13, 13}, {2, 15}}, + {{TQEType::ZX, 13, 13}, {5, 8}}, {{TQEType::ZY, 13, 13}, {15, 2}}, + {{TQEType::ZZ, 13, 13}, {7, 7}}, {{TQEType::XX, 14, 13}, {10, 8}}, + {{TQEType::XY, 14, 13}, {15, 2}}, {{TQEType::XZ, 14, 13}, {11, 7}}, + {{TQEType::YX, 14, 13}, {2, 12}}, {{TQEType::YY, 14, 13}, {13, 14}}, + {{TQEType::YZ, 14, 13}, {1, 15}}, {{TQEType::ZX, 14, 13}, {6, 9}}, + {{TQEType::ZY, 14, 13}, {12, 1}}, {{TQEType::ZZ, 14, 13}, {4, 5}}, + {{TQEType::XX, 15, 15}, {10, 10}}, {{TQEType::XY, 15, 15}, {15, 0}}, + {{TQEType::XZ, 15, 15}, {10, 5}}, {{TQEType::YX, 15, 15}, {0, 15}}, + {{TQEType::YY, 15, 15}, {15, 15}}, {{TQEType::YZ, 15, 15}, {0, 15}}, + {{TQEType::ZX, 15, 15}, {5, 10}}, {{TQEType::ZY, 15, 15}, {15, 0}}, + {{TQEType::ZZ, 15, 15}, {5, 5}}, {{TQEType::XX, 12, 15}, {9, 11}}, + {{TQEType::XY, 12, 15}, {12, 3}}, {{TQEType::XZ, 12, 15}, {9, 7}}, + {{TQEType::YX, 12, 15}, {3, 15}}, {{TQEType::YY, 12, 15}, {12, 15}}, + {{TQEType::YZ, 12, 15}, {3, 15}}, {{TQEType::ZX, 12, 15}, {6, 11}}, + {{TQEType::ZY, 12, 15}, {12, 3}}, {{TQEType::ZZ, 12, 15}, {6, 7}}, + {{TQEType::XX, 13, 14}, {8, 10}}, {{TQEType::XY, 13, 14}, {12, 2}}, + {{TQEType::XZ, 13, 14}, {9, 6}}, {{TQEType::YX, 13, 14}, {2, 15}}, + {{TQEType::YY, 13, 14}, {14, 13}}, {{TQEType::YZ, 13, 14}, {1, 12}}, + {{TQEType::ZX, 13, 14}, {7, 11}}, {{TQEType::ZY, 13, 14}, {15, 1}}, + {{TQEType::ZZ, 13, 14}, {5, 4}}, {{TQEType::XX, 14, 14}, {11, 11}}, + {{TQEType::XY, 14, 14}, {15, 1}}, {{TQEType::XZ, 14, 14}, {10, 4}}, + {{TQEType::YX, 14, 14}, {1, 15}}, {{TQEType::YY, 14, 14}, {13, 13}}, + {{TQEType::YZ, 14, 14}, {2, 12}}, {{TQEType::ZX, 14, 14}, {4, 10}}, + {{TQEType::ZY, 14, 14}, {12, 2}}, {{TQEType::ZZ, 14, 14}, {6, 6}}, + {{TQEType::XX, 15, 12}, {11, 9}}, {{TQEType::XY, 15, 12}, {15, 3}}, + {{TQEType::XZ, 15, 12}, {11, 6}}, {{TQEType::YX, 15, 12}, {3, 12}}, + {{TQEType::YY, 15, 12}, {15, 12}}, {{TQEType::YZ, 15, 12}, {3, 12}}, + {{TQEType::ZX, 15, 12}, {7, 9}}, {{TQEType::ZY, 15, 12}, {15, 3}}, + {{TQEType::ZZ, 15, 12}, {7, 6}}, {{TQEType::XX, 12, 12}, {8, 8}}, + {{TQEType::XY, 12, 12}, {12, 0}}, {{TQEType::XZ, 12, 12}, {8, 4}}, + {{TQEType::YX, 12, 12}, {0, 12}}, {{TQEType::YY, 12, 12}, {12, 12}}, + {{TQEType::YZ, 12, 12}, {0, 12}}, {{TQEType::ZX, 12, 12}, {4, 8}}, + {{TQEType::ZY, 12, 12}, {12, 0}}, {{TQEType::ZZ, 12, 12}, {4, 4}}, + {{TQEType::XX, 10, 13}, {14, 8}}, {{TQEType::XY, 10, 13}, {11, 2}}, + {{TQEType::XZ, 10, 13}, {15, 7}}, {{TQEType::YX, 10, 13}, {6, 8}}, + {{TQEType::YY, 10, 13}, {9, 2}}, {{TQEType::YZ, 10, 13}, {5, 7}}, + {{TQEType::ZX, 10, 13}, {2, 13}}, {{TQEType::ZY, 10, 13}, {8, 13}}, + {{TQEType::ZZ, 10, 13}, {0, 13}}, {{TQEType::XX, 8, 13}, {12, 9}}, + {{TQEType::XY, 8, 13}, {9, 1}}, {{TQEType::XZ, 8, 13}, {13, 5}}, + {{TQEType::YX, 8, 13}, {4, 9}}, {{TQEType::YY, 8, 13}, {11, 1}}, + {{TQEType::YZ, 8, 13}, {7, 5}}, {{TQEType::ZX, 8, 13}, {0, 13}}, + {{TQEType::ZY, 8, 13}, {10, 13}}, {{TQEType::ZZ, 8, 13}, {2, 13}}, + {{TQEType::XX, 9, 15}, {12, 11}}, {{TQEType::XY, 9, 15}, {9, 3}}, + {{TQEType::XZ, 9, 15}, {12, 7}}, {{TQEType::YX, 9, 15}, {6, 10}}, + {{TQEType::YY, 9, 15}, {9, 0}}, {{TQEType::YZ, 9, 15}, {6, 5}}, + {{TQEType::ZX, 9, 15}, {3, 14}}, {{TQEType::ZY, 9, 15}, {9, 12}}, + {{TQEType::ZZ, 9, 15}, {3, 13}}, {{TQEType::XX, 11, 15}, {14, 10}}, + {{TQEType::XY, 11, 15}, {11, 0}}, {{TQEType::XZ, 11, 15}, {14, 5}}, + {{TQEType::YX, 11, 15}, {4, 11}}, {{TQEType::YY, 11, 15}, {11, 3}}, + {{TQEType::YZ, 11, 15}, {4, 7}}, {{TQEType::ZX, 11, 15}, {1, 14}}, + {{TQEType::ZY, 11, 15}, {11, 12}}, {{TQEType::ZZ, 11, 15}, {1, 13}}, + {{TQEType::XX, 10, 14}, {15, 11}}, {{TQEType::XY, 10, 14}, {11, 1}}, + {{TQEType::XZ, 10, 14}, {14, 4}}, {{TQEType::YX, 10, 14}, {5, 11}}, + {{TQEType::YY, 10, 14}, {9, 1}}, {{TQEType::YZ, 10, 14}, {6, 4}}, + {{TQEType::ZX, 10, 14}, {0, 14}}, {{TQEType::ZY, 10, 14}, {8, 14}}, + {{TQEType::ZZ, 10, 14}, {2, 14}}, {{TQEType::XX, 8, 14}, {13, 10}}, + {{TQEType::XY, 8, 14}, {9, 2}}, {{TQEType::XZ, 8, 14}, {12, 6}}, + {{TQEType::YX, 8, 14}, {7, 10}}, {{TQEType::YY, 8, 14}, {11, 2}}, + {{TQEType::YZ, 8, 14}, {4, 6}}, {{TQEType::ZX, 8, 14}, {2, 14}}, + {{TQEType::ZY, 8, 14}, {10, 14}}, {{TQEType::ZZ, 8, 14}, {0, 14}}, + {{TQEType::XX, 9, 12}, {13, 8}}, {{TQEType::XY, 9, 12}, {9, 0}}, + {{TQEType::XZ, 9, 12}, {13, 4}}, {{TQEType::YX, 9, 12}, {5, 9}}, + {{TQEType::YY, 9, 12}, {9, 3}}, {{TQEType::YZ, 9, 12}, {5, 6}}, + {{TQEType::ZX, 9, 12}, {1, 13}}, {{TQEType::ZY, 9, 12}, {9, 15}}, + {{TQEType::ZZ, 9, 12}, {1, 14}}, {{TQEType::XX, 11, 12}, {15, 9}}, + {{TQEType::XY, 11, 12}, {11, 3}}, {{TQEType::XZ, 11, 12}, {15, 6}}, + {{TQEType::YX, 11, 12}, {7, 8}}, {{TQEType::YY, 11, 12}, {11, 0}}, + {{TQEType::YZ, 11, 12}, {7, 4}}, {{TQEType::ZX, 11, 12}, {3, 13}}, + {{TQEType::ZY, 11, 12}, {11, 15}}, {{TQEType::ZZ, 11, 12}, {3, 14}}, + {{TQEType::XX, 9, 13}, {13, 9}}, {{TQEType::XY, 9, 13}, {8, 1}}, + {{TQEType::XZ, 9, 13}, {12, 5}}, {{TQEType::YX, 9, 13}, {5, 8}}, + {{TQEType::YY, 9, 13}, {10, 2}}, {{TQEType::YZ, 9, 13}, {6, 7}}, + {{TQEType::ZX, 9, 13}, {1, 12}}, {{TQEType::ZY, 9, 13}, {11, 14}}, + {{TQEType::ZZ, 9, 13}, {3, 15}}, {{TQEType::XX, 11, 13}, {15, 8}}, + {{TQEType::XY, 11, 13}, {10, 2}}, {{TQEType::XZ, 11, 13}, {14, 7}}, + {{TQEType::YX, 11, 13}, {7, 9}}, {{TQEType::YY, 11, 13}, {8, 1}}, + {{TQEType::YZ, 11, 13}, {4, 5}}, {{TQEType::ZX, 11, 13}, {3, 12}}, + {{TQEType::ZY, 11, 13}, {9, 14}}, {{TQEType::ZZ, 11, 13}, {1, 15}}, + {{TQEType::XX, 10, 15}, {15, 10}}, {{TQEType::XY, 10, 15}, {10, 0}}, + {{TQEType::XZ, 10, 15}, {15, 5}}, {{TQEType::YX, 10, 15}, {5, 10}}, + {{TQEType::YY, 10, 15}, {10, 0}}, {{TQEType::YZ, 10, 15}, {5, 5}}, + {{TQEType::ZX, 10, 15}, {0, 15}}, {{TQEType::ZY, 10, 15}, {10, 15}}, + {{TQEType::ZZ, 10, 15}, {0, 15}}, {{TQEType::XX, 8, 15}, {13, 11}}, + {{TQEType::XY, 8, 15}, {8, 3}}, {{TQEType::XZ, 8, 15}, {13, 7}}, + {{TQEType::YX, 8, 15}, {7, 11}}, {{TQEType::YY, 8, 15}, {8, 3}}, + {{TQEType::YZ, 8, 15}, {7, 7}}, {{TQEType::ZX, 8, 15}, {2, 15}}, + {{TQEType::ZY, 8, 15}, {8, 15}}, {{TQEType::ZZ, 8, 15}, {2, 15}}, + {{TQEType::XX, 9, 14}, {12, 10}}, {{TQEType::XY, 9, 14}, {8, 2}}, + {{TQEType::XZ, 9, 14}, {13, 6}}, {{TQEType::YX, 9, 14}, {6, 11}}, + {{TQEType::YY, 9, 14}, {10, 1}}, {{TQEType::YZ, 9, 14}, {5, 4}}, + {{TQEType::ZX, 9, 14}, {3, 15}}, {{TQEType::ZY, 9, 14}, {11, 13}}, + {{TQEType::ZZ, 9, 14}, {1, 12}}, {{TQEType::XX, 11, 14}, {14, 11}}, + {{TQEType::XY, 11, 14}, {10, 1}}, {{TQEType::XZ, 11, 14}, {15, 4}}, + {{TQEType::YX, 11, 14}, {4, 10}}, {{TQEType::YY, 11, 14}, {8, 2}}, + {{TQEType::YZ, 11, 14}, {7, 6}}, {{TQEType::ZX, 11, 14}, {1, 15}}, + {{TQEType::ZY, 11, 14}, {9, 13}}, {{TQEType::ZZ, 11, 14}, {3, 12}}, + {{TQEType::XX, 10, 12}, {14, 9}}, {{TQEType::XY, 10, 12}, {10, 3}}, + {{TQEType::XZ, 10, 12}, {14, 6}}, {{TQEType::YX, 10, 12}, {6, 9}}, + {{TQEType::YY, 10, 12}, {10, 3}}, {{TQEType::YZ, 10, 12}, {6, 6}}, + {{TQEType::ZX, 10, 12}, {2, 12}}, {{TQEType::ZY, 10, 12}, {10, 12}}, + {{TQEType::ZZ, 10, 12}, {2, 12}}, {{TQEType::XX, 8, 12}, {12, 8}}, + {{TQEType::XY, 8, 12}, {8, 0}}, {{TQEType::XZ, 8, 12}, {12, 4}}, + {{TQEType::YX, 8, 12}, {4, 8}}, {{TQEType::YY, 8, 12}, {8, 0}}, + {{TQEType::YZ, 8, 12}, {4, 4}}, {{TQEType::ZX, 8, 12}, {0, 12}}, + {{TQEType::ZY, 8, 12}, {8, 12}}, {{TQEType::ZZ, 8, 12}, {0, 12}}, + {{TQEType::XX, 1, 13}, {5, 13}}, {{TQEType::XY, 1, 13}, {0, 13}}, + {{TQEType::XZ, 1, 13}, {4, 13}}, {{TQEType::YX, 1, 13}, {13, 12}}, + {{TQEType::YY, 1, 13}, {2, 14}}, {{TQEType::YZ, 1, 13}, {14, 15}}, + {{TQEType::ZX, 1, 13}, {9, 12}}, {{TQEType::ZY, 1, 13}, {3, 14}}, + {{TQEType::ZZ, 1, 13}, {11, 15}}, {{TQEType::XX, 3, 13}, {7, 12}}, + {{TQEType::XY, 3, 13}, {2, 14}}, {{TQEType::XZ, 3, 13}, {6, 15}}, + {{TQEType::YX, 3, 13}, {15, 13}}, {{TQEType::YY, 3, 13}, {0, 13}}, + {{TQEType::YZ, 3, 13}, {12, 13}}, {{TQEType::ZX, 3, 13}, {11, 12}}, + {{TQEType::ZY, 3, 13}, {1, 14}}, {{TQEType::ZZ, 3, 13}, {9, 15}}, + {{TQEType::XX, 2, 13}, {6, 12}}, {{TQEType::XY, 2, 13}, {3, 14}}, + {{TQEType::XZ, 2, 13}, {7, 15}}, {{TQEType::YX, 2, 13}, {14, 12}}, + {{TQEType::YY, 2, 13}, {1, 14}}, {{TQEType::YZ, 2, 13}, {13, 15}}, + {{TQEType::ZX, 2, 13}, {10, 13}}, {{TQEType::ZY, 2, 13}, {0, 13}}, + {{TQEType::ZZ, 2, 13}, {8, 13}}, {{TQEType::XX, 0, 13}, {4, 13}}, + {{TQEType::XY, 0, 13}, {1, 13}}, {{TQEType::XZ, 0, 13}, {5, 13}}, + {{TQEType::YX, 0, 13}, {12, 13}}, {{TQEType::YY, 0, 13}, {3, 13}}, + {{TQEType::YZ, 0, 13}, {15, 13}}, {{TQEType::ZX, 0, 13}, {8, 13}}, + {{TQEType::ZY, 0, 13}, {2, 13}}, {{TQEType::ZZ, 0, 13}, {10, 13}}, + {{TQEType::XX, 1, 14}, {4, 14}}, {{TQEType::XY, 1, 14}, {0, 14}}, + {{TQEType::XZ, 1, 14}, {5, 14}}, {{TQEType::YX, 1, 14}, {14, 15}}, + {{TQEType::YY, 1, 14}, {2, 13}}, {{TQEType::YZ, 1, 14}, {13, 12}}, + {{TQEType::ZX, 1, 14}, {11, 15}}, {{TQEType::ZY, 1, 14}, {3, 13}}, + {{TQEType::ZZ, 1, 14}, {9, 12}}, {{TQEType::XX, 3, 14}, {6, 15}}, + {{TQEType::XY, 3, 14}, {2, 13}}, {{TQEType::XZ, 3, 14}, {7, 12}}, + {{TQEType::YX, 3, 14}, {12, 14}}, {{TQEType::YY, 3, 14}, {0, 14}}, + {{TQEType::YZ, 3, 14}, {15, 14}}, {{TQEType::ZX, 3, 14}, {9, 15}}, + {{TQEType::ZY, 3, 14}, {1, 13}}, {{TQEType::ZZ, 3, 14}, {11, 12}}, + {{TQEType::XX, 2, 14}, {7, 15}}, {{TQEType::XY, 2, 14}, {3, 13}}, + {{TQEType::XZ, 2, 14}, {6, 12}}, {{TQEType::YX, 2, 14}, {13, 15}}, + {{TQEType::YY, 2, 14}, {1, 13}}, {{TQEType::YZ, 2, 14}, {14, 12}}, + {{TQEType::ZX, 2, 14}, {8, 14}}, {{TQEType::ZY, 2, 14}, {0, 14}}, + {{TQEType::ZZ, 2, 14}, {10, 14}}, {{TQEType::XX, 0, 14}, {5, 14}}, + {{TQEType::XY, 0, 14}, {1, 14}}, {{TQEType::XZ, 0, 14}, {4, 14}}, + {{TQEType::YX, 0, 14}, {15, 14}}, {{TQEType::YY, 0, 14}, {3, 14}}, + {{TQEType::YZ, 0, 14}, {12, 14}}, {{TQEType::ZX, 0, 14}, {10, 14}}, + {{TQEType::ZY, 0, 14}, {2, 14}}, {{TQEType::ZZ, 0, 14}, {8, 14}}, + {{TQEType::XX, 1, 15}, {4, 15}}, {{TQEType::XY, 1, 15}, {1, 15}}, + {{TQEType::XZ, 1, 15}, {4, 15}}, {{TQEType::YX, 1, 15}, {14, 14}}, + {{TQEType::YY, 1, 15}, {1, 12}}, {{TQEType::YZ, 1, 15}, {14, 13}}, + {{TQEType::ZX, 1, 15}, {11, 14}}, {{TQEType::ZY, 1, 15}, {1, 12}}, + {{TQEType::ZZ, 1, 15}, {11, 13}}, {{TQEType::XX, 3, 15}, {6, 14}}, + {{TQEType::XY, 3, 15}, {3, 12}}, {{TQEType::XZ, 3, 15}, {6, 13}}, + {{TQEType::YX, 3, 15}, {12, 15}}, {{TQEType::YY, 3, 15}, {3, 15}}, + {{TQEType::YZ, 3, 15}, {12, 15}}, {{TQEType::ZX, 3, 15}, {9, 14}}, + {{TQEType::ZY, 3, 15}, {3, 12}}, {{TQEType::ZZ, 3, 15}, {9, 13}}, + {{TQEType::XX, 2, 15}, {7, 14}}, {{TQEType::XY, 2, 15}, {2, 12}}, + {{TQEType::XZ, 2, 15}, {7, 13}}, {{TQEType::YX, 2, 15}, {13, 14}}, + {{TQEType::YY, 2, 15}, {2, 12}}, {{TQEType::YZ, 2, 15}, {13, 13}}, + {{TQEType::ZX, 2, 15}, {8, 15}}, {{TQEType::ZY, 2, 15}, {2, 15}}, + {{TQEType::ZZ, 2, 15}, {8, 15}}, {{TQEType::XX, 0, 15}, {5, 15}}, + {{TQEType::XY, 0, 15}, {0, 15}}, {{TQEType::XZ, 0, 15}, {5, 15}}, + {{TQEType::YX, 0, 15}, {15, 15}}, {{TQEType::YY, 0, 15}, {0, 15}}, + {{TQEType::YZ, 0, 15}, {15, 15}}, {{TQEType::ZX, 0, 15}, {10, 15}}, + {{TQEType::ZY, 0, 15}, {0, 15}}, {{TQEType::ZZ, 0, 15}, {10, 15}}, + {{TQEType::XX, 1, 12}, {5, 12}}, {{TQEType::XY, 1, 12}, {1, 12}}, + {{TQEType::XZ, 1, 12}, {5, 12}}, {{TQEType::YX, 1, 12}, {13, 13}}, + {{TQEType::YY, 1, 12}, {1, 15}}, {{TQEType::YZ, 1, 12}, {13, 14}}, + {{TQEType::ZX, 1, 12}, {9, 13}}, {{TQEType::ZY, 1, 12}, {1, 15}}, + {{TQEType::ZZ, 1, 12}, {9, 14}}, {{TQEType::XX, 3, 12}, {7, 13}}, + {{TQEType::XY, 3, 12}, {3, 15}}, {{TQEType::XZ, 3, 12}, {7, 14}}, + {{TQEType::YX, 3, 12}, {15, 12}}, {{TQEType::YY, 3, 12}, {3, 12}}, + {{TQEType::YZ, 3, 12}, {15, 12}}, {{TQEType::ZX, 3, 12}, {11, 13}}, + {{TQEType::ZY, 3, 12}, {3, 15}}, {{TQEType::ZZ, 3, 12}, {11, 14}}, + {{TQEType::XX, 2, 12}, {6, 13}}, {{TQEType::XY, 2, 12}, {2, 15}}, + {{TQEType::XZ, 2, 12}, {6, 14}}, {{TQEType::YX, 2, 12}, {14, 13}}, + {{TQEType::YY, 2, 12}, {2, 15}}, {{TQEType::YZ, 2, 12}, {14, 14}}, + {{TQEType::ZX, 2, 12}, {10, 12}}, {{TQEType::ZY, 2, 12}, {2, 12}}, + {{TQEType::ZZ, 2, 12}, {10, 12}}, {{TQEType::XX, 0, 12}, {4, 12}}, + {{TQEType::XY, 0, 12}, {0, 12}}, {{TQEType::XZ, 0, 12}, {4, 12}}, + {{TQEType::YX, 0, 12}, {12, 12}}, {{TQEType::YY, 0, 12}, {0, 12}}, + {{TQEType::YZ, 0, 12}, {12, 12}}, {{TQEType::ZX, 0, 12}, {8, 12}}, + {{TQEType::ZY, 0, 12}, {0, 12}}, {{TQEType::ZZ, 0, 12}, {8, 12}}, + {{TQEType::XX, 5, 9}, {1, 9}}, {{TQEType::XY, 5, 9}, {0, 9}}, + {{TQEType::XZ, 5, 9}, {4, 9}}, {{TQEType::YX, 5, 9}, {9, 12}}, + {{TQEType::YY, 5, 9}, {10, 6}}, {{TQEType::YZ, 5, 9}, {6, 3}}, + {{TQEType::ZX, 5, 9}, {13, 12}}, {{TQEType::ZY, 5, 9}, {15, 6}}, + {{TQEType::ZZ, 5, 9}, {7, 3}}, {{TQEType::XX, 4, 9}, {0, 9}}, + {{TQEType::XY, 4, 9}, {1, 9}}, {{TQEType::XZ, 4, 9}, {5, 9}}, + {{TQEType::YX, 4, 9}, {8, 13}}, {{TQEType::YY, 4, 9}, {11, 5}}, + {{TQEType::YZ, 4, 9}, {7, 1}}, {{TQEType::ZX, 4, 9}, {12, 13}}, + {{TQEType::ZY, 4, 9}, {14, 5}}, {{TQEType::ZZ, 4, 9}, {6, 1}}, + {{TQEType::XX, 5, 11}, {0, 11}}, {{TQEType::XY, 5, 11}, {1, 11}}, + {{TQEType::XZ, 5, 11}, {4, 11}}, {{TQEType::YX, 5, 11}, {10, 14}}, + {{TQEType::YY, 5, 11}, {9, 4}}, {{TQEType::YZ, 5, 11}, {6, 1}}, + {{TQEType::ZX, 5, 11}, {15, 14}}, {{TQEType::ZY, 5, 11}, {13, 4}}, + {{TQEType::ZZ, 5, 11}, {7, 1}}, {{TQEType::XX, 4, 11}, {1, 11}}, + {{TQEType::XY, 4, 11}, {0, 11}}, {{TQEType::XZ, 4, 11}, {5, 11}}, + {{TQEType::YX, 4, 11}, {11, 15}}, {{TQEType::YY, 4, 11}, {8, 7}}, + {{TQEType::YZ, 4, 11}, {7, 3}}, {{TQEType::ZX, 4, 11}, {14, 15}}, + {{TQEType::ZY, 4, 11}, {12, 7}}, {{TQEType::ZZ, 4, 11}, {6, 3}}, + {{TQEType::XX, 7, 10}, {2, 11}}, {{TQEType::XY, 7, 10}, {2, 9}}, + {{TQEType::XZ, 7, 10}, {7, 8}}, {{TQEType::YX, 7, 10}, {8, 14}}, + {{TQEType::YY, 7, 10}, {8, 6}}, {{TQEType::YZ, 7, 10}, {7, 2}}, + {{TQEType::ZX, 7, 10}, {13, 15}}, {{TQEType::ZY, 7, 10}, {13, 5}}, + {{TQEType::ZZ, 7, 10}, {7, 0}}, {{TQEType::XX, 6, 10}, {3, 11}}, + {{TQEType::XY, 6, 10}, {3, 9}}, {{TQEType::XZ, 6, 10}, {6, 8}}, + {{TQEType::YX, 6, 10}, {9, 15}}, {{TQEType::YY, 6, 10}, {9, 5}}, + {{TQEType::YZ, 6, 10}, {6, 0}}, {{TQEType::ZX, 6, 10}, {12, 14}}, + {{TQEType::ZY, 6, 10}, {12, 6}}, {{TQEType::ZZ, 6, 10}, {6, 2}}, + {{TQEType::XX, 7, 8}, {3, 9}}, {{TQEType::XY, 7, 8}, {3, 11}}, + {{TQEType::XZ, 7, 8}, {7, 10}}, {{TQEType::YX, 7, 8}, {11, 12}}, + {{TQEType::YY, 7, 8}, {11, 4}}, {{TQEType::YZ, 7, 8}, {7, 0}}, + {{TQEType::ZX, 7, 8}, {15, 13}}, {{TQEType::ZY, 7, 8}, {15, 7}}, + {{TQEType::ZZ, 7, 8}, {7, 2}}, {{TQEType::XX, 6, 8}, {2, 9}}, + {{TQEType::XY, 6, 8}, {2, 11}}, {{TQEType::XZ, 6, 8}, {6, 10}}, + {{TQEType::YX, 6, 8}, {10, 13}}, {{TQEType::YY, 6, 8}, {10, 7}}, + {{TQEType::YZ, 6, 8}, {6, 2}}, {{TQEType::ZX, 6, 8}, {14, 12}}, + {{TQEType::ZY, 6, 8}, {14, 4}}, {{TQEType::ZZ, 6, 8}, {6, 0}}, + {{TQEType::XX, 7, 9}, {3, 8}}, {{TQEType::XY, 7, 9}, {2, 10}}, + {{TQEType::XZ, 7, 9}, {6, 11}}, {{TQEType::YX, 7, 9}, {11, 13}}, + {{TQEType::YY, 7, 9}, {8, 5}}, {{TQEType::YZ, 7, 9}, {4, 1}}, + {{TQEType::ZX, 7, 9}, {15, 12}}, {{TQEType::ZY, 7, 9}, {13, 6}}, + {{TQEType::ZZ, 7, 9}, {5, 3}}, {{TQEType::XX, 6, 9}, {2, 8}}, + {{TQEType::XY, 6, 9}, {3, 10}}, {{TQEType::XZ, 6, 9}, {7, 11}}, + {{TQEType::YX, 6, 9}, {10, 12}}, {{TQEType::YY, 6, 9}, {9, 6}}, + {{TQEType::YZ, 6, 9}, {5, 3}}, {{TQEType::ZX, 6, 9}, {14, 13}}, + {{TQEType::ZY, 6, 9}, {12, 5}}, {{TQEType::ZZ, 6, 9}, {4, 1}}, + {{TQEType::XX, 7, 11}, {2, 10}}, {{TQEType::XY, 7, 11}, {3, 8}}, + {{TQEType::XZ, 7, 11}, {6, 9}}, {{TQEType::YX, 7, 11}, {8, 15}}, + {{TQEType::YY, 7, 11}, {11, 7}}, {{TQEType::YZ, 7, 11}, {4, 3}}, + {{TQEType::ZX, 7, 11}, {13, 14}}, {{TQEType::ZY, 7, 11}, {15, 4}}, + {{TQEType::ZZ, 7, 11}, {5, 1}}, {{TQEType::XX, 6, 11}, {3, 10}}, + {{TQEType::XY, 6, 11}, {2, 8}}, {{TQEType::XZ, 6, 11}, {7, 9}}, + {{TQEType::YX, 6, 11}, {9, 14}}, {{TQEType::YY, 6, 11}, {10, 4}}, + {{TQEType::YZ, 6, 11}, {5, 1}}, {{TQEType::ZX, 6, 11}, {12, 15}}, + {{TQEType::ZY, 6, 11}, {14, 7}}, {{TQEType::ZZ, 6, 11}, {4, 3}}, + {{TQEType::XX, 5, 10}, {0, 10}}, {{TQEType::XY, 5, 10}, {0, 10}}, + {{TQEType::XZ, 5, 10}, {5, 10}}, {{TQEType::YX, 5, 10}, {10, 15}}, + {{TQEType::YY, 5, 10}, {10, 5}}, {{TQEType::YZ, 5, 10}, {5, 0}}, + {{TQEType::ZX, 5, 10}, {15, 15}}, {{TQEType::ZY, 5, 10}, {15, 5}}, + {{TQEType::ZZ, 5, 10}, {5, 0}}, {{TQEType::XX, 4, 10}, {1, 10}}, + {{TQEType::XY, 4, 10}, {1, 10}}, {{TQEType::XZ, 4, 10}, {4, 10}}, + {{TQEType::YX, 4, 10}, {11, 14}}, {{TQEType::YY, 4, 10}, {11, 6}}, + {{TQEType::YZ, 4, 10}, {4, 2}}, {{TQEType::ZX, 4, 10}, {14, 14}}, + {{TQEType::ZY, 4, 10}, {14, 6}}, {{TQEType::ZZ, 4, 10}, {4, 2}}, + {{TQEType::XX, 5, 8}, {1, 8}}, {{TQEType::XY, 5, 8}, {1, 8}}, + {{TQEType::XZ, 5, 8}, {5, 8}}, {{TQEType::YX, 5, 8}, {9, 13}}, + {{TQEType::YY, 5, 8}, {9, 7}}, {{TQEType::YZ, 5, 8}, {5, 2}}, + {{TQEType::ZX, 5, 8}, {13, 13}}, {{TQEType::ZY, 5, 8}, {13, 7}}, + {{TQEType::ZZ, 5, 8}, {5, 2}}, {{TQEType::XX, 4, 8}, {0, 8}}, + {{TQEType::XY, 4, 8}, {0, 8}}, {{TQEType::XZ, 4, 8}, {4, 8}}, + {{TQEType::YX, 4, 8}, {8, 12}}, {{TQEType::YY, 4, 8}, {8, 4}}, + {{TQEType::YZ, 4, 8}, {4, 0}}, {{TQEType::ZX, 4, 8}, {12, 12}}, + {{TQEType::ZY, 4, 8}, {12, 4}}, {{TQEType::ZZ, 4, 8}, {4, 0}}, + {{TQEType::XX, 15, 9}, {11, 12}}, {{TQEType::XY, 15, 9}, {10, 6}}, + {{TQEType::XZ, 15, 9}, {14, 3}}, {{TQEType::YX, 15, 9}, {3, 9}}, + {{TQEType::YY, 15, 9}, {0, 9}}, {{TQEType::YZ, 15, 9}, {12, 9}}, + {{TQEType::ZX, 15, 9}, {7, 12}}, {{TQEType::ZY, 15, 9}, {5, 6}}, + {{TQEType::ZZ, 15, 9}, {13, 3}}, {{TQEType::XX, 12, 9}, {8, 13}}, + {{TQEType::XY, 12, 9}, {9, 5}}, {{TQEType::XZ, 12, 9}, {13, 1}}, + {{TQEType::YX, 12, 9}, {0, 9}}, {{TQEType::YY, 12, 9}, {3, 9}}, + {{TQEType::YZ, 12, 9}, {15, 9}}, {{TQEType::ZX, 12, 9}, {4, 13}}, + {{TQEType::ZY, 12, 9}, {6, 5}}, {{TQEType::ZZ, 12, 9}, {14, 1}}, + {{TQEType::XX, 15, 11}, {10, 14}}, {{TQEType::XY, 15, 11}, {11, 4}}, + {{TQEType::XZ, 15, 11}, {14, 1}}, {{TQEType::YX, 15, 11}, {0, 11}}, + {{TQEType::YY, 15, 11}, {3, 11}}, {{TQEType::YZ, 15, 11}, {12, 11}}, + {{TQEType::ZX, 15, 11}, {5, 14}}, {{TQEType::ZY, 15, 11}, {7, 4}}, + {{TQEType::ZZ, 15, 11}, {13, 1}}, {{TQEType::XX, 12, 11}, {9, 15}}, + {{TQEType::XY, 12, 11}, {8, 7}}, {{TQEType::XZ, 12, 11}, {13, 3}}, + {{TQEType::YX, 12, 11}, {3, 11}}, {{TQEType::YY, 12, 11}, {0, 11}}, + {{TQEType::YZ, 12, 11}, {15, 11}}, {{TQEType::ZX, 12, 11}, {6, 15}}, + {{TQEType::ZY, 12, 11}, {4, 7}}, {{TQEType::ZZ, 12, 11}, {14, 3}}, + {{TQEType::XX, 13, 10}, {8, 14}}, {{TQEType::XY, 13, 10}, {8, 6}}, + {{TQEType::XZ, 13, 10}, {13, 2}}, {{TQEType::YX, 13, 10}, {2, 11}}, + {{TQEType::YY, 13, 10}, {2, 9}}, {{TQEType::YZ, 13, 10}, {13, 8}}, + {{TQEType::ZX, 13, 10}, {7, 15}}, {{TQEType::ZY, 13, 10}, {7, 5}}, + {{TQEType::ZZ, 13, 10}, {13, 0}}, {{TQEType::XX, 14, 10}, {11, 15}}, + {{TQEType::XY, 14, 10}, {11, 5}}, {{TQEType::XZ, 14, 10}, {14, 0}}, + {{TQEType::YX, 14, 10}, {1, 11}}, {{TQEType::YY, 14, 10}, {1, 9}}, + {{TQEType::YZ, 14, 10}, {14, 8}}, {{TQEType::ZX, 14, 10}, {4, 14}}, + {{TQEType::ZY, 14, 10}, {4, 6}}, {{TQEType::ZZ, 14, 10}, {14, 2}}, + {{TQEType::XX, 13, 8}, {9, 12}}, {{TQEType::XY, 13, 8}, {9, 4}}, + {{TQEType::XZ, 13, 8}, {13, 0}}, {{TQEType::YX, 13, 8}, {1, 9}}, + {{TQEType::YY, 13, 8}, {1, 11}}, {{TQEType::YZ, 13, 8}, {13, 10}}, + {{TQEType::ZX, 13, 8}, {5, 13}}, {{TQEType::ZY, 13, 8}, {5, 7}}, + {{TQEType::ZZ, 13, 8}, {13, 2}}, {{TQEType::XX, 14, 8}, {10, 13}}, + {{TQEType::XY, 14, 8}, {10, 7}}, {{TQEType::XZ, 14, 8}, {14, 2}}, + {{TQEType::YX, 14, 8}, {2, 9}}, {{TQEType::YY, 14, 8}, {2, 11}}, + {{TQEType::YZ, 14, 8}, {14, 10}}, {{TQEType::ZX, 14, 8}, {6, 12}}, + {{TQEType::ZY, 14, 8}, {6, 4}}, {{TQEType::ZZ, 14, 8}, {14, 0}}, + {{TQEType::XX, 13, 9}, {9, 13}}, {{TQEType::XY, 13, 9}, {8, 5}}, + {{TQEType::XZ, 13, 9}, {12, 1}}, {{TQEType::YX, 13, 9}, {1, 8}}, + {{TQEType::YY, 13, 9}, {2, 10}}, {{TQEType::YZ, 13, 9}, {14, 11}}, + {{TQEType::ZX, 13, 9}, {5, 12}}, {{TQEType::ZY, 13, 9}, {7, 6}}, + {{TQEType::ZZ, 13, 9}, {15, 3}}, {{TQEType::XX, 14, 9}, {10, 12}}, + {{TQEType::XY, 14, 9}, {11, 6}}, {{TQEType::XZ, 14, 9}, {15, 3}}, + {{TQEType::YX, 14, 9}, {2, 8}}, {{TQEType::YY, 14, 9}, {1, 10}}, + {{TQEType::YZ, 14, 9}, {13, 11}}, {{TQEType::ZX, 14, 9}, {6, 13}}, + {{TQEType::ZY, 14, 9}, {4, 5}}, {{TQEType::ZZ, 14, 9}, {12, 1}}, + {{TQEType::XX, 13, 11}, {8, 15}}, {{TQEType::XY, 13, 11}, {9, 7}}, + {{TQEType::XZ, 13, 11}, {12, 3}}, {{TQEType::YX, 13, 11}, {2, 10}}, + {{TQEType::YY, 13, 11}, {1, 8}}, {{TQEType::YZ, 13, 11}, {14, 9}}, + {{TQEType::ZX, 13, 11}, {7, 14}}, {{TQEType::ZY, 13, 11}, {5, 4}}, + {{TQEType::ZZ, 13, 11}, {15, 1}}, {{TQEType::XX, 14, 11}, {11, 14}}, + {{TQEType::XY, 14, 11}, {10, 4}}, {{TQEType::XZ, 14, 11}, {15, 1}}, + {{TQEType::YX, 14, 11}, {1, 10}}, {{TQEType::YY, 14, 11}, {2, 8}}, + {{TQEType::YZ, 14, 11}, {13, 9}}, {{TQEType::ZX, 14, 11}, {4, 15}}, + {{TQEType::ZY, 14, 11}, {6, 7}}, {{TQEType::ZZ, 14, 11}, {12, 3}}, + {{TQEType::XX, 15, 10}, {10, 15}}, {{TQEType::XY, 15, 10}, {10, 5}}, + {{TQEType::XZ, 15, 10}, {15, 0}}, {{TQEType::YX, 15, 10}, {0, 10}}, + {{TQEType::YY, 15, 10}, {0, 10}}, {{TQEType::YZ, 15, 10}, {15, 10}}, + {{TQEType::ZX, 15, 10}, {5, 15}}, {{TQEType::ZY, 15, 10}, {5, 5}}, + {{TQEType::ZZ, 15, 10}, {15, 0}}, {{TQEType::XX, 12, 10}, {9, 14}}, + {{TQEType::XY, 12, 10}, {9, 6}}, {{TQEType::XZ, 12, 10}, {12, 2}}, + {{TQEType::YX, 12, 10}, {3, 10}}, {{TQEType::YY, 12, 10}, {3, 10}}, + {{TQEType::YZ, 12, 10}, {12, 10}}, {{TQEType::ZX, 12, 10}, {6, 14}}, + {{TQEType::ZY, 12, 10}, {6, 6}}, {{TQEType::ZZ, 12, 10}, {12, 2}}, + {{TQEType::XX, 15, 8}, {11, 13}}, {{TQEType::XY, 15, 8}, {11, 7}}, + {{TQEType::XZ, 15, 8}, {15, 2}}, {{TQEType::YX, 15, 8}, {3, 8}}, + {{TQEType::YY, 15, 8}, {3, 8}}, {{TQEType::YZ, 15, 8}, {15, 8}}, + {{TQEType::ZX, 15, 8}, {7, 13}}, {{TQEType::ZY, 15, 8}, {7, 7}}, + {{TQEType::ZZ, 15, 8}, {15, 2}}, {{TQEType::XX, 12, 8}, {8, 12}}, + {{TQEType::XY, 12, 8}, {8, 4}}, {{TQEType::XZ, 12, 8}, {12, 0}}, + {{TQEType::YX, 12, 8}, {0, 8}}, {{TQEType::YY, 12, 8}, {0, 8}}, + {{TQEType::YZ, 12, 8}, {12, 8}}, {{TQEType::ZX, 12, 8}, {4, 12}}, + {{TQEType::ZY, 12, 8}, {4, 4}}, {{TQEType::ZZ, 12, 8}, {12, 0}}, + {{TQEType::XX, 10, 9}, {14, 12}}, {{TQEType::XY, 10, 9}, {15, 6}}, + {{TQEType::XZ, 10, 9}, {11, 3}}, {{TQEType::YX, 10, 9}, {6, 12}}, + {{TQEType::YY, 10, 9}, {5, 6}}, {{TQEType::YZ, 10, 9}, {9, 3}}, + {{TQEType::ZX, 10, 9}, {2, 9}}, {{TQEType::ZY, 10, 9}, {0, 9}}, + {{TQEType::ZZ, 10, 9}, {8, 9}}, {{TQEType::XX, 8, 9}, {12, 13}}, + {{TQEType::XY, 8, 9}, {13, 5}}, {{TQEType::XZ, 8, 9}, {9, 1}}, + {{TQEType::YX, 8, 9}, {4, 13}}, {{TQEType::YY, 8, 9}, {7, 5}}, + {{TQEType::YZ, 8, 9}, {11, 1}}, {{TQEType::ZX, 8, 9}, {0, 9}}, + {{TQEType::ZY, 8, 9}, {2, 9}}, {{TQEType::ZZ, 8, 9}, {10, 9}}, + {{TQEType::XX, 10, 11}, {15, 14}}, {{TQEType::XY, 10, 11}, {14, 4}}, + {{TQEType::XZ, 10, 11}, {11, 1}}, {{TQEType::YX, 10, 11}, {5, 14}}, + {{TQEType::YY, 10, 11}, {6, 4}}, {{TQEType::YZ, 10, 11}, {9, 1}}, + {{TQEType::ZX, 10, 11}, {0, 11}}, {{TQEType::ZY, 10, 11}, {2, 11}}, + {{TQEType::ZZ, 10, 11}, {8, 11}}, {{TQEType::XX, 8, 11}, {13, 15}}, + {{TQEType::XY, 8, 11}, {12, 7}}, {{TQEType::XZ, 8, 11}, {9, 3}}, + {{TQEType::YX, 8, 11}, {7, 15}}, {{TQEType::YY, 8, 11}, {4, 7}}, + {{TQEType::YZ, 8, 11}, {11, 3}}, {{TQEType::ZX, 8, 11}, {2, 11}}, + {{TQEType::ZY, 8, 11}, {0, 11}}, {{TQEType::ZZ, 8, 11}, {10, 11}}, + {{TQEType::XX, 9, 10}, {12, 14}}, {{TQEType::XY, 9, 10}, {12, 6}}, + {{TQEType::XZ, 9, 10}, {9, 2}}, {{TQEType::YX, 9, 10}, {6, 15}}, + {{TQEType::YY, 9, 10}, {6, 5}}, {{TQEType::YZ, 9, 10}, {9, 0}}, + {{TQEType::ZX, 9, 10}, {3, 11}}, {{TQEType::ZY, 9, 10}, {3, 9}}, + {{TQEType::ZZ, 9, 10}, {9, 8}}, {{TQEType::XX, 11, 10}, {14, 15}}, + {{TQEType::XY, 11, 10}, {14, 5}}, {{TQEType::XZ, 11, 10}, {11, 0}}, + {{TQEType::YX, 11, 10}, {4, 14}}, {{TQEType::YY, 11, 10}, {4, 6}}, + {{TQEType::YZ, 11, 10}, {11, 2}}, {{TQEType::ZX, 11, 10}, {1, 11}}, + {{TQEType::ZY, 11, 10}, {1, 9}}, {{TQEType::ZZ, 11, 10}, {11, 8}}, + {{TQEType::XX, 9, 8}, {13, 12}}, {{TQEType::XY, 9, 8}, {13, 4}}, + {{TQEType::XZ, 9, 8}, {9, 0}}, {{TQEType::YX, 9, 8}, {5, 13}}, + {{TQEType::YY, 9, 8}, {5, 7}}, {{TQEType::YZ, 9, 8}, {9, 2}}, + {{TQEType::ZX, 9, 8}, {1, 9}}, {{TQEType::ZY, 9, 8}, {1, 11}}, + {{TQEType::ZZ, 9, 8}, {9, 10}}, {{TQEType::XX, 11, 8}, {15, 13}}, + {{TQEType::XY, 11, 8}, {15, 7}}, {{TQEType::XZ, 11, 8}, {11, 2}}, + {{TQEType::YX, 11, 8}, {7, 12}}, {{TQEType::YY, 11, 8}, {7, 4}}, + {{TQEType::YZ, 11, 8}, {11, 0}}, {{TQEType::ZX, 11, 8}, {3, 9}}, + {{TQEType::ZY, 11, 8}, {3, 11}}, {{TQEType::ZZ, 11, 8}, {11, 10}}, + {{TQEType::XX, 9, 9}, {13, 13}}, {{TQEType::XY, 9, 9}, {12, 5}}, + {{TQEType::XZ, 9, 9}, {8, 1}}, {{TQEType::YX, 9, 9}, {5, 12}}, + {{TQEType::YY, 9, 9}, {6, 6}}, {{TQEType::YZ, 9, 9}, {10, 3}}, + {{TQEType::ZX, 9, 9}, {1, 8}}, {{TQEType::ZY, 9, 9}, {3, 10}}, + {{TQEType::ZZ, 9, 9}, {11, 11}}, {{TQEType::XX, 11, 9}, {15, 12}}, + {{TQEType::XY, 11, 9}, {14, 6}}, {{TQEType::XZ, 11, 9}, {10, 3}}, + {{TQEType::YX, 11, 9}, {7, 13}}, {{TQEType::YY, 11, 9}, {4, 5}}, + {{TQEType::YZ, 11, 9}, {8, 1}}, {{TQEType::ZX, 11, 9}, {3, 8}}, + {{TQEType::ZY, 11, 9}, {1, 10}}, {{TQEType::ZZ, 11, 9}, {9, 11}}, + {{TQEType::XX, 9, 11}, {12, 15}}, {{TQEType::XY, 9, 11}, {13, 7}}, + {{TQEType::XZ, 9, 11}, {8, 3}}, {{TQEType::YX, 9, 11}, {6, 14}}, + {{TQEType::YY, 9, 11}, {5, 4}}, {{TQEType::YZ, 9, 11}, {10, 1}}, + {{TQEType::ZX, 9, 11}, {3, 10}}, {{TQEType::ZY, 9, 11}, {1, 8}}, + {{TQEType::ZZ, 9, 11}, {11, 9}}, {{TQEType::XX, 11, 11}, {14, 14}}, + {{TQEType::XY, 11, 11}, {15, 4}}, {{TQEType::XZ, 11, 11}, {10, 1}}, + {{TQEType::YX, 11, 11}, {4, 15}}, {{TQEType::YY, 11, 11}, {7, 7}}, + {{TQEType::YZ, 11, 11}, {8, 3}}, {{TQEType::ZX, 11, 11}, {1, 10}}, + {{TQEType::ZY, 11, 11}, {3, 8}}, {{TQEType::ZZ, 11, 11}, {9, 9}}, + {{TQEType::XX, 10, 10}, {15, 15}}, {{TQEType::XY, 10, 10}, {15, 5}}, + {{TQEType::XZ, 10, 10}, {10, 0}}, {{TQEType::YX, 10, 10}, {5, 15}}, + {{TQEType::YY, 10, 10}, {5, 5}}, {{TQEType::YZ, 10, 10}, {10, 0}}, + {{TQEType::ZX, 10, 10}, {0, 10}}, {{TQEType::ZY, 10, 10}, {0, 10}}, + {{TQEType::ZZ, 10, 10}, {10, 10}}, {{TQEType::XX, 8, 10}, {13, 14}}, + {{TQEType::XY, 8, 10}, {13, 6}}, {{TQEType::XZ, 8, 10}, {8, 2}}, + {{TQEType::YX, 8, 10}, {7, 14}}, {{TQEType::YY, 8, 10}, {7, 6}}, + {{TQEType::YZ, 8, 10}, {8, 2}}, {{TQEType::ZX, 8, 10}, {2, 10}}, + {{TQEType::ZY, 8, 10}, {2, 10}}, {{TQEType::ZZ, 8, 10}, {8, 10}}, + {{TQEType::XX, 10, 8}, {14, 13}}, {{TQEType::XY, 10, 8}, {14, 7}}, + {{TQEType::XZ, 10, 8}, {10, 2}}, {{TQEType::YX, 10, 8}, {6, 13}}, + {{TQEType::YY, 10, 8}, {6, 7}}, {{TQEType::YZ, 10, 8}, {10, 2}}, + {{TQEType::ZX, 10, 8}, {2, 8}}, {{TQEType::ZY, 10, 8}, {2, 8}}, + {{TQEType::ZZ, 10, 8}, {10, 8}}, {{TQEType::XX, 8, 8}, {12, 12}}, + {{TQEType::XY, 8, 8}, {12, 4}}, {{TQEType::XZ, 8, 8}, {8, 0}}, + {{TQEType::YX, 8, 8}, {4, 12}}, {{TQEType::YY, 8, 8}, {4, 4}}, + {{TQEType::YZ, 8, 8}, {8, 0}}, {{TQEType::ZX, 8, 8}, {0, 8}}, + {{TQEType::ZY, 8, 8}, {0, 8}}, {{TQEType::ZZ, 8, 8}, {8, 8}}, + {{TQEType::XX, 1, 9}, {5, 9}}, {{TQEType::XY, 1, 9}, {4, 9}}, + {{TQEType::XZ, 1, 9}, {0, 9}}, {{TQEType::YX, 1, 9}, {13, 8}}, + {{TQEType::YY, 1, 9}, {14, 10}}, {{TQEType::YZ, 1, 9}, {2, 11}}, + {{TQEType::ZX, 1, 9}, {9, 8}}, {{TQEType::ZY, 1, 9}, {11, 10}}, + {{TQEType::ZZ, 1, 9}, {3, 11}}, {{TQEType::XX, 3, 9}, {7, 8}}, + {{TQEType::XY, 3, 9}, {6, 10}}, {{TQEType::XZ, 3, 9}, {2, 11}}, + {{TQEType::YX, 3, 9}, {15, 9}}, {{TQEType::YY, 3, 9}, {12, 9}}, + {{TQEType::YZ, 3, 9}, {0, 9}}, {{TQEType::ZX, 3, 9}, {11, 8}}, + {{TQEType::ZY, 3, 9}, {9, 10}}, {{TQEType::ZZ, 3, 9}, {1, 11}}, + {{TQEType::XX, 2, 9}, {6, 8}}, {{TQEType::XY, 2, 9}, {7, 10}}, + {{TQEType::XZ, 2, 9}, {3, 11}}, {{TQEType::YX, 2, 9}, {14, 8}}, + {{TQEType::YY, 2, 9}, {13, 10}}, {{TQEType::YZ, 2, 9}, {1, 11}}, + {{TQEType::ZX, 2, 9}, {10, 9}}, {{TQEType::ZY, 2, 9}, {8, 9}}, + {{TQEType::ZZ, 2, 9}, {0, 9}}, {{TQEType::XX, 0, 9}, {4, 9}}, + {{TQEType::XY, 0, 9}, {5, 9}}, {{TQEType::XZ, 0, 9}, {1, 9}}, + {{TQEType::YX, 0, 9}, {12, 9}}, {{TQEType::YY, 0, 9}, {15, 9}}, + {{TQEType::YZ, 0, 9}, {3, 9}}, {{TQEType::ZX, 0, 9}, {8, 9}}, + {{TQEType::ZY, 0, 9}, {10, 9}}, {{TQEType::ZZ, 0, 9}, {2, 9}}, + {{TQEType::XX, 1, 11}, {4, 11}}, {{TQEType::XY, 1, 11}, {5, 11}}, + {{TQEType::XZ, 1, 11}, {0, 11}}, {{TQEType::YX, 1, 11}, {14, 10}}, + {{TQEType::YY, 1, 11}, {13, 8}}, {{TQEType::YZ, 1, 11}, {2, 9}}, + {{TQEType::ZX, 1, 11}, {11, 10}}, {{TQEType::ZY, 1, 11}, {9, 8}}, + {{TQEType::ZZ, 1, 11}, {3, 9}}, {{TQEType::XX, 3, 11}, {6, 10}}, + {{TQEType::XY, 3, 11}, {7, 8}}, {{TQEType::XZ, 3, 11}, {2, 9}}, + {{TQEType::YX, 3, 11}, {12, 11}}, {{TQEType::YY, 3, 11}, {15, 11}}, + {{TQEType::YZ, 3, 11}, {0, 11}}, {{TQEType::ZX, 3, 11}, {9, 10}}, + {{TQEType::ZY, 3, 11}, {11, 8}}, {{TQEType::ZZ, 3, 11}, {1, 9}}, + {{TQEType::XX, 2, 11}, {7, 10}}, {{TQEType::XY, 2, 11}, {6, 8}}, + {{TQEType::XZ, 2, 11}, {3, 9}}, {{TQEType::YX, 2, 11}, {13, 10}}, + {{TQEType::YY, 2, 11}, {14, 8}}, {{TQEType::YZ, 2, 11}, {1, 9}}, + {{TQEType::ZX, 2, 11}, {8, 11}}, {{TQEType::ZY, 2, 11}, {10, 11}}, + {{TQEType::ZZ, 2, 11}, {0, 11}}, {{TQEType::XX, 0, 11}, {5, 11}}, + {{TQEType::XY, 0, 11}, {4, 11}}, {{TQEType::XZ, 0, 11}, {1, 11}}, + {{TQEType::YX, 0, 11}, {15, 11}}, {{TQEType::YY, 0, 11}, {12, 11}}, + {{TQEType::YZ, 0, 11}, {3, 11}}, {{TQEType::ZX, 0, 11}, {10, 11}}, + {{TQEType::ZY, 0, 11}, {8, 11}}, {{TQEType::ZZ, 0, 11}, {2, 11}}, + {{TQEType::XX, 1, 10}, {4, 10}}, {{TQEType::XY, 1, 10}, {4, 10}}, + {{TQEType::XZ, 1, 10}, {1, 10}}, {{TQEType::YX, 1, 10}, {14, 11}}, + {{TQEType::YY, 1, 10}, {14, 9}}, {{TQEType::YZ, 1, 10}, {1, 8}}, + {{TQEType::ZX, 1, 10}, {11, 11}}, {{TQEType::ZY, 1, 10}, {11, 9}}, + {{TQEType::ZZ, 1, 10}, {1, 8}}, {{TQEType::XX, 3, 10}, {6, 11}}, + {{TQEType::XY, 3, 10}, {6, 9}}, {{TQEType::XZ, 3, 10}, {3, 8}}, + {{TQEType::YX, 3, 10}, {12, 10}}, {{TQEType::YY, 3, 10}, {12, 10}}, + {{TQEType::YZ, 3, 10}, {3, 10}}, {{TQEType::ZX, 3, 10}, {9, 11}}, + {{TQEType::ZY, 3, 10}, {9, 9}}, {{TQEType::ZZ, 3, 10}, {3, 8}}, + {{TQEType::XX, 2, 10}, {7, 11}}, {{TQEType::XY, 2, 10}, {7, 9}}, + {{TQEType::XZ, 2, 10}, {2, 8}}, {{TQEType::YX, 2, 10}, {13, 11}}, + {{TQEType::YY, 2, 10}, {13, 9}}, {{TQEType::YZ, 2, 10}, {2, 8}}, + {{TQEType::ZX, 2, 10}, {8, 10}}, {{TQEType::ZY, 2, 10}, {8, 10}}, + {{TQEType::ZZ, 2, 10}, {2, 10}}, {{TQEType::XX, 0, 10}, {5, 10}}, + {{TQEType::XY, 0, 10}, {5, 10}}, {{TQEType::XZ, 0, 10}, {0, 10}}, + {{TQEType::YX, 0, 10}, {15, 10}}, {{TQEType::YY, 0, 10}, {15, 10}}, + {{TQEType::YZ, 0, 10}, {0, 10}}, {{TQEType::ZX, 0, 10}, {10, 10}}, + {{TQEType::ZY, 0, 10}, {10, 10}}, {{TQEType::ZZ, 0, 10}, {0, 10}}, + {{TQEType::XX, 1, 8}, {5, 8}}, {{TQEType::XY, 1, 8}, {5, 8}}, + {{TQEType::XZ, 1, 8}, {1, 8}}, {{TQEType::YX, 1, 8}, {13, 9}}, + {{TQEType::YY, 1, 8}, {13, 11}}, {{TQEType::YZ, 1, 8}, {1, 10}}, + {{TQEType::ZX, 1, 8}, {9, 9}}, {{TQEType::ZY, 1, 8}, {9, 11}}, + {{TQEType::ZZ, 1, 8}, {1, 10}}, {{TQEType::XX, 3, 8}, {7, 9}}, + {{TQEType::XY, 3, 8}, {7, 11}}, {{TQEType::XZ, 3, 8}, {3, 10}}, + {{TQEType::YX, 3, 8}, {15, 8}}, {{TQEType::YY, 3, 8}, {15, 8}}, + {{TQEType::YZ, 3, 8}, {3, 8}}, {{TQEType::ZX, 3, 8}, {11, 9}}, + {{TQEType::ZY, 3, 8}, {11, 11}}, {{TQEType::ZZ, 3, 8}, {3, 10}}, + {{TQEType::XX, 2, 8}, {6, 9}}, {{TQEType::XY, 2, 8}, {6, 11}}, + {{TQEType::XZ, 2, 8}, {2, 10}}, {{TQEType::YX, 2, 8}, {14, 9}}, + {{TQEType::YY, 2, 8}, {14, 11}}, {{TQEType::YZ, 2, 8}, {2, 10}}, + {{TQEType::ZX, 2, 8}, {10, 8}}, {{TQEType::ZY, 2, 8}, {10, 8}}, + {{TQEType::ZZ, 2, 8}, {2, 8}}, {{TQEType::XX, 0, 8}, {4, 8}}, + {{TQEType::XY, 0, 8}, {4, 8}}, {{TQEType::XZ, 0, 8}, {0, 8}}, + {{TQEType::YX, 0, 8}, {12, 8}}, {{TQEType::YY, 0, 8}, {12, 8}}, + {{TQEType::YZ, 0, 8}, {0, 8}}, {{TQEType::ZX, 0, 8}, {8, 8}}, + {{TQEType::ZY, 0, 8}, {8, 8}}, {{TQEType::ZZ, 0, 8}, {0, 8}}, + {{TQEType::XX, 7, 1}, {7, 0}}, {{TQEType::XY, 7, 1}, {6, 2}}, + {{TQEType::XZ, 7, 1}, {6, 3}}, {{TQEType::YX, 7, 1}, {7, 5}}, + {{TQEType::YY, 7, 1}, {4, 13}}, {{TQEType::YZ, 7, 1}, {4, 9}}, + {{TQEType::ZX, 7, 1}, {7, 4}}, {{TQEType::ZY, 7, 1}, {5, 14}}, + {{TQEType::ZZ, 7, 1}, {5, 11}}, {{TQEType::XX, 6, 1}, {6, 0}}, + {{TQEType::XY, 6, 1}, {7, 2}}, {{TQEType::XZ, 6, 1}, {7, 3}}, + {{TQEType::YX, 6, 1}, {6, 4}}, {{TQEType::YY, 6, 1}, {5, 14}}, + {{TQEType::YZ, 6, 1}, {5, 11}}, {{TQEType::ZX, 6, 1}, {6, 5}}, + {{TQEType::ZY, 6, 1}, {4, 13}}, {{TQEType::ZZ, 6, 1}, {4, 9}}, + {{TQEType::XX, 7, 3}, {6, 2}}, {{TQEType::XY, 7, 3}, {7, 0}}, + {{TQEType::XZ, 7, 3}, {6, 1}}, {{TQEType::YX, 7, 3}, {4, 7}}, + {{TQEType::YY, 7, 3}, {7, 15}}, {{TQEType::YZ, 7, 3}, {4, 11}}, + {{TQEType::ZX, 7, 3}, {5, 6}}, {{TQEType::ZY, 7, 3}, {7, 12}}, + {{TQEType::ZZ, 7, 3}, {5, 9}}, {{TQEType::XX, 6, 3}, {7, 2}}, + {{TQEType::XY, 6, 3}, {6, 0}}, {{TQEType::XZ, 6, 3}, {7, 1}}, + {{TQEType::YX, 6, 3}, {5, 6}}, {{TQEType::YY, 6, 3}, {6, 12}}, + {{TQEType::YZ, 6, 3}, {5, 9}}, {{TQEType::ZX, 6, 3}, {4, 7}}, + {{TQEType::ZY, 6, 3}, {6, 15}}, {{TQEType::ZZ, 6, 3}, {4, 11}}, + {{TQEType::XX, 7, 2}, {6, 3}}, {{TQEType::XY, 7, 2}, {6, 1}}, + {{TQEType::XZ, 7, 2}, {7, 0}}, {{TQEType::YX, 7, 2}, {4, 6}}, + {{TQEType::YY, 7, 2}, {4, 14}}, {{TQEType::YZ, 7, 2}, {7, 10}}, + {{TQEType::ZX, 7, 2}, {5, 7}}, {{TQEType::ZY, 7, 2}, {5, 13}}, + {{TQEType::ZZ, 7, 2}, {7, 8}}, {{TQEType::XX, 6, 2}, {7, 3}}, + {{TQEType::XY, 6, 2}, {7, 1}}, {{TQEType::XZ, 6, 2}, {6, 0}}, + {{TQEType::YX, 6, 2}, {5, 7}}, {{TQEType::YY, 6, 2}, {5, 13}}, + {{TQEType::YZ, 6, 2}, {6, 8}}, {{TQEType::ZX, 6, 2}, {4, 6}}, + {{TQEType::ZY, 6, 2}, {4, 14}}, {{TQEType::ZZ, 6, 2}, {6, 10}}, + {{TQEType::XX, 7, 0}, {7, 1}}, {{TQEType::XY, 7, 0}, {7, 3}}, + {{TQEType::XZ, 7, 0}, {7, 2}}, {{TQEType::YX, 7, 0}, {7, 4}}, + {{TQEType::YY, 7, 0}, {7, 12}}, {{TQEType::YZ, 7, 0}, {7, 8}}, + {{TQEType::ZX, 7, 0}, {7, 5}}, {{TQEType::ZY, 7, 0}, {7, 15}}, + {{TQEType::ZZ, 7, 0}, {7, 10}}, {{TQEType::XX, 6, 0}, {6, 1}}, + {{TQEType::XY, 6, 0}, {6, 3}}, {{TQEType::XZ, 6, 0}, {6, 2}}, + {{TQEType::YX, 6, 0}, {6, 5}}, {{TQEType::YY, 6, 0}, {6, 15}}, + {{TQEType::YZ, 6, 0}, {6, 10}}, {{TQEType::ZX, 6, 0}, {6, 4}}, + {{TQEType::ZY, 6, 0}, {6, 12}}, {{TQEType::ZZ, 6, 0}, {6, 8}}, + {{TQEType::XX, 5, 1}, {5, 1}}, {{TQEType::XY, 5, 1}, {4, 1}}, + {{TQEType::XZ, 5, 1}, {4, 1}}, {{TQEType::YX, 5, 1}, {5, 4}}, + {{TQEType::YY, 5, 1}, {6, 14}}, {{TQEType::YZ, 5, 1}, {6, 11}}, + {{TQEType::ZX, 5, 1}, {5, 4}}, {{TQEType::ZY, 5, 1}, {7, 14}}, + {{TQEType::ZZ, 5, 1}, {7, 11}}, {{TQEType::XX, 4, 1}, {4, 1}}, + {{TQEType::XY, 4, 1}, {5, 1}}, {{TQEType::XZ, 4, 1}, {5, 1}}, + {{TQEType::YX, 4, 1}, {4, 5}}, {{TQEType::YY, 4, 1}, {7, 13}}, + {{TQEType::YZ, 4, 1}, {7, 9}}, {{TQEType::ZX, 4, 1}, {4, 5}}, + {{TQEType::ZY, 4, 1}, {6, 13}}, {{TQEType::ZZ, 4, 1}, {6, 9}}, + {{TQEType::XX, 5, 3}, {4, 3}}, {{TQEType::XY, 5, 3}, {5, 3}}, + {{TQEType::XZ, 5, 3}, {4, 3}}, {{TQEType::YX, 5, 3}, {6, 6}}, + {{TQEType::YY, 5, 3}, {5, 12}}, {{TQEType::YZ, 5, 3}, {6, 9}}, + {{TQEType::ZX, 5, 3}, {7, 6}}, {{TQEType::ZY, 5, 3}, {5, 12}}, + {{TQEType::ZZ, 5, 3}, {7, 9}}, {{TQEType::XX, 4, 3}, {5, 3}}, + {{TQEType::XY, 4, 3}, {4, 3}}, {{TQEType::XZ, 4, 3}, {5, 3}}, + {{TQEType::YX, 4, 3}, {7, 7}}, {{TQEType::YY, 4, 3}, {4, 15}}, + {{TQEType::YZ, 4, 3}, {7, 11}}, {{TQEType::ZX, 4, 3}, {6, 7}}, + {{TQEType::ZY, 4, 3}, {4, 15}}, {{TQEType::ZZ, 4, 3}, {6, 11}}, + {{TQEType::XX, 5, 2}, {4, 2}}, {{TQEType::XY, 5, 2}, {4, 2}}, + {{TQEType::XZ, 5, 2}, {5, 2}}, {{TQEType::YX, 5, 2}, {6, 7}}, + {{TQEType::YY, 5, 2}, {6, 13}}, {{TQEType::YZ, 5, 2}, {5, 8}}, + {{TQEType::ZX, 5, 2}, {7, 7}}, {{TQEType::ZY, 5, 2}, {7, 13}}, + {{TQEType::ZZ, 5, 2}, {5, 8}}, {{TQEType::XX, 4, 2}, {5, 2}}, + {{TQEType::XY, 4, 2}, {5, 2}}, {{TQEType::XZ, 4, 2}, {4, 2}}, + {{TQEType::YX, 4, 2}, {7, 6}}, {{TQEType::YY, 4, 2}, {7, 14}}, + {{TQEType::YZ, 4, 2}, {4, 10}}, {{TQEType::ZX, 4, 2}, {6, 6}}, + {{TQEType::ZY, 4, 2}, {6, 14}}, {{TQEType::ZZ, 4, 2}, {4, 10}}, + {{TQEType::XX, 5, 0}, {5, 0}}, {{TQEType::XY, 5, 0}, {5, 0}}, + {{TQEType::XZ, 5, 0}, {5, 0}}, {{TQEType::YX, 5, 0}, {5, 5}}, + {{TQEType::YY, 5, 0}, {5, 15}}, {{TQEType::YZ, 5, 0}, {5, 10}}, + {{TQEType::ZX, 5, 0}, {5, 5}}, {{TQEType::ZY, 5, 0}, {5, 15}}, + {{TQEType::ZZ, 5, 0}, {5, 10}}, {{TQEType::XX, 4, 0}, {4, 0}}, + {{TQEType::XY, 4, 0}, {4, 0}}, {{TQEType::XZ, 4, 0}, {4, 0}}, + {{TQEType::YX, 4, 0}, {4, 4}}, {{TQEType::YY, 4, 0}, {4, 12}}, + {{TQEType::YZ, 4, 0}, {4, 8}}, {{TQEType::ZX, 4, 0}, {4, 4}}, + {{TQEType::ZY, 4, 0}, {4, 12}}, {{TQEType::ZZ, 4, 0}, {4, 8}}, + {{TQEType::XX, 13, 1}, {13, 5}}, {{TQEType::XY, 13, 1}, {12, 13}}, + {{TQEType::XZ, 13, 1}, {12, 9}}, {{TQEType::YX, 13, 1}, {13, 0}}, + {{TQEType::YY, 13, 1}, {14, 2}}, {{TQEType::YZ, 13, 1}, {14, 3}}, + {{TQEType::ZX, 13, 1}, {13, 4}}, {{TQEType::ZY, 13, 1}, {15, 14}}, + {{TQEType::ZZ, 13, 1}, {15, 11}}, {{TQEType::XX, 14, 1}, {14, 4}}, + {{TQEType::XY, 14, 1}, {15, 14}}, {{TQEType::XZ, 14, 1}, {15, 11}}, + {{TQEType::YX, 14, 1}, {14, 0}}, {{TQEType::YY, 14, 1}, {13, 2}}, + {{TQEType::YZ, 14, 1}, {13, 3}}, {{TQEType::ZX, 14, 1}, {14, 5}}, + {{TQEType::ZY, 14, 1}, {12, 13}}, {{TQEType::ZZ, 14, 1}, {12, 9}}, + {{TQEType::XX, 13, 3}, {12, 7}}, {{TQEType::XY, 13, 3}, {13, 15}}, + {{TQEType::XZ, 13, 3}, {12, 11}}, {{TQEType::YX, 13, 3}, {14, 2}}, + {{TQEType::YY, 13, 3}, {13, 0}}, {{TQEType::YZ, 13, 3}, {14, 1}}, + {{TQEType::ZX, 13, 3}, {15, 6}}, {{TQEType::ZY, 13, 3}, {13, 12}}, + {{TQEType::ZZ, 13, 3}, {15, 9}}, {{TQEType::XX, 14, 3}, {15, 6}}, + {{TQEType::XY, 14, 3}, {14, 12}}, {{TQEType::XZ, 14, 3}, {15, 9}}, + {{TQEType::YX, 14, 3}, {13, 2}}, {{TQEType::YY, 14, 3}, {14, 0}}, + {{TQEType::YZ, 14, 3}, {13, 1}}, {{TQEType::ZX, 14, 3}, {12, 7}}, + {{TQEType::ZY, 14, 3}, {14, 15}}, {{TQEType::ZZ, 14, 3}, {12, 11}}, + {{TQEType::XX, 13, 2}, {12, 6}}, {{TQEType::XY, 13, 2}, {12, 14}}, + {{TQEType::XZ, 13, 2}, {13, 10}}, {{TQEType::YX, 13, 2}, {14, 3}}, + {{TQEType::YY, 13, 2}, {14, 1}}, {{TQEType::YZ, 13, 2}, {13, 0}}, + {{TQEType::ZX, 13, 2}, {15, 7}}, {{TQEType::ZY, 13, 2}, {15, 13}}, + {{TQEType::ZZ, 13, 2}, {13, 8}}, {{TQEType::XX, 14, 2}, {15, 7}}, + {{TQEType::XY, 14, 2}, {15, 13}}, {{TQEType::XZ, 14, 2}, {14, 8}}, + {{TQEType::YX, 14, 2}, {13, 3}}, {{TQEType::YY, 14, 2}, {13, 1}}, + {{TQEType::YZ, 14, 2}, {14, 0}}, {{TQEType::ZX, 14, 2}, {12, 6}}, + {{TQEType::ZY, 14, 2}, {12, 14}}, {{TQEType::ZZ, 14, 2}, {14, 10}}, + {{TQEType::XX, 13, 0}, {13, 4}}, {{TQEType::XY, 13, 0}, {13, 12}}, + {{TQEType::XZ, 13, 0}, {13, 8}}, {{TQEType::YX, 13, 0}, {13, 1}}, + {{TQEType::YY, 13, 0}, {13, 3}}, {{TQEType::YZ, 13, 0}, {13, 2}}, + {{TQEType::ZX, 13, 0}, {13, 5}}, {{TQEType::ZY, 13, 0}, {13, 15}}, + {{TQEType::ZZ, 13, 0}, {13, 10}}, {{TQEType::XX, 14, 0}, {14, 5}}, + {{TQEType::XY, 14, 0}, {14, 15}}, {{TQEType::XZ, 14, 0}, {14, 10}}, + {{TQEType::YX, 14, 0}, {14, 1}}, {{TQEType::YY, 14, 0}, {14, 3}}, + {{TQEType::YZ, 14, 0}, {14, 2}}, {{TQEType::ZX, 14, 0}, {14, 4}}, + {{TQEType::ZY, 14, 0}, {14, 12}}, {{TQEType::ZZ, 14, 0}, {14, 8}}, + {{TQEType::XX, 15, 1}, {15, 4}}, {{TQEType::XY, 15, 1}, {14, 14}}, + {{TQEType::XZ, 15, 1}, {14, 11}}, {{TQEType::YX, 15, 1}, {15, 1}}, + {{TQEType::YY, 15, 1}, {12, 1}}, {{TQEType::YZ, 15, 1}, {12, 1}}, + {{TQEType::ZX, 15, 1}, {15, 4}}, {{TQEType::ZY, 15, 1}, {13, 14}}, + {{TQEType::ZZ, 15, 1}, {13, 11}}, {{TQEType::XX, 12, 1}, {12, 5}}, + {{TQEType::XY, 12, 1}, {13, 13}}, {{TQEType::XZ, 12, 1}, {13, 9}}, + {{TQEType::YX, 12, 1}, {12, 1}}, {{TQEType::YY, 12, 1}, {15, 1}}, + {{TQEType::YZ, 12, 1}, {15, 1}}, {{TQEType::ZX, 12, 1}, {12, 5}}, + {{TQEType::ZY, 12, 1}, {14, 13}}, {{TQEType::ZZ, 12, 1}, {14, 9}}, + {{TQEType::XX, 15, 3}, {14, 6}}, {{TQEType::XY, 15, 3}, {15, 12}}, + {{TQEType::XZ, 15, 3}, {14, 9}}, {{TQEType::YX, 15, 3}, {12, 3}}, + {{TQEType::YY, 15, 3}, {15, 3}}, {{TQEType::YZ, 15, 3}, {12, 3}}, + {{TQEType::ZX, 15, 3}, {13, 6}}, {{TQEType::ZY, 15, 3}, {15, 12}}, + {{TQEType::ZZ, 15, 3}, {13, 9}}, {{TQEType::XX, 12, 3}, {13, 7}}, + {{TQEType::XY, 12, 3}, {12, 15}}, {{TQEType::XZ, 12, 3}, {13, 11}}, + {{TQEType::YX, 12, 3}, {15, 3}}, {{TQEType::YY, 12, 3}, {12, 3}}, + {{TQEType::YZ, 12, 3}, {15, 3}}, {{TQEType::ZX, 12, 3}, {14, 7}}, + {{TQEType::ZY, 12, 3}, {12, 15}}, {{TQEType::ZZ, 12, 3}, {14, 11}}, + {{TQEType::XX, 15, 2}, {14, 7}}, {{TQEType::XY, 15, 2}, {14, 13}}, + {{TQEType::XZ, 15, 2}, {15, 8}}, {{TQEType::YX, 15, 2}, {12, 2}}, + {{TQEType::YY, 15, 2}, {12, 2}}, {{TQEType::YZ, 15, 2}, {15, 2}}, + {{TQEType::ZX, 15, 2}, {13, 7}}, {{TQEType::ZY, 15, 2}, {13, 13}}, + {{TQEType::ZZ, 15, 2}, {15, 8}}, {{TQEType::XX, 12, 2}, {13, 6}}, + {{TQEType::XY, 12, 2}, {13, 14}}, {{TQEType::XZ, 12, 2}, {12, 10}}, + {{TQEType::YX, 12, 2}, {15, 2}}, {{TQEType::YY, 12, 2}, {15, 2}}, + {{TQEType::YZ, 12, 2}, {12, 2}}, {{TQEType::ZX, 12, 2}, {14, 6}}, + {{TQEType::ZY, 12, 2}, {14, 14}}, {{TQEType::ZZ, 12, 2}, {12, 10}}, + {{TQEType::XX, 15, 0}, {15, 5}}, {{TQEType::XY, 15, 0}, {15, 15}}, + {{TQEType::XZ, 15, 0}, {15, 10}}, {{TQEType::YX, 15, 0}, {15, 0}}, + {{TQEType::YY, 15, 0}, {15, 0}}, {{TQEType::YZ, 15, 0}, {15, 0}}, + {{TQEType::ZX, 15, 0}, {15, 5}}, {{TQEType::ZY, 15, 0}, {15, 15}}, + {{TQEType::ZZ, 15, 0}, {15, 10}}, {{TQEType::XX, 12, 0}, {12, 4}}, + {{TQEType::XY, 12, 0}, {12, 12}}, {{TQEType::XZ, 12, 0}, {12, 8}}, + {{TQEType::YX, 12, 0}, {12, 0}}, {{TQEType::YY, 12, 0}, {12, 0}}, + {{TQEType::YZ, 12, 0}, {12, 0}}, {{TQEType::ZX, 12, 0}, {12, 4}}, + {{TQEType::ZY, 12, 0}, {12, 12}}, {{TQEType::ZZ, 12, 0}, {12, 8}}, + {{TQEType::XX, 9, 1}, {9, 5}}, {{TQEType::XY, 9, 1}, {8, 13}}, + {{TQEType::XZ, 9, 1}, {8, 9}}, {{TQEType::YX, 9, 1}, {9, 4}}, + {{TQEType::YY, 9, 1}, {10, 14}}, {{TQEType::YZ, 9, 1}, {10, 11}}, + {{TQEType::ZX, 9, 1}, {9, 0}}, {{TQEType::ZY, 9, 1}, {11, 2}}, + {{TQEType::ZZ, 9, 1}, {11, 3}}, {{TQEType::XX, 11, 1}, {11, 4}}, + {{TQEType::XY, 11, 1}, {10, 14}}, {{TQEType::XZ, 11, 1}, {10, 11}}, + {{TQEType::YX, 11, 1}, {11, 5}}, {{TQEType::YY, 11, 1}, {8, 13}}, + {{TQEType::YZ, 11, 1}, {8, 9}}, {{TQEType::ZX, 11, 1}, {11, 0}}, + {{TQEType::ZY, 11, 1}, {9, 2}}, {{TQEType::ZZ, 11, 1}, {9, 3}}, + {{TQEType::XX, 9, 3}, {8, 7}}, {{TQEType::XY, 9, 3}, {9, 15}}, + {{TQEType::XZ, 9, 3}, {8, 11}}, {{TQEType::YX, 9, 3}, {10, 6}}, + {{TQEType::YY, 9, 3}, {9, 12}}, {{TQEType::YZ, 9, 3}, {10, 9}}, + {{TQEType::ZX, 9, 3}, {11, 2}}, {{TQEType::ZY, 9, 3}, {9, 0}}, + {{TQEType::ZZ, 9, 3}, {11, 1}}, {{TQEType::XX, 11, 3}, {10, 6}}, + {{TQEType::XY, 11, 3}, {11, 12}}, {{TQEType::XZ, 11, 3}, {10, 9}}, + {{TQEType::YX, 11, 3}, {8, 7}}, {{TQEType::YY, 11, 3}, {11, 15}}, + {{TQEType::YZ, 11, 3}, {8, 11}}, {{TQEType::ZX, 11, 3}, {9, 2}}, + {{TQEType::ZY, 11, 3}, {11, 0}}, {{TQEType::ZZ, 11, 3}, {9, 1}}, + {{TQEType::XX, 9, 2}, {8, 6}}, {{TQEType::XY, 9, 2}, {8, 14}}, + {{TQEType::XZ, 9, 2}, {9, 10}}, {{TQEType::YX, 9, 2}, {10, 7}}, + {{TQEType::YY, 9, 2}, {10, 13}}, {{TQEType::YZ, 9, 2}, {9, 8}}, + {{TQEType::ZX, 9, 2}, {11, 3}}, {{TQEType::ZY, 9, 2}, {11, 1}}, + {{TQEType::ZZ, 9, 2}, {9, 0}}, {{TQEType::XX, 11, 2}, {10, 7}}, + {{TQEType::XY, 11, 2}, {10, 13}}, {{TQEType::XZ, 11, 2}, {11, 8}}, + {{TQEType::YX, 11, 2}, {8, 6}}, {{TQEType::YY, 11, 2}, {8, 14}}, + {{TQEType::YZ, 11, 2}, {11, 10}}, {{TQEType::ZX, 11, 2}, {9, 3}}, + {{TQEType::ZY, 11, 2}, {9, 1}}, {{TQEType::ZZ, 11, 2}, {11, 0}}, + {{TQEType::XX, 9, 0}, {9, 4}}, {{TQEType::XY, 9, 0}, {9, 12}}, + {{TQEType::XZ, 9, 0}, {9, 8}}, {{TQEType::YX, 9, 0}, {9, 5}}, + {{TQEType::YY, 9, 0}, {9, 15}}, {{TQEType::YZ, 9, 0}, {9, 10}}, + {{TQEType::ZX, 9, 0}, {9, 1}}, {{TQEType::ZY, 9, 0}, {9, 3}}, + {{TQEType::ZZ, 9, 0}, {9, 2}}, {{TQEType::XX, 11, 0}, {11, 5}}, + {{TQEType::XY, 11, 0}, {11, 15}}, {{TQEType::XZ, 11, 0}, {11, 10}}, + {{TQEType::YX, 11, 0}, {11, 4}}, {{TQEType::YY, 11, 0}, {11, 12}}, + {{TQEType::YZ, 11, 0}, {11, 8}}, {{TQEType::ZX, 11, 0}, {11, 1}}, + {{TQEType::ZY, 11, 0}, {11, 3}}, {{TQEType::ZZ, 11, 0}, {11, 2}}, + {{TQEType::XX, 10, 1}, {10, 4}}, {{TQEType::XY, 10, 1}, {11, 14}}, + {{TQEType::XZ, 10, 1}, {11, 11}}, {{TQEType::YX, 10, 1}, {10, 4}}, + {{TQEType::YY, 10, 1}, {9, 14}}, {{TQEType::YZ, 10, 1}, {9, 11}}, + {{TQEType::ZX, 10, 1}, {10, 1}}, {{TQEType::ZY, 10, 1}, {8, 1}}, + {{TQEType::ZZ, 10, 1}, {8, 1}}, {{TQEType::XX, 8, 1}, {8, 5}}, + {{TQEType::XY, 8, 1}, {9, 13}}, {{TQEType::XZ, 8, 1}, {9, 9}}, + {{TQEType::YX, 8, 1}, {8, 5}}, {{TQEType::YY, 8, 1}, {11, 13}}, + {{TQEType::YZ, 8, 1}, {11, 9}}, {{TQEType::ZX, 8, 1}, {8, 1}}, + {{TQEType::ZY, 8, 1}, {10, 1}}, {{TQEType::ZZ, 8, 1}, {10, 1}}, + {{TQEType::XX, 10, 3}, {11, 6}}, {{TQEType::XY, 10, 3}, {10, 12}}, + {{TQEType::XZ, 10, 3}, {11, 9}}, {{TQEType::YX, 10, 3}, {9, 6}}, + {{TQEType::YY, 10, 3}, {10, 12}}, {{TQEType::YZ, 10, 3}, {9, 9}}, + {{TQEType::ZX, 10, 3}, {8, 3}}, {{TQEType::ZY, 10, 3}, {10, 3}}, + {{TQEType::ZZ, 10, 3}, {8, 3}}, {{TQEType::XX, 8, 3}, {9, 7}}, + {{TQEType::XY, 8, 3}, {8, 15}}, {{TQEType::XZ, 8, 3}, {9, 11}}, + {{TQEType::YX, 8, 3}, {11, 7}}, {{TQEType::YY, 8, 3}, {8, 15}}, + {{TQEType::YZ, 8, 3}, {11, 11}}, {{TQEType::ZX, 8, 3}, {10, 3}}, + {{TQEType::ZY, 8, 3}, {8, 3}}, {{TQEType::ZZ, 8, 3}, {10, 3}}, + {{TQEType::XX, 10, 2}, {11, 7}}, {{TQEType::XY, 10, 2}, {11, 13}}, + {{TQEType::XZ, 10, 2}, {10, 8}}, {{TQEType::YX, 10, 2}, {9, 7}}, + {{TQEType::YY, 10, 2}, {9, 13}}, {{TQEType::YZ, 10, 2}, {10, 8}}, + {{TQEType::ZX, 10, 2}, {8, 2}}, {{TQEType::ZY, 10, 2}, {8, 2}}, + {{TQEType::ZZ, 10, 2}, {10, 2}}, {{TQEType::XX, 8, 2}, {9, 6}}, + {{TQEType::XY, 8, 2}, {9, 14}}, {{TQEType::XZ, 8, 2}, {8, 10}}, + {{TQEType::YX, 8, 2}, {11, 6}}, {{TQEType::YY, 8, 2}, {11, 14}}, + {{TQEType::YZ, 8, 2}, {8, 10}}, {{TQEType::ZX, 8, 2}, {10, 2}}, + {{TQEType::ZY, 8, 2}, {10, 2}}, {{TQEType::ZZ, 8, 2}, {8, 2}}, + {{TQEType::XX, 10, 0}, {10, 5}}, {{TQEType::XY, 10, 0}, {10, 15}}, + {{TQEType::XZ, 10, 0}, {10, 10}}, {{TQEType::YX, 10, 0}, {10, 5}}, + {{TQEType::YY, 10, 0}, {10, 15}}, {{TQEType::YZ, 10, 0}, {10, 10}}, + {{TQEType::ZX, 10, 0}, {10, 0}}, {{TQEType::ZY, 10, 0}, {10, 0}}, + {{TQEType::ZZ, 10, 0}, {10, 0}}, {{TQEType::XX, 8, 0}, {8, 4}}, + {{TQEType::XY, 8, 0}, {8, 12}}, {{TQEType::XZ, 8, 0}, {8, 8}}, + {{TQEType::YX, 8, 0}, {8, 4}}, {{TQEType::YY, 8, 0}, {8, 12}}, + {{TQEType::YZ, 8, 0}, {8, 8}}, {{TQEType::ZX, 8, 0}, {8, 0}}, + {{TQEType::ZY, 8, 0}, {8, 0}}, {{TQEType::ZZ, 8, 0}, {8, 0}}, + {{TQEType::XX, 1, 1}, {1, 1}}, {{TQEType::XY, 1, 1}, {0, 1}}, + {{TQEType::XZ, 1, 1}, {0, 1}}, {{TQEType::YX, 1, 1}, {1, 0}}, + {{TQEType::YY, 1, 1}, {2, 2}}, {{TQEType::YZ, 1, 1}, {2, 3}}, + {{TQEType::ZX, 1, 1}, {1, 0}}, {{TQEType::ZY, 1, 1}, {3, 2}}, + {{TQEType::ZZ, 1, 1}, {3, 3}}, {{TQEType::XX, 3, 1}, {3, 0}}, + {{TQEType::XY, 3, 1}, {2, 2}}, {{TQEType::XZ, 3, 1}, {2, 3}}, + {{TQEType::YX, 3, 1}, {3, 1}}, {{TQEType::YY, 3, 1}, {0, 1}}, + {{TQEType::YZ, 3, 1}, {0, 1}}, {{TQEType::ZX, 3, 1}, {3, 0}}, + {{TQEType::ZY, 3, 1}, {1, 2}}, {{TQEType::ZZ, 3, 1}, {1, 3}}, + {{TQEType::XX, 2, 1}, {2, 0}}, {{TQEType::XY, 2, 1}, {3, 2}}, + {{TQEType::XZ, 2, 1}, {3, 3}}, {{TQEType::YX, 2, 1}, {2, 0}}, + {{TQEType::YY, 2, 1}, {1, 2}}, {{TQEType::YZ, 2, 1}, {1, 3}}, + {{TQEType::ZX, 2, 1}, {2, 1}}, {{TQEType::ZY, 2, 1}, {0, 1}}, + {{TQEType::ZZ, 2, 1}, {0, 1}}, {{TQEType::XX, 0, 1}, {0, 1}}, + {{TQEType::XY, 0, 1}, {1, 1}}, {{TQEType::XZ, 0, 1}, {1, 1}}, + {{TQEType::YX, 0, 1}, {0, 1}}, {{TQEType::YY, 0, 1}, {3, 1}}, + {{TQEType::YZ, 0, 1}, {3, 1}}, {{TQEType::ZX, 0, 1}, {0, 1}}, + {{TQEType::ZY, 0, 1}, {2, 1}}, {{TQEType::ZZ, 0, 1}, {2, 1}}, + {{TQEType::XX, 1, 3}, {0, 3}}, {{TQEType::XY, 1, 3}, {1, 3}}, + {{TQEType::XZ, 1, 3}, {0, 3}}, {{TQEType::YX, 1, 3}, {2, 2}}, + {{TQEType::YY, 1, 3}, {1, 0}}, {{TQEType::YZ, 1, 3}, {2, 1}}, + {{TQEType::ZX, 1, 3}, {3, 2}}, {{TQEType::ZY, 1, 3}, {1, 0}}, + {{TQEType::ZZ, 1, 3}, {3, 1}}, {{TQEType::XX, 3, 3}, {2, 2}}, + {{TQEType::XY, 3, 3}, {3, 0}}, {{TQEType::XZ, 3, 3}, {2, 1}}, + {{TQEType::YX, 3, 3}, {0, 3}}, {{TQEType::YY, 3, 3}, {3, 3}}, + {{TQEType::YZ, 3, 3}, {0, 3}}, {{TQEType::ZX, 3, 3}, {1, 2}}, + {{TQEType::ZY, 3, 3}, {3, 0}}, {{TQEType::ZZ, 3, 3}, {1, 1}}, + {{TQEType::XX, 2, 3}, {3, 2}}, {{TQEType::XY, 2, 3}, {2, 0}}, + {{TQEType::XZ, 2, 3}, {3, 1}}, {{TQEType::YX, 2, 3}, {1, 2}}, + {{TQEType::YY, 2, 3}, {2, 0}}, {{TQEType::YZ, 2, 3}, {1, 1}}, + {{TQEType::ZX, 2, 3}, {0, 3}}, {{TQEType::ZY, 2, 3}, {2, 3}}, + {{TQEType::ZZ, 2, 3}, {0, 3}}, {{TQEType::XX, 0, 3}, {1, 3}}, + {{TQEType::XY, 0, 3}, {0, 3}}, {{TQEType::XZ, 0, 3}, {1, 3}}, + {{TQEType::YX, 0, 3}, {3, 3}}, {{TQEType::YY, 0, 3}, {0, 3}}, + {{TQEType::YZ, 0, 3}, {3, 3}}, {{TQEType::ZX, 0, 3}, {2, 3}}, + {{TQEType::ZY, 0, 3}, {0, 3}}, {{TQEType::ZZ, 0, 3}, {2, 3}}, + {{TQEType::XX, 1, 2}, {0, 2}}, {{TQEType::XY, 1, 2}, {0, 2}}, + {{TQEType::XZ, 1, 2}, {1, 2}}, {{TQEType::YX, 1, 2}, {2, 3}}, + {{TQEType::YY, 1, 2}, {2, 1}}, {{TQEType::YZ, 1, 2}, {1, 0}}, + {{TQEType::ZX, 1, 2}, {3, 3}}, {{TQEType::ZY, 1, 2}, {3, 1}}, + {{TQEType::ZZ, 1, 2}, {1, 0}}, {{TQEType::XX, 3, 2}, {2, 3}}, + {{TQEType::XY, 3, 2}, {2, 1}}, {{TQEType::XZ, 3, 2}, {3, 0}}, + {{TQEType::YX, 3, 2}, {0, 2}}, {{TQEType::YY, 3, 2}, {0, 2}}, + {{TQEType::YZ, 3, 2}, {3, 2}}, {{TQEType::ZX, 3, 2}, {1, 3}}, + {{TQEType::ZY, 3, 2}, {1, 1}}, {{TQEType::ZZ, 3, 2}, {3, 0}}, + {{TQEType::XX, 2, 2}, {3, 3}}, {{TQEType::XY, 2, 2}, {3, 1}}, + {{TQEType::XZ, 2, 2}, {2, 0}}, {{TQEType::YX, 2, 2}, {1, 3}}, + {{TQEType::YY, 2, 2}, {1, 1}}, {{TQEType::YZ, 2, 2}, {2, 0}}, + {{TQEType::ZX, 2, 2}, {0, 2}}, {{TQEType::ZY, 2, 2}, {0, 2}}, + {{TQEType::ZZ, 2, 2}, {2, 2}}, {{TQEType::XX, 0, 2}, {1, 2}}, + {{TQEType::XY, 0, 2}, {1, 2}}, {{TQEType::XZ, 0, 2}, {0, 2}}, + {{TQEType::YX, 0, 2}, {3, 2}}, {{TQEType::YY, 0, 2}, {3, 2}}, + {{TQEType::YZ, 0, 2}, {0, 2}}, {{TQEType::ZX, 0, 2}, {2, 2}}, + {{TQEType::ZY, 0, 2}, {2, 2}}, {{TQEType::ZZ, 0, 2}, {0, 2}}, + {{TQEType::XX, 1, 0}, {1, 0}}, {{TQEType::XY, 1, 0}, {1, 0}}, + {{TQEType::XZ, 1, 0}, {1, 0}}, {{TQEType::YX, 1, 0}, {1, 1}}, + {{TQEType::YY, 1, 0}, {1, 3}}, {{TQEType::YZ, 1, 0}, {1, 2}}, + {{TQEType::ZX, 1, 0}, {1, 1}}, {{TQEType::ZY, 1, 0}, {1, 3}}, + {{TQEType::ZZ, 1, 0}, {1, 2}}, {{TQEType::XX, 3, 0}, {3, 1}}, + {{TQEType::XY, 3, 0}, {3, 3}}, {{TQEType::XZ, 3, 0}, {3, 2}}, + {{TQEType::YX, 3, 0}, {3, 0}}, {{TQEType::YY, 3, 0}, {3, 0}}, + {{TQEType::YZ, 3, 0}, {3, 0}}, {{TQEType::ZX, 3, 0}, {3, 1}}, + {{TQEType::ZY, 3, 0}, {3, 3}}, {{TQEType::ZZ, 3, 0}, {3, 2}}, + {{TQEType::XX, 2, 0}, {2, 1}}, {{TQEType::XY, 2, 0}, {2, 3}}, + {{TQEType::XZ, 2, 0}, {2, 2}}, {{TQEType::YX, 2, 0}, {2, 1}}, + {{TQEType::YY, 2, 0}, {2, 3}}, {{TQEType::YZ, 2, 0}, {2, 2}}, + {{TQEType::ZX, 2, 0}, {2, 0}}, {{TQEType::ZY, 2, 0}, {2, 0}}, + {{TQEType::ZZ, 2, 0}, {2, 0}}, {{TQEType::XX, 0, 0}, {0, 0}}, + {{TQEType::XY, 0, 0}, {0, 0}}, {{TQEType::XZ, 0, 0}, {0, 0}}, + {{TQEType::YX, 0, 0}, {0, 0}}, {{TQEType::YY, 0, 0}, {0, 0}}, + {{TQEType::YZ, 0, 0}, {0, 0}}, {{TQEType::ZX, 0, 0}, {0, 0}}, + {{TQEType::ZY, 0, 0}, {0, 0}}, {{TQEType::ZZ, 0, 0}, {0, 0}}}; + +/** + * @brief Maps a pair of week suppotrs in a factor support vector to a set of + * TQE gates that will transform them to a pair that only has one weak (not + * always possible) + */ +const static std::unordered_map< + std::pair, std::vector, hash_pair> + FACTOR_PAIR_WW_TO_WN_OR_NW_TQES = { + {{5, 5}, {TQEType::XY, TQEType::ZX, TQEType::YX, TQEType::XZ}}, + {{4, 5}, {}}, + {{5, 4}, {}}, + {{4, 4}, {TQEType::XY, TQEType::ZX, TQEType::YX, TQEType::XZ}}, + {{15, 5}, {TQEType::ZX, TQEType::YZ, TQEType::XX, TQEType::YY}}, + {{12, 5}, {}}, + {{15, 4}, {}}, + {{12, 4}, {TQEType::ZX, TQEType::YZ, TQEType::XX, TQEType::YY}}, + {{10, 5}, {TQEType::ZZ, TQEType::YX, TQEType::ZY, TQEType::XX}}, + {{8, 5}, {}}, + {{10, 4}, {}}, + {{8, 4}, {TQEType::ZZ, TQEType::YX, TQEType::ZY, TQEType::XX}}, + {{1, 5}, {}}, + {{3, 5}, {}}, + {{2, 5}, {}}, + {{1, 4}, {}}, + {{3, 4}, {}}, + {{2, 4}, {}}, + {{5, 15}, {TQEType::ZY, TQEType::XZ, TQEType::XX, TQEType::YY}}, + {{4, 15}, {}}, + {{5, 12}, {}}, + {{4, 12}, {TQEType::ZY, TQEType::XZ, TQEType::XX, TQEType::YY}}, + {{15, 15}, {TQEType::XY, TQEType::ZY, TQEType::YX, TQEType::YZ}}, + {{12, 15}, {}}, + {{15, 12}, {}}, + {{12, 12}, {TQEType::XY, TQEType::ZY, TQEType::YX, TQEType::YZ}}, + {{10, 15}, {TQEType::XY, TQEType::ZX, TQEType::ZZ, TQEType::YY}}, + {{8, 15}, {}}, + {{10, 12}, {}}, + {{8, 12}, {TQEType::XY, TQEType::ZX, TQEType::ZZ, TQEType::YY}}, + {{1, 15}, {}}, + {{3, 15}, {}}, + {{2, 15}, {}}, + {{1, 12}, {}}, + {{3, 12}, {}}, + {{2, 12}, {}}, + {{5, 10}, {TQEType::XY, TQEType::ZZ, TQEType::YZ, TQEType::XX}}, + {{4, 10}, {}}, + {{5, 8}, {}}, + {{4, 8}, {TQEType::XY, TQEType::ZZ, TQEType::YZ, TQEType::XX}}, + {{15, 10}, {TQEType::ZZ, TQEType::YX, TQEType::XZ, TQEType::YY}}, + {{12, 10}, {}}, + {{15, 8}, {}}, + {{12, 8}, {TQEType::ZZ, TQEType::YX, TQEType::XZ, TQEType::YY}}, + {{10, 10}, {TQEType::ZX, TQEType::YZ, TQEType::ZY, TQEType::XZ}}, + {{8, 10}, {}}, + {{10, 8}, {}}, + {{8, 8}, {TQEType::ZX, TQEType::YZ, TQEType::ZY, TQEType::XZ}}, + {{1, 10}, {}}, + {{3, 10}, {}}, + {{2, 10}, {}}, + {{1, 8}, {}}, + {{3, 8}, {}}, + {{2, 8}, {}}, + {{5, 1}, {}}, + {{4, 1}, {}}, + {{5, 3}, {}}, + {{4, 3}, {}}, + {{5, 2}, {}}, + {{4, 2}, {}}, + {{15, 1}, {}}, + {{12, 1}, {}}, + {{15, 3}, {}}, + {{12, 3}, {}}, + {{15, 2}, {}}, + {{12, 2}, {}}, + {{10, 1}, {}}, + {{8, 1}, {}}, + {{10, 3}, {}}, + {{8, 3}, {}}, + {{10, 2}, {}}, + {{8, 2}, {}}, + {{1, 1}, {TQEType::XY, TQEType::ZX, TQEType::YX, TQEType::XZ}}, + {{3, 1}, {TQEType::ZX, TQEType::YZ, TQEType::XX, TQEType::YY}}, + {{2, 1}, {TQEType::ZZ, TQEType::YX, TQEType::ZY, TQEType::XX}}, + {{1, 3}, {TQEType::ZY, TQEType::XZ, TQEType::XX, TQEType::YY}}, + {{3, 3}, {TQEType::XY, TQEType::ZY, TQEType::YX, TQEType::YZ}}, + {{2, 3}, {TQEType::XY, TQEType::ZX, TQEType::ZZ, TQEType::YY}}, + {{1, 2}, {TQEType::XY, TQEType::ZZ, TQEType::YZ, TQEType::XX}}, + {{3, 2}, {TQEType::ZZ, TQEType::YX, TQEType::XZ, TQEType::YY}}, + {{2, 2}, {TQEType::ZX, TQEType::YZ, TQEType::ZY, TQEType::XZ}}}; + +/** + * @brief Maps a pair of strong supports in a factor support vector + * to a set of TQE gates that will transform them to a pair of weak supports + */ +const static std::unordered_map< + std::pair, std::vector, hash_pair> + FACTOR_PAIR_SS_TO_WW_TQES = { + {{7, 7}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::ZX, TQEType::YZ, + TQEType::XZ}}, + {{6, 7}, + {TQEType::YX, TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::ZZ, + TQEType::XZ}}, + {{7, 6}, + {TQEType::YX, TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::ZZ, + TQEType::XZ}}, + {{6, 6}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::ZX, TQEType::YZ, + TQEType::XZ}}, + {{13, 7}, + {TQEType::ZY, TQEType::YY, TQEType::ZX, TQEType::YZ, TQEType::XZ, + TQEType::XX}}, + {{14, 7}, + {TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{13, 6}, + {TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{14, 6}, + {TQEType::ZY, TQEType::YY, TQEType::ZX, TQEType::YZ, TQEType::XZ, + TQEType::XX}}, + {{9, 7}, + {TQEType::YX, TQEType::ZY, TQEType::YY, TQEType::ZZ, TQEType::XZ, + TQEType::XX}}, + {{11, 7}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{9, 6}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{11, 6}, + {TQEType::YX, TQEType::ZY, TQEType::YY, TQEType::ZZ, TQEType::XZ, + TQEType::XX}}, + {{7, 13}, + {TQEType::ZY, TQEType::YY, TQEType::ZX, TQEType::YZ, TQEType::XZ, + TQEType::XX}}, + {{6, 13}, + {TQEType::YX, TQEType::ZY, TQEType::YY, TQEType::ZZ, TQEType::XZ, + TQEType::XX}}, + {{7, 14}, + {TQEType::YX, TQEType::ZY, TQEType::YY, TQEType::ZZ, TQEType::XZ, + TQEType::XX}}, + {{6, 14}, + {TQEType::ZY, TQEType::YY, TQEType::ZX, TQEType::YZ, TQEType::XZ, + TQEType::XX}}, + {{13, 13}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::ZX, TQEType::YZ, + TQEType::XZ}}, + {{14, 13}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{13, 14}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{14, 14}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::ZX, TQEType::YZ, + TQEType::XZ}}, + {{9, 13}, + {TQEType::YX, TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::ZZ, + TQEType::XZ}}, + {{11, 13}, + {TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{9, 14}, + {TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{11, 14}, + {TQEType::YX, TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::ZZ, + TQEType::XZ}}, + {{7, 9}, + {TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{6, 9}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{7, 11}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{6, 11}, + {TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::YZ, TQEType::ZZ, + TQEType::XX}}, + {{13, 9}, + {TQEType::YX, TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::ZZ, + TQEType::XZ}}, + {{14, 9}, + {TQEType::YX, TQEType::ZY, TQEType::YY, TQEType::ZZ, TQEType::XZ, + TQEType::XX}}, + {{13, 11}, + {TQEType::YX, TQEType::ZY, TQEType::YY, TQEType::ZZ, TQEType::XZ, + TQEType::XX}}, + {{14, 11}, + {TQEType::YX, TQEType::YY, TQEType::XY, TQEType::ZX, TQEType::ZZ, + TQEType::XZ}}, + {{9, 9}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::ZX, TQEType::YZ, + TQEType::XZ}}, + {{11, 9}, + {TQEType::ZY, TQEType::YY, TQEType::ZX, TQEType::YZ, TQEType::XZ, + TQEType::XX}}, + {{9, 11}, + {TQEType::ZY, TQEType::YY, TQEType::ZX, TQEType::YZ, TQEType::XZ, + TQEType::XX}}, + {{11, 11}, + {TQEType::YX, TQEType::ZY, TQEType::XY, TQEType::ZX, TQEType::YZ, + TQEType::XZ}}}; + +/** + * @brief Maps a strong support and a weak support in a factor support vector + * to a set of TQE gates that will transform the weak support to no support + */ +const static std::unordered_map< + std::pair, std::vector, hash_pair> + FACTOR_PAIR_SW_TO_SN_TQES = { + {{7, 5}, {TQEType::ZX}}, {{6, 5}, {TQEType::YX}}, + {{7, 4}, {TQEType::YX}}, {{6, 4}, {TQEType::ZX}}, + {{13, 5}, {TQEType::ZX}}, {{14, 5}, {TQEType::XX}}, + {{13, 4}, {TQEType::XX}}, {{14, 4}, {TQEType::ZX}}, + {{9, 5}, {TQEType::YX}}, {{11, 5}, {TQEType::XX}}, + {{9, 4}, {TQEType::XX}}, {{11, 4}, {TQEType::YX}}, + {{7, 15}, {TQEType::ZY}}, {{6, 15}, {TQEType::YY}}, + {{7, 12}, {TQEType::YY}}, {{6, 12}, {TQEType::ZY}}, + {{13, 15}, {TQEType::ZY}}, {{14, 15}, {TQEType::XY}}, + {{13, 12}, {TQEType::XY}}, {{14, 12}, {TQEType::ZY}}, + {{9, 15}, {TQEType::YY}}, {{11, 15}, {TQEType::XY}}, + {{9, 12}, {TQEType::XY}}, {{11, 12}, {TQEType::YY}}, + {{7, 10}, {TQEType::ZZ}}, {{6, 10}, {TQEType::YZ}}, + {{7, 8}, {TQEType::YZ}}, {{6, 8}, {TQEType::ZZ}}, + {{13, 10}, {TQEType::ZZ}}, {{14, 10}, {TQEType::XZ}}, + {{13, 8}, {TQEType::XZ}}, {{14, 8}, {TQEType::ZZ}}, + {{9, 10}, {TQEType::YZ}}, {{11, 10}, {TQEType::XZ}}, + {{9, 8}, {TQEType::XZ}}, {{11, 8}, {TQEType::YZ}}, + {{7, 1}, {TQEType::XX}}, {{6, 1}, {TQEType::XX}}, + {{7, 3}, {TQEType::XY}}, {{6, 3}, {TQEType::XY}}, + {{7, 2}, {TQEType::XZ}}, {{6, 2}, {TQEType::XZ}}, + {{13, 1}, {TQEType::YX}}, {{14, 1}, {TQEType::YX}}, + {{13, 3}, {TQEType::YY}}, {{14, 3}, {TQEType::YY}}, + {{13, 2}, {TQEType::YZ}}, {{14, 2}, {TQEType::YZ}}, + {{9, 1}, {TQEType::ZX}}, {{11, 1}, {TQEType::ZX}}, + {{9, 3}, {TQEType::ZY}}, {{11, 3}, {TQEType::ZY}}, + {{9, 2}, {TQEType::ZZ}}, {{11, 2}, {TQEType::ZZ}}}; + +} // namespace GreedyPauliSimp + +} // namespace Transforms + +} // namespace tket diff --git a/tket/include/tket/Transformations/Rebase.hpp b/tket/include/tket/Transformations/Rebase.hpp index 3eea674873..9bc011bd41 100644 --- a/tket/include/tket/Transformations/Rebase.hpp +++ b/tket/include/tket/Transformations/Rebase.hpp @@ -77,6 +77,10 @@ Transform rebase_TK(); // Singleqs: Rz, PhasedX Transform rebase_UMD(); +// Multiqs: AAMS +// Singleqs: GPI, GPI2 +Transform rebase_ionq(); + } // namespace Transforms } // namespace tket diff --git a/tket/include/tket/Transformations/Replacement.hpp b/tket/include/tket/Transformations/Replacement.hpp index 3018387424..f41a4ade07 100644 --- a/tket/include/tket/Transformations/Replacement.hpp +++ b/tket/include/tket/Transformations/Replacement.hpp @@ -54,7 +54,8 @@ Circuit CX_circ_from_multiq(const Op_ptr op); Circuit CX_ZX_circ_from_op(const Op_ptr op); /** - * Replace CnRy, CnX, CnZ, CnY with 2-qubit gates and single qubit gates + * Replace CnRy, CnRx, CnRz, CnX, CnZ, CnY with 2-qubit gates and single qubit + * gates * * @param op operation * @param two_q_type whether rebase 2-q gates to CX or TK2 diff --git a/tket/src/Architecture/DistancesFromArchitecture.cpp b/tket/src/Architecture/DistancesFromArchitecture.cpp index 412c777356..5c17a7917c 100644 --- a/tket/src/Architecture/DistancesFromArchitecture.cpp +++ b/tket/src/Architecture/DistancesFromArchitecture.cpp @@ -80,8 +80,8 @@ std::size_t DistancesFromArchitecture::operator()( distance_entry > 0 || AssertMessage() << "DistancesFromArchitecture: architecture has " << arch.n_nodes() << " vertices, " - << arch.n_connections() << " edges; " << " and d(" - << vertex1 << "," << vertex2 + << arch.n_connections() << " edges; " + << " and d(" << vertex1 << "," << vertex2 << ")=0. " "Is the graph connected?"); // GCOVR_EXCL_STOP diff --git a/tket/src/Circuit/CircPool.cpp b/tket/src/Circuit/CircPool.cpp index 1b9d84368f..d0a6a4e1c8 100644 --- a/tket/src/Circuit/CircPool.cpp +++ b/tket/src/Circuit/CircPool.cpp @@ -153,6 +153,20 @@ const Circuit &CX_using_XXPhase_1() { return *C; } +const Circuit &CX_using_AAMS() { + static std::unique_ptr C = std::make_unique([]() { + Circuit c(2); + c.add_op(OpType::GPI2, 0.5, {0}); + c.add_op(OpType::GPI2, 1, {0}); + c.add_op(OpType::GPI2, 1, {1}); + c.add_op(OpType::AAMS, {0.5, 0, 0}, {0, 1}); + c.add_op(OpType::GPI2, -0.5, {0}); + c.add_phase(-0.25); + return c; + }()); + return *C; +} + const Circuit &CX_VS_CX_reduced() { static std::unique_ptr C = std::make_unique([]() { Circuit c(2); @@ -1377,6 +1391,80 @@ Circuit tk1_to_PhasedXRz( return c; } +Circuit Rx_using_GPI(const Expr &theta) { + Circuit c(1); + c.add_op(OpType::GPI2, 0.5, {0}); + c.add_op(OpType::GPI, 0.5 * theta, {0}); + c.add_op(OpType::GPI, 0, {0}); + c.add_op(OpType::GPI2, -0.5, {0}); + return c; +} + +Circuit Ry_using_GPI(const Expr &theta) { + Circuit c(1); + c.add_op(OpType::GPI2, 1, {0}); + c.add_op(OpType::GPI, 0.5 * theta, {0}); + c.add_op(OpType::GPI, 0, {0}); + c.add_op(OpType::GPI2, 0, {0}); + return c; +} + +Circuit Rz_using_GPI(const Expr &theta) { + Circuit c(1); + c.add_op(OpType::GPI, -0.5 * theta, {0}); + c.add_op(OpType::GPI, 0, {0}); + return c; +} + +Circuit XXPhase_using_AAMS(const Expr &theta) { + Circuit c(2); + c.add_op(OpType::AAMS, {theta, 0, 0}, {0, 1}); + return c; +} + +Circuit YYPhase_using_AAMS(const Expr &theta) { + Circuit c(2); + c.add_op(OpType::AAMS, {theta, 0.5, 0.5}, {0, 1}); + return c; +} + +Circuit ZZPhase_using_AAMS(const Expr &theta) { + Circuit c(2); + c.add_op(OpType::GPI2, 0.5, {0}); + c.add_op(OpType::GPI2, 1, {0}); + c.add_op(OpType::GPI2, 1, {1}); + c.add_op(OpType::AAMS, {theta, 0, 0.5}, {0, 1}); + c.add_op(OpType::GPI2, 0, {1}); + c.add_op(OpType::GPI2, 0, {0}); + c.add_op(OpType::GPI2, -0.5, {0}); + return c; +} + +Circuit TK1_using_GPI(const Expr &alpha, const Expr &beta, const Expr &gamma) { + Circuit c(1); + c.add_op(OpType::GPI, 0, {0}); + c.add_op(OpType::GPI, 0.5 * gamma, {0}); + c.add_op(OpType::GPI2, 0.5, {0}); + c.add_op(OpType::GPI, 0.5 * beta, {0}); + c.add_op(OpType::GPI2, 0.5, {0}); + c.add_op(OpType::GPI, 0.5 * alpha, {0}); + return c; +} + +Circuit TK2_using_AAMS(const Expr &alpha, const Expr &beta, const Expr &gamma) { + Circuit c(2); + c.add_op(OpType::AAMS, {alpha, 0, 0}, {0, 1}); + c.add_op(OpType::AAMS, {beta, 0.5, 0.5}, {0, 1}); + c.add_op(OpType::GPI2, 0.5, {0}); + c.add_op(OpType::GPI2, 1, {0}); + c.add_op(OpType::GPI2, 1, {1}); + c.add_op(OpType::AAMS, {gamma, 0, 0.5}, {0, 1}); + c.add_op(OpType::GPI2, 0, {1}); + c.add_op(OpType::GPI2, 0, {0}); + c.add_op(OpType::GPI2, -0.5, {0}); + return c; +} + } // namespace CircPool } // namespace tket diff --git a/tket/src/Circuit/CircUtils.cpp b/tket/src/Circuit/CircUtils.cpp index fe23674bc5..c97cb45f26 100644 --- a/tket/src/Circuit/CircUtils.cpp +++ b/tket/src/Circuit/CircUtils.cpp @@ -622,6 +622,8 @@ Circuit with_CX(Gate_ptr op) { #define CNZTYPE(n) (((n) == 2) ? OpType::CZ : OpType::CnZ) #define CNYTYPE(n) (((n) == 2) ? OpType::CY : OpType::CnY) #define CNRYTYPE(n) (((n) == 2) ? OpType::CRy : OpType::CnRy) +#define CNRXTYPE(n) (((n) == 2) ? OpType::CRx : OpType::CnRx) +#define CNRZTYPE(n) (((n) == 2) ? OpType::CRz : OpType::CnRz) /** * Construct a circuit representing CnU1. */ @@ -692,12 +694,13 @@ static Circuit with_controls_symbolic(const Circuit &c, unsigned n_controls) { } static const OpTypeSet multiq_gate_set = { - OpType::CX, OpType::CCX, OpType::CnX, OpType::CRy, OpType::CnRy, - OpType::CZ, OpType::CnZ, OpType::CY, OpType::CnY}; + OpType::CX, OpType::CCX, OpType::CnX, OpType::CRy, + OpType::CnRy, OpType::CZ, OpType::CnZ, OpType::CY, + OpType::CnY, OpType::CnRx, OpType::CnRz}; unsigned c_n_qubits = c1.n_qubits(); - // 1. Rebase to {CX, CCX, CnX, CnRy} and single-qubit gates + // 1. Rebase to {CX, CCX, CnX, CnRy, CnRx, CnRz} and single-qubit gates VertexList bin; BGL_FORALL_VERTICES(v, c1.dag, DAG) { Op_ptr op = c1.get_Op_ptr_from_Vertex(v); @@ -778,6 +781,16 @@ static Circuit with_controls_symbolic(const Circuit &c, unsigned n_controls) { case OpType::CnRy: c2.add_op(CNRYTYPE(n_new_args), params, new_args); break; + case OpType::Rx: + case OpType::CRx: + case OpType::CnRx: + c2.add_op(CNRXTYPE(n_new_args), params, new_args); + break; + case OpType::Rz: + case OpType::CRz: + case OpType::CnRz: + c2.add_op(CNRZTYPE(n_new_args), params, new_args); + break; case OpType::Z: case OpType::CZ: case OpType::CnZ: @@ -843,6 +856,7 @@ static Eigen::Matrix2cd get_target_op_matrix(const Op_ptr &op) { return Gate(OpType::V, {}, 1).get_unitary(); case OpType::CVdg: return Gate(OpType::Vdg, {}, 1).get_unitary(); + case OpType::CnRx: case OpType::CRx: return Gate(OpType::Rx, op->get_params(), 1).get_unitary(); case OpType::CnRy: @@ -851,6 +865,7 @@ static Eigen::Matrix2cd get_target_op_matrix(const Op_ptr &op) { case OpType::CY: case OpType::CnY: return Gate(OpType::Y, {}, 1).get_unitary(); + case OpType::CnRz: case OpType::CRz: return Gate(OpType::Rz, op->get_params(), 1).get_unitary(); case OpType::CZ: @@ -1248,6 +1263,8 @@ Circuit with_controls(const Circuit &c, unsigned n_controls) { #undef CNZTYPE #undef CNYTYPE #undef CNRYTYPE +#undef CNRXTYPE +#undef CNRZTYPE std::tuple, Circuit> normalise_TK2_angles( Expr a, Expr b, Expr c) { diff --git a/tket/src/Circuit/ControlledGates.cpp b/tket/src/Circuit/ControlledGates.cpp index f06790914f..f1f648d7a4 100644 --- a/tket/src/Circuit/ControlledGates.cpp +++ b/tket/src/Circuit/ControlledGates.cpp @@ -804,6 +804,46 @@ Circuit CnRy_normal_decomp(const Op_ptr op, unsigned arity) { return rep; } +Circuit CnRz_normal_decomp(const Op_ptr op, unsigned arity) { + if (op->get_type() != OpType::CnRz) { + throw CircuitInvalidity("Operation not CnRz"); + } + OpDesc desc = op->get_desc(); + Expr angle = op->get_params()[0]; + Circuit cnry_circuit = + CnRy_normal_decomp(get_op_ptr(OpType::CnRy, angle), arity); + TKET_ASSERT(cnry_circuit.n_qubits() == arity); + // The target to the CnRy gate will be to the qubit indexed as arity-1 + // Therefore we add basis change Clifford gates to this qubit + Circuit rep(arity); + + rep.add_op(OpType::H, {arity - 1}); + rep.add_op(OpType::S, {arity - 1}); + rep.append(cnry_circuit); + rep.add_op(OpType::Sdg, {arity - 1}); + rep.add_op(OpType::H, {arity - 1}); + return rep; +} + +Circuit CnRx_normal_decomp(const Op_ptr op, unsigned arity) { + if (op->get_type() != OpType::CnRx) { + throw CircuitInvalidity("Operation not CnR"); + } + OpDesc desc = op->get_desc(); + Expr angle = op->get_params()[0]; + Circuit cnry_circuit = + CnRy_normal_decomp(get_op_ptr(OpType::CnRy, angle), arity); + TKET_ASSERT(cnry_circuit.n_qubits() == arity); + // The target to the CnRy gate will be to the qubit indexed as arity-1 + // Therefore we add basis change Clifford gates to this qubit + Circuit rep(arity); + + rep.add_op(OpType::S, {arity - 1}); + rep.append(cnry_circuit); + rep.add_op(OpType::Sdg, {arity - 1}); + return rep; +} + // decompose CnX gate using lemma 7.1 // `n` = no. of controls Circuit CnX_gray_decomp(unsigned n) { diff --git a/tket/src/Circuit/basic_circ_manip.cpp b/tket/src/Circuit/basic_circ_manip.cpp index d00d39f929..49749eb4a1 100644 --- a/tket/src/Circuit/basic_circ_manip.cpp +++ b/tket/src/Circuit/basic_circ_manip.cpp @@ -108,6 +108,10 @@ Vertex Circuit::add_op( } if (optype == OpType::CnRy && args.size() == 1) { return add_op(get_op_ptr(OpType::Ry, gate->get_params()), arg_ids); + } else if (optype == OpType::CnRx && args.size() == 1) { + return add_op(get_op_ptr(OpType::Rx, gate->get_params()), arg_ids); + } else if (optype == OpType::CnRz && args.size() == 1) { + return add_op(get_op_ptr(OpType::Rz, gate->get_params()), arg_ids); } else if (optype == OpType::CnX && args.size() == 1) { return add_op(get_op_ptr(OpType::X), arg_ids); } else if (optype == OpType::CnZ && args.size() == 1) { diff --git a/tket/src/Circuit/latex_drawing.cpp b/tket/src/Circuit/latex_drawing.cpp index bd47547283..2949db930f 100644 --- a/tket/src/Circuit/latex_drawing.cpp +++ b/tket/src/Circuit/latex_drawing.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include "tket/Circuit/Boxes.hpp" @@ -36,6 +37,8 @@ void add_latex_for_command(LatexContext& context, const Command& command) { unit_vector_t args = command.get_args(); const Op_ptr op = command.get_op_ptr(); switch (op->get_type()) { + case OpType::CnRz: + case OpType::CnRx: case OpType::CnRy: case OpType::CnX: case OpType::CnY: @@ -53,6 +56,16 @@ void add_latex_for_command(LatexContext& context, const Command& command) { << "\\gate{\\text{" << get_op_ptr(OpType::Ry, op->get_params())->get_name(true) << "}} & "; + } else if (op->get_type() == OpType::CnRx) { + lines.at(target_index).buffer + << "\\gate{\\text{" + << get_op_ptr(OpType::Rx, op->get_params())->get_name(true) + << "}} & "; + } else if (op->get_type() == OpType::CnRz) { + lines.at(target_index).buffer + << "\\gate{\\text{" + << get_op_ptr(OpType::Rz, op->get_params())->get_name(true) + << "}} & "; } else if (op->get_type() == OpType::CnX) { lines.at(target_index).buffer << "\\targ{} & "; } else if (op->get_type() == OpType::CnY) { @@ -287,14 +300,16 @@ std::string Circuit::to_latex_str() const { unsigned n_lines = lines.size(); line_ids.insert({qb, n_lines}); LineBufferInfo& line = *lines.emplace(lines.end()); - line.buffer << "\\lstick{" + qb.repr() + "} & "; + line.buffer << "\\lstick{" + + boost::replace_all_copy(qb.repr(), "_", "\\_") + "} & "; line.is_quantum = true; } for (const Bit& cb : this->all_bits()) { unsigned n_lines = lines.size(); line_ids.insert({cb, n_lines}); LineBufferInfo& line = *lines.emplace(lines.end()); - line.buffer << "\\lstick{" + cb.repr() + "} & "; + line.buffer << "\\lstick{" + + boost::replace_all_copy(cb.repr(), "_", "\\_") + "} & "; line.is_quantum = false; } diff --git a/tket/src/Circuit/macro_manipulation.cpp b/tket/src/Circuit/macro_manipulation.cpp index 4aeb715900..8b77cab4d5 100644 --- a/tket/src/Circuit/macro_manipulation.cpp +++ b/tket/src/Circuit/macro_manipulation.cpp @@ -484,6 +484,9 @@ void Circuit::_handle_interior( } Vertex v = circ.add_vertex(op_type_ptr); vmap[*vi] = v; + } else if (desc.is_barrier()) { + Vertex v = circ.add_vertex(op); + vmap[*vi] = v; } else { throw CircuitInvalidity( "Cannot dagger or transpose op: " + op->get_name()); diff --git a/tket/src/Clifford/UnitaryTableau.cpp b/tket/src/Clifford/UnitaryTableau.cpp index e73a1d1203..50a5dcc76c 100644 --- a/tket/src/Clifford/UnitaryTableau.cpp +++ b/tket/src/Clifford/UnitaryTableau.cpp @@ -715,16 +715,16 @@ std::ostream& operator<<(std::ostream& os, const UnitaryRevTableau& tab) { for (unsigned i = 0; i < nqs; ++i) { Qubit qi = tab.tab_.qubits_.right.at(i); os << tab.tab_.tab_.xmat.row(i) << " " << tab.tab_.tab_.zmat.row(i) - << " " << tab.tab_.tab_.phase(i) << "\t->\t" << "X@" << qi.repr() - << std::endl; + << " " << tab.tab_.tab_.phase(i) << "\t->\t" + << "X@" << qi.repr() << std::endl; } os << "--" << std::endl; for (unsigned i = 0; i < nqs; ++i) { Qubit qi = tab.tab_.qubits_.right.at(i); os << tab.tab_.tab_.xmat.row(i + nqs) << " " << tab.tab_.tab_.zmat.row(i + nqs) << " " - << tab.tab_.tab_.phase(i + nqs) << "\t->\t" << "Z@" << qi.repr() - << std::endl; + << tab.tab_.tab_.phase(i + nqs) << "\t->\t" + << "Z@" << qi.repr() << std::endl; } return os; } diff --git a/tket/src/Gate/Gate.cpp b/tket/src/Gate/Gate.cpp index 6dc93da255..5c6f24958d 100644 --- a/tket/src/Gate/Gate.cpp +++ b/tket/src/Gate/Gate.cpp @@ -110,6 +110,8 @@ Op_ptr Gate::dagger() const { case OpType::Rx: case OpType::PhaseGadget: case OpType::CnRy: + case OpType::CnRx: + case OpType::CnRz: case OpType::XXPhase: case OpType::YYPhase: case OpType::ZZPhase: @@ -215,6 +217,8 @@ Op_ptr Gate::transpose() const { case OpType::SXdg: case OpType::CRz: case OpType::CRx: + case OpType::CnRz: + case OpType::CnRx: case OpType::CU1: case OpType::U1: case OpType::Rz: @@ -438,7 +442,9 @@ std::optional Gate::is_identity() const { case OpType::CRy: case OpType::PhaseGadget: case OpType::ISWAP: - case OpType::CnRy: { + case OpType::CnRy: + case OpType::CnRx: + case OpType::CnRz: { return equiv_0(params[0], 4) ? 0. : notid; } case OpType::FSim: { @@ -575,6 +581,8 @@ bool Gate::has_symmetry(unsigned port1, unsigned port2) const { // n (+1) qubit gates case OpType::CnX: case OpType::CnY: + case OpType::CnRx: + case OpType::CnRz: case OpType::CnRy: { // symmetry on first n ports not on n+1 auto last_port = n_q - 1; @@ -863,6 +871,7 @@ std::optional Gate::commuting_basis(unsigned i) const { } case OpType::CZ: case OpType::CRz: + case OpType::CnRz: case OpType::CS: case OpType::CSdg: case OpType::CU1: @@ -901,6 +910,7 @@ std::optional Gate::commuting_basis(unsigned i) const { case OpType::CSX: case OpType::CSXdg: case OpType::CRx: + case OpType::CnRx: case OpType::CX: case OpType::CCX: case OpType::CnX: { diff --git a/tket/src/Gate/GateUnitaryMatrixComposites.cpp b/tket/src/Gate/GateUnitaryMatrixComposites.cpp index 1ab23a34de..e88736ce15 100644 --- a/tket/src/Gate/GateUnitaryMatrixComposites.cpp +++ b/tket/src/Gate/GateUnitaryMatrixComposites.cpp @@ -105,6 +105,17 @@ Eigen::MatrixXcd GateUnitaryMatrixImplementations::CnRy( Ry(alpha), number_of_qubits); } +Eigen::MatrixXcd GateUnitaryMatrixImplementations::CnRx( + unsigned int number_of_qubits, double alpha) { + return GateUnitaryMatrixUtils::get_multi_controlled_gate_dense_unitary( + Rx(alpha), number_of_qubits); +} +Eigen::MatrixXcd GateUnitaryMatrixImplementations::CnRz( + unsigned int number_of_qubits, double alpha) { + return GateUnitaryMatrixUtils::get_multi_controlled_gate_dense_unitary( + Rz(alpha), number_of_qubits); +} + Eigen::MatrixXcd GateUnitaryMatrixImplementations::CnX( unsigned int number_of_qubits) { return GateUnitaryMatrixUtils::get_multi_controlled_gate_dense_unitary( diff --git a/tket/src/Gate/GateUnitaryMatrixVariableQubits.cpp b/tket/src/Gate/GateUnitaryMatrixVariableQubits.cpp index d8902e5e3b..dea7ec852a 100644 --- a/tket/src/Gate/GateUnitaryMatrixVariableQubits.cpp +++ b/tket/src/Gate/GateUnitaryMatrixVariableQubits.cpp @@ -26,6 +26,8 @@ GateUnitaryMatrixVariableQubits::GateUnitaryMatrixVariableQubits( : op_type(op_type_), known_type(true), number_of_parameters(0) { switch (op_type) { case OpType::CnRy: + case OpType::CnRx: + case OpType::CnRz: // Fall through. case OpType::PhaseGadget: number_of_parameters = 1; @@ -71,6 +73,12 @@ Eigen::MatrixXcd GateUnitaryMatrixVariableQubits::get_dense_unitary( if (op_type == OpType::CnRy) { return GateUnitaryMatrixImplementations::CnRy( number_of_qubits, parameters[0]); + } else if (op_type == OpType::CnRx) { + return GateUnitaryMatrixImplementations::CnRx( + number_of_qubits, parameters[0]); + } else if (op_type == OpType::CnRz) { + return GateUnitaryMatrixImplementations::CnRz( + number_of_qubits, parameters[0]); } else { TKET_ASSERT(op_type == OpType::PhaseGadget); return GateUnitaryMatrixImplementations::PhaseGadget( diff --git a/tket/src/Gate/GateUnitarySparseMatrix.cpp b/tket/src/Gate/GateUnitarySparseMatrix.cpp index cf25f6bed2..549d28d51e 100644 --- a/tket/src/Gate/GateUnitarySparseMatrix.cpp +++ b/tket/src/Gate/GateUnitarySparseMatrix.cpp @@ -47,6 +47,12 @@ static OpType get_primitive_type(OpType type_without_controls) { case OpType::CnRy: return OpType::Ry; + case OpType::CnRx: + return OpType::Rx; + + case OpType::CnRz: + return OpType::Rz; + default: return OpType::noop; } diff --git a/tket/src/Mapping/BoxDecomposition.cpp b/tket/src/Mapping/BoxDecomposition.cpp index 1aae01c200..dc7f812789 100644 --- a/tket/src/Mapping/BoxDecomposition.cpp +++ b/tket/src/Mapping/BoxDecomposition.cpp @@ -53,7 +53,7 @@ bool BoxDecomposition::solve() { return true; } -BoxDecompositionRoutingMethod::BoxDecompositionRoutingMethod(){}; +BoxDecompositionRoutingMethod::BoxDecompositionRoutingMethod() {}; std::pair BoxDecompositionRoutingMethod::routing_method( MappingFrontier_ptr &mapping_frontier, diff --git a/tket/src/Mapping/LexiRouteRoutingMethod.cpp b/tket/src/Mapping/LexiRouteRoutingMethod.cpp index 16c3cdbab3..07ecafa8f6 100644 --- a/tket/src/Mapping/LexiRouteRoutingMethod.cpp +++ b/tket/src/Mapping/LexiRouteRoutingMethod.cpp @@ -17,7 +17,7 @@ namespace tket { LexiRouteRoutingMethod::LexiRouteRoutingMethod(unsigned _max_depth) - : max_depth_(_max_depth){}; + : max_depth_(_max_depth) {}; std::pair LexiRouteRoutingMethod::routing_method( MappingFrontier_ptr& mapping_frontier, diff --git a/tket/src/Mapping/RoutingMethodCircuit.cpp b/tket/src/Mapping/RoutingMethodCircuit.cpp index e5da4e4c7b..f2610eef79 100644 --- a/tket/src/Mapping/RoutingMethodCircuit.cpp +++ b/tket/src/Mapping/RoutingMethodCircuit.cpp @@ -23,7 +23,7 @@ RoutingMethodCircuit::RoutingMethodCircuit( unsigned _max_size, unsigned _max_depth) : route_subcircuit_(_route_subcircuit), max_size_(_max_size), - max_depth_(_max_depth){}; + max_depth_(_max_depth) {}; std::pair RoutingMethodCircuit::routing_method( MappingFrontier_ptr& mapping_frontier, diff --git a/tket/src/OpType/OpTypeFunctions.cpp b/tket/src/OpType/OpTypeFunctions.cpp index adb5cae654..5a564c3171 100644 --- a/tket/src/OpType/OpTypeFunctions.cpp +++ b/tket/src/OpType/OpTypeFunctions.cpp @@ -26,23 +26,29 @@ bool find_in_set(const OpType& val, const OpTypeSet& set) { const OpTypeSet& all_gate_types() { static const OpTypeSet optypes{ - OpType::Z, OpType::X, OpType::Y, OpType::S, - OpType::Sdg, OpType::T, OpType::Tdg, OpType::V, - OpType::Vdg, OpType::SX, OpType::SXdg, OpType::H, - OpType::Rx, OpType::Ry, OpType::Rz, OpType::U3, - OpType::U2, OpType::U1, OpType::TK1, OpType::CX, - OpType::CY, OpType::CZ, OpType::CH, OpType::CV, - OpType::CVdg, OpType::CSX, OpType::CSXdg, OpType::CS, - OpType::CSdg, OpType::CRz, OpType::CRx, OpType::CRy, - OpType::CU1, OpType::CU3, OpType::PhaseGadget, OpType::CCX, - OpType::SWAP, OpType::CSWAP, OpType::noop, OpType::Measure, - OpType::Reset, OpType::ECR, OpType::ISWAP, OpType::PhasedX, - OpType::ZZMax, OpType::XXPhase, OpType::YYPhase, OpType::ZZPhase, - OpType::CnRy, OpType::CnX, OpType::CnZ, OpType::CnY, - OpType::BRIDGE, OpType::Collapse, OpType::ESWAP, OpType::FSim, - OpType::Sycamore, OpType::ISWAPMax, OpType::PhasedISWAP, OpType::XXPhase3, - OpType::NPhasedX, OpType::TK2, OpType::Phase, OpType::GPI, - OpType::GPI2, OpType::AAMS}; + OpType::Z, OpType::X, OpType::Y, + OpType::S, OpType::Sdg, OpType::T, + OpType::Tdg, OpType::V, OpType::Vdg, + OpType::SX, OpType::SXdg, OpType::H, + OpType::Rx, OpType::Ry, OpType::Rz, + OpType::U3, OpType::U2, OpType::U1, + OpType::TK1, OpType::CX, OpType::CY, + OpType::CZ, OpType::CH, OpType::CV, + OpType::CVdg, OpType::CSX, OpType::CSXdg, + OpType::CS, OpType::CSdg, OpType::CRz, + OpType::CRx, OpType::CRy, OpType::CU1, + OpType::CU3, OpType::PhaseGadget, OpType::CCX, + OpType::SWAP, OpType::CSWAP, OpType::noop, + OpType::Measure, OpType::Reset, OpType::ECR, + OpType::ISWAP, OpType::PhasedX, OpType::ZZMax, + OpType::XXPhase, OpType::YYPhase, OpType::ZZPhase, + OpType::CnRx, OpType::CnRz, OpType::CnRy, + OpType::CnX, OpType::CnZ, OpType::CnY, + OpType::BRIDGE, OpType::Collapse, OpType::ESWAP, + OpType::FSim, OpType::Sycamore, OpType::ISWAPMax, + OpType::PhasedISWAP, OpType::XXPhase3, OpType::NPhasedX, + OpType::TK2, OpType::Phase, OpType::GPI, + OpType::GPI2, OpType::AAMS}; static std::unique_ptr gates = std::make_unique(optypes); return *gates; @@ -50,19 +56,20 @@ const OpTypeSet& all_gate_types() { const OpTypeSet& all_multi_qubit_types() { static const OpTypeSet optypes{ - OpType::CX, OpType::CY, OpType::CZ, - OpType::CH, OpType::CV, OpType::CVdg, - OpType::CSX, OpType::CSXdg, OpType::CS, - OpType::CSdg, OpType::CRz, OpType::CRx, - OpType::CRy, OpType::CU1, OpType::CU3, - OpType::PhaseGadget, OpType::CCX, OpType::SWAP, - OpType::CSWAP, OpType::ECR, OpType::ISWAP, - OpType::ZZMax, OpType::XXPhase, OpType::YYPhase, - OpType::ZZPhase, OpType::CnRy, OpType::CnX, - OpType::CnZ, OpType::CnY, OpType::BRIDGE, - OpType::ESWAP, OpType::FSim, OpType::Sycamore, - OpType::ISWAPMax, OpType::PhasedISWAP, OpType::XXPhase3, - OpType::NPhasedX, OpType::TK2, OpType::AAMS}; + OpType::CX, OpType::CY, OpType::CZ, + OpType::CH, OpType::CV, OpType::CVdg, + OpType::CSX, OpType::CSXdg, OpType::CS, + OpType::CSdg, OpType::CRz, OpType::CRx, + OpType::CRy, OpType::CU1, OpType::CU3, + OpType::PhaseGadget, OpType::CCX, OpType::SWAP, + OpType::CSWAP, OpType::ECR, OpType::ISWAP, + OpType::ZZMax, OpType::XXPhase, OpType::YYPhase, + OpType::ZZPhase, OpType::CnRx, OpType::CnRz, + OpType::CnRy, OpType::CnX, OpType::CnZ, + OpType::CnY, OpType::BRIDGE, OpType::ESWAP, + OpType::FSim, OpType::Sycamore, OpType::ISWAPMax, + OpType::PhasedISWAP, OpType::XXPhase3, OpType::NPhasedX, + OpType::TK2, OpType::AAMS}; static std::unique_ptr gates = std::make_unique(optypes); return *gates; @@ -120,8 +127,9 @@ const OpTypeSet& all_controlled_gate_types() { static const OpTypeSet optypes{ OpType::CX, OpType::CCX, OpType::CnX, OpType::CnZ, OpType::CnY, OpType::CSX, OpType::CSXdg, OpType::CS, OpType::CSdg, OpType::CV, - OpType::CVdg, OpType::CRx, OpType::CnRy, OpType::CRy, OpType::CY, - OpType::CRz, OpType::CZ, OpType::CH, OpType::CU1, OpType::CU3}; + OpType::CVdg, OpType::CRx, OpType::CnRx, OpType::CnRz, OpType::CnRy, + OpType::CRy, OpType::CY, OpType::CRz, OpType::CZ, OpType::CH, + OpType::CU1, OpType::CU3}; static std::unique_ptr gates = std::make_unique(optypes); return *gates; @@ -214,10 +222,11 @@ bool is_flowop_type(OpType optype) { bool is_rotation_type(OpType optype) { static const OpTypeSet rotation_gates = { - OpType::Rx, OpType::Ry, OpType::Rz, OpType::U1, - OpType::CnRy, OpType::CRz, OpType::CRx, OpType::CRy, - OpType::CU1, OpType::XXPhase, OpType::YYPhase, OpType::ZZPhase, - OpType::ESWAP, OpType::ISWAP, OpType::XXPhase3}; + OpType::Rx, OpType::Ry, OpType::Rz, OpType::U1, + OpType::CnRy, OpType::CnRx, OpType::CnRz, OpType::CRz, + OpType::CRx, OpType::CRy, OpType::CU1, OpType::XXPhase, + OpType::YYPhase, OpType::ZZPhase, OpType::ESWAP, OpType::ISWAP, + OpType::XXPhase3}; return find_in_set(optype, rotation_gates); } diff --git a/tket/src/OpType/OpTypeInfo.cpp b/tket/src/OpType/OpTypeInfo.cpp index a2605edd20..19e292bb70 100644 --- a/tket/src/OpType/OpTypeInfo.cpp +++ b/tket/src/OpType/OpTypeInfo.cpp @@ -123,6 +123,8 @@ const std::map& optypeinfo() { {OpType::XXPhase3, {"XXPhase3", "$R_{X_0X_1}R_{X_0X_2}R_{X_1X_2}$", {4}, tripleq}}, {OpType::CnRy, {"CnRy", "CnRy", {4}, std::nullopt}}, + {OpType::CnRx, {"CnRx", "CnRx", {4}, std::nullopt}}, + {OpType::CnRz, {"CnRz", "CnRz", {4}, std::nullopt}}, {OpType::CnX, {"CnX", "CnX", {}, std::nullopt}}, {OpType::CnZ, {"CnZ", "CnZ", {}, std::nullopt}}, {OpType::CnY, {"CnY", "CnY", {}, std::nullopt}}, diff --git a/tket/src/Placement/Placement.cpp b/tket/src/Placement/Placement.cpp index 53a7f4a299..41e1b1cfad 100644 --- a/tket/src/Placement/Placement.cpp +++ b/tket/src/Placement/Placement.cpp @@ -48,7 +48,7 @@ void fill_partial_mapping( } Placement::Placement(const Architecture& _architecture) - : architecture_(_architecture){}; + : architecture_(_architecture) {}; bool Placement::place( Circuit& circ_, std::shared_ptr compilation_map) const { diff --git a/tket/src/Predicates/CompilerPass.cpp b/tket/src/Predicates/CompilerPass.cpp index e6d3522f9d..6a709ab9ed 100644 --- a/tket/src/Predicates/CompilerPass.cpp +++ b/tket/src/Predicates/CompilerPass.cpp @@ -487,6 +487,10 @@ void from_json(const nlohmann::json& j, PassPtr& pp) { content.at("pauli_synth_strat").get(); CXConfigType cxc = content.at("cx_config").get(); pp = gen_pauli_exponentials(pss, cxc); + } else if (passname == "GreedyPauliSimp") { + double discount_rate = content.at("discount_rate").get(); + double depth_weight = content.at("depth_weight").get(); + pp = gen_greedy_pauli_simp(discount_rate, depth_weight); } else if (passname == "PauliSimp") { // SEQUENCE PASS - DESERIALIZABLE ONLY Transforms::PauliSynthStrat pss = diff --git a/tket/src/Predicates/PassGenerators.cpp b/tket/src/Predicates/PassGenerators.cpp index d75f48be49..2467796bcc 100644 --- a/tket/src/Predicates/PassGenerators.cpp +++ b/tket/src/Predicates/PassGenerators.cpp @@ -36,6 +36,7 @@ #include "tket/Transformations/CliffordResynthesis.hpp" #include "tket/Transformations/ContextualReduction.hpp" #include "tket/Transformations/Decomposition.hpp" +#include "tket/Transformations/GreedyPauliOptimisation.hpp" #include "tket/Transformations/OptimisationPass.hpp" #include "tket/Transformations/PauliOptimisation.hpp" #include "tket/Transformations/Rebase.hpp" @@ -811,6 +812,39 @@ PassPtr gen_synthesise_pauli_graph( return std::make_shared(seq); } +PassPtr gen_greedy_pauli_simp(double discount_rate, double depth_weight) { + Transform t = + Transforms::greedy_pauli_optimisation(discount_rate, depth_weight); + PredicatePtr ccontrol_pred = std::make_shared(); + PredicatePtr mid_pred = std::make_shared(); + OpTypeSet ins = {OpType::Z, OpType::X, OpType::Y, + OpType::S, OpType::Sdg, OpType::V, + OpType::Vdg, OpType::H, OpType::CX, + OpType::CY, OpType::CZ, OpType::SWAP, + OpType::Rz, OpType::Rx, OpType::Ry, + OpType::T, OpType::Tdg, OpType::ZZMax, + OpType::ZZPhase, OpType::PhaseGadget, OpType::XXPhase, + OpType::YYPhase, OpType::PauliExpBox, OpType::Measure, + OpType::PhasedX}; + PredicatePtr in_gates = std::make_shared(ins); + PredicatePtrMap precons{ + CompilationUnit::make_type_pair(ccontrol_pred), + CompilationUnit::make_type_pair(mid_pred), + CompilationUnit::make_type_pair(in_gates)}; + PredicateClassGuarantees g_postcons = { + {typeid(ConnectivityPredicate), Guarantee::Clear}, + {typeid(NoWireSwapsPredicate), Guarantee::Clear}}; + PostConditions postcon{{}, g_postcons, Guarantee::Preserve}; + + // record pass config + nlohmann::json j; + j["name"] = "GreedyPauliSimp"; + j["discount_rate"] = discount_rate; + j["depth_weight"] = depth_weight; + + return std::make_shared(precons, t, postcon, j); +} + PassPtr gen_special_UCC_synthesis( Transforms::PauliSynthStrat strat, CXConfigType cx_config) { Transform t = Transforms::special_UCC_synthesis(strat, cx_config); diff --git a/tket/src/Predicates/Predicates.cpp b/tket/src/Predicates/Predicates.cpp index eaa5f2cd82..e5a6207921 100644 --- a/tket/src/Predicates/Predicates.cpp +++ b/tket/src/Predicates/Predicates.cpp @@ -52,8 +52,7 @@ static std::string auto_name(const T&) { return predicate_name(typeid(T)); } -#define SET_PRED_NAME(a) \ - { typeid(a), #a } +#define SET_PRED_NAME(a) {typeid(a), #a} const std::string& predicate_name(std::type_index idx) { static const std::map predicate_names = { diff --git a/tket/src/Transformations/Decomposition.cpp b/tket/src/Transformations/Decomposition.cpp index 22a25376d1..9e431ffb24 100644 --- a/tket/src/Transformations/Decomposition.cpp +++ b/tket/src/Transformations/Decomposition.cpp @@ -1805,7 +1805,8 @@ Transform decomp_controlled_Rys() { Transform decomp_arbitrary_controlled_gates() { static const std::set cn_gate_set = { - OpType::CCX, OpType::CnX, OpType::CnRy, OpType::CnZ, OpType::CnY}; + OpType::CCX, OpType::CnX, OpType::CnRy, OpType::CnZ, + OpType::CnY, OpType::CnRx, OpType::CnRz}; std::set all_gates; std::copy( all_gate_types().begin(), all_gate_types().end(), diff --git a/tket/src/Transformations/GreedyPauliOptimisation.cpp b/tket/src/Transformations/GreedyPauliOptimisation.cpp new file mode 100644 index 0000000000..2fcc62a7c6 --- /dev/null +++ b/tket/src/Transformations/GreedyPauliOptimisation.cpp @@ -0,0 +1,947 @@ +// Copyright 2019-2024 Cambridge Quantum Computing +// +// 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 "tket/Transformations/GreedyPauliOptimisation.hpp" + +#include + +#include "tket/Circuit/PauliExpBoxes.hpp" +#include "tket/Converters/Converters.hpp" +#include "tket/OpType/OpType.hpp" +#include "tket/OpType/OpTypeInfo.hpp" +#include "tket/Ops/Op.hpp" +#include "tket/PauliGraph/PauliGraph.hpp" +#include "tket/Transformations/CliffordOptimisation.hpp" +#include "tket/Transformations/GreedyPauliOptimisationLookupTables.hpp" +#include "tket/Transformations/Transform.hpp" + +namespace tket { + +namespace Transforms { + +namespace GreedyPauliSimp { + +static void apply_tqe_to_circ(const TQE& tqe, Circuit& circ) { + auto [gate_type, a, b] = tqe; + switch (gate_type) { + case TQEType::XX: + circ.add_op(OpType::H, {a}); + circ.add_op(OpType::CX, {a, b}); + circ.add_op(OpType::H, {a}); + break; + case TQEType::XY: + circ.add_op(OpType::H, {a}); + circ.add_op(OpType::CY, {a, b}); + circ.add_op(OpType::H, {a}); + break; + case TQEType::XZ: + circ.add_op(OpType::CX, {b, a}); + break; + case TQEType::YX: + circ.add_op(OpType::H, {b}); + circ.add_op(OpType::CY, {b, a}); + circ.add_op(OpType::H, {b}); + break; + case TQEType::YY: + circ.add_op(OpType::V, {a}); + circ.add_op(OpType::CY, {a, b}); + circ.add_op(OpType::Vdg, {a}); + break; + case TQEType::YZ: + circ.add_op(OpType::CY, {b, a}); + break; + case TQEType::ZX: + circ.add_op(OpType::CX, {a, b}); + break; + case TQEType::ZY: + circ.add_op(OpType::CY, {a, b}); + break; + case TQEType::ZZ: + circ.add_op(OpType::CZ, {a, b}); + break; + } +} + +static void apply_tqe_to_tableau(const TQE& tqe, UnitaryRevTableau& tab) { + auto [gate_type, a_int, b_int] = tqe; + Qubit a(a_int); + Qubit b(b_int); + switch (gate_type) { + case TQEType::XX: + tab.apply_gate_at_end(OpType::H, {a}); + tab.apply_gate_at_end(OpType::CX, {a, b}); + tab.apply_gate_at_end(OpType::H, {a}); + break; + case TQEType::XY: + tab.apply_gate_at_end(OpType::H, {a}); + tab.apply_gate_at_end(OpType::CY, {a, b}); + tab.apply_gate_at_end(OpType::H, {a}); + break; + case TQEType::XZ: + tab.apply_gate_at_end(OpType::CX, {b, a}); + break; + case TQEType::YX: + tab.apply_gate_at_end(OpType::H, {b}); + tab.apply_gate_at_end(OpType::CY, {b, a}); + tab.apply_gate_at_end(OpType::H, {b}); + break; + case TQEType::YY: + tab.apply_gate_at_end(OpType::V, {a}); + tab.apply_gate_at_end(OpType::CY, {a, b}); + tab.apply_gate_at_end(OpType::Vdg, {a}); + break; + case TQEType::YZ: + tab.apply_gate_at_end(OpType::CY, {b, a}); + break; + case TQEType::ZX: + tab.apply_gate_at_end(OpType::CX, {a, b}); + break; + case TQEType::ZY: + tab.apply_gate_at_end(OpType::CY, {a, b}); + break; + case TQEType::ZZ: + tab.apply_gate_at_end(OpType::CZ, {a, b}); + break; + } +} + +PauliExpNode::PauliExpNode(std::vector support_vec, Expr theta) + : support_vec_(support_vec), theta_(theta) { + tqe_cost_ = support_vec_.size() - + std::count(support_vec_.begin(), support_vec_.end(), 0) - 1; +} + +int PauliExpNode::tqe_cost_increase(const TQE& tqe) const { + unsigned supp0 = support_vec_[std::get<1>(tqe)]; + unsigned supp1 = support_vec_[std::get<2>(tqe)]; + unsigned new_supp0, new_supp1; + std::tie(new_supp0, new_supp1) = + SINGLET_PAIR_TRANSFORMATION_MAP.at({std::get<0>(tqe), supp0, supp1}); + return (new_supp0 > 0) + (new_supp1 > 0) - (supp0 > 0) - (supp1 > 0); +} + +void PauliExpNode::update(const TQE& tqe) { + unsigned a = std::get<1>(tqe); + unsigned b = std::get<2>(tqe); + unsigned supp0 = support_vec_[a]; + unsigned supp1 = support_vec_[b]; + unsigned new_supp0, new_supp1; + std::tie(new_supp0, new_supp1) = + SINGLET_PAIR_TRANSFORMATION_MAP.at({std::get<0>(tqe), supp0, supp1}); + support_vec_[a] = new_supp0; + support_vec_[b] = new_supp1; + tqe_cost_ += (new_supp0 > 0) + (new_supp1 > 0) - (supp0 > 0) - (supp1 > 0); +} + +std::vector PauliExpNode::reduction_tqes() const { + std::vector tqes; + // qubits with support + std::vector sqs; + for (unsigned i = 0; i < support_vec_.size(); i++) { + if (support_vec_[i] > 0) sqs.push_back(i); + } + for (unsigned i = 0; i < sqs.size() - 1; i++) { + for (unsigned j = i + 1; j < sqs.size(); j++) { + std::vector tqe_types = SINGLET_PAIR_REDUCTION_TQES.at( + {support_vec_[sqs[i]], support_vec_[sqs[j]]}); + for (const TQEType& tt : tqe_types) { + tqes.push_back({tt, sqs[i], sqs[j]}); + } + } + } + return tqes; +} + +std::pair PauliExpNode::first_support() const { + for (unsigned i = 0; i < support_vec_.size(); i++) { + if (support_vec_[i] > 0) { + return {i, support_vec_[i]}; + } + } + // Should be impossible to reach here + TKET_ASSERT(false); +} + +TableauRowNode::TableauRowNode(std::vector support_vec) + : support_vec_(support_vec) { + n_weaks_ = 0; + n_strongs_ = 0; + for (const unsigned& supp : support_vec_) { + SupportType st = FACTOR_WEAKNESS_MAP.at(supp); + if (st == SupportType::Strong) { + n_strongs_++; + } else if (st == SupportType::Weak) { + n_weaks_++; + } + } + tqe_cost_ = static_cast(1.5 * (n_strongs_ - 1) + n_weaks_); +} + +int TableauRowNode::tqe_cost_increase(const TQE& tqe) const { + unsigned supp0 = support_vec_[std::get<1>(tqe)]; + unsigned supp1 = support_vec_[std::get<2>(tqe)]; + unsigned new_supp0, new_supp1; + std::tie(new_supp0, new_supp1) = + FACTOR_PAIR_TRANSFORMATION_MAP.at({std::get<0>(tqe), supp0, supp1}); + SupportType st_supp0 = FACTOR_WEAKNESS_MAP.at(supp0); + SupportType st_supp1 = FACTOR_WEAKNESS_MAP.at(supp1); + SupportType st_new_supp0 = FACTOR_WEAKNESS_MAP.at(new_supp0); + SupportType st_new_supp1 = FACTOR_WEAKNESS_MAP.at(new_supp1); + unsigned old_strongs = + (st_supp0 == SupportType::Strong) + (st_supp1 == SupportType::Strong); + unsigned old_weaks = + (st_supp0 == SupportType::Weak) + (st_supp1 == SupportType::Weak); + unsigned new_strongs = (st_new_supp0 == SupportType::Strong) + + (st_new_supp1 == SupportType::Strong); + unsigned new_weaks = + (st_new_supp0 == SupportType::Weak) + (st_new_supp1 == SupportType::Weak); + int strong_increase = new_strongs - old_strongs; + int weak_increase = new_weaks - old_weaks; + return static_cast(1.5 * strong_increase + weak_increase); +} + +void TableauRowNode::update(const TQE& tqe) { + unsigned a = std::get<1>(tqe); + unsigned b = std::get<2>(tqe); + unsigned supp0 = support_vec_[a]; + unsigned supp1 = support_vec_[b]; + unsigned new_supp0, new_supp1; + std::tie(new_supp0, new_supp1) = + FACTOR_PAIR_TRANSFORMATION_MAP.at({std::get<0>(tqe), supp0, supp1}); + support_vec_[a] = new_supp0; + support_vec_[b] = new_supp1; + SupportType st_supp0 = FACTOR_WEAKNESS_MAP.at(supp0); + SupportType st_supp1 = FACTOR_WEAKNESS_MAP.at(supp1); + SupportType st_new_supp0 = FACTOR_WEAKNESS_MAP.at(new_supp0); + SupportType st_new_supp1 = FACTOR_WEAKNESS_MAP.at(new_supp1); + unsigned old_strongs = + (st_supp0 == SupportType::Strong) + (st_supp1 == SupportType::Strong); + unsigned old_weaks = + (st_supp0 == SupportType::Weak) + (st_supp1 == SupportType::Weak); + unsigned new_strongs = (st_new_supp0 == SupportType::Strong) + + (st_new_supp1 == SupportType::Strong); + unsigned new_weaks = + (st_new_supp0 == SupportType::Weak) + (st_new_supp1 == SupportType::Weak); + n_strongs_ += new_strongs - old_strongs; + n_weaks_ += new_weaks - old_weaks; + tqe_cost_ = static_cast(1.5 * (n_strongs_ - 1) + n_weaks_); +} + +std::vector TableauRowNode::reduction_tqes() const { + std::vector tqes; + // qubits with support + std::vector sqs; + for (unsigned i = 0; i < support_vec_.size(); i++) { + if (support_vec_[i] > 0) sqs.push_back(i); + } + for (unsigned i = 0; i < sqs.size() - 1; i++) { + for (unsigned j = i + 1; j < sqs.size(); j++) { + std::vector tqe_types; + unsigned a = sqs[i]; + unsigned b = sqs[j]; + unsigned supp0 = support_vec_[a]; + unsigned supp1 = support_vec_[b]; + SupportType st_supp0 = FACTOR_WEAKNESS_MAP.at(supp0); + SupportType st_supp1 = FACTOR_WEAKNESS_MAP.at(supp1); + if (st_supp0 == SupportType::Strong) { + if (st_supp1 == SupportType::Strong) { + // TQEs that transform a SS pair to WW + tqe_types = FACTOR_PAIR_SS_TO_WW_TQES.at({supp0, supp1}); + } else { + // TQEs that transform a SW pair to a single strong + tqe_types = FACTOR_PAIR_SW_TO_SN_TQES.at({supp0, supp1}); + } + } else { + if (st_supp1 == SupportType::Strong) { + // TQEs that transform a WS pair to a single strong + tqe_types = FACTOR_PAIR_SW_TO_SN_TQES.at({supp1, supp0}); + // flip qubits + a = sqs[j]; + b = sqs[i]; + } else { + // TQEs that transform a WW pair to a single weak, not always + // possible + tqe_types = FACTOR_PAIR_WW_TO_WN_OR_NW_TQES.at({supp0, supp1}); + } + } + for (const TQEType& tt : tqe_types) { + tqes.push_back({tt, a, b}); + } + } + } + return tqes; +} + +std::pair TableauRowNode::first_support() const { + for (unsigned i = 0; i < support_vec_.size(); i++) { + if (support_vec_[i] > 0) { + return {i, support_vec_[i]}; + } + } + // Should be impossible to reach here + TKET_ASSERT(false); +} + +// return the sum of the cost increases on remaining tableau nodes +static double default_tableau_tqe_cost( + const std::vector& rows, + const std::vector& remaining_indices, const TQE& tqe) { + double cost = 0; + for (const unsigned& index : remaining_indices) { + cost += rows[index].tqe_cost_increase(tqe); + } + return cost; +} + +// return the weighted sum of the cost increases on remaining nodes +// we discount the weight after each set +static double default_pauliexp_tqe_cost( + const double discount_rate, + const std::vector>& rotation_sets, + const std::vector& rows, const TQE& tqe) { + double discount = 1 / (1 + discount_rate); + double weight = 1; + double exp_cost = 0; + double tab_cost = 0; + for (const std::vector& rotation_set : rotation_sets) { + for (const PauliExpNode& node : rotation_set) { + exp_cost += weight * node.tqe_cost_increase(tqe); + } + weight *= discount; + } + for (const TableauRowNode& node : rows) { + tab_cost += weight * node.tqe_cost_increase(tqe); + } + return exp_cost + tab_cost; +} + +// given a map from TQE to a vector of costs, select the one with the minimum +// weighted sum of minmax-normalised costs +static TQE minmax_selection( + const std::map>& tqe_candidates_cost, + const std::vector& weights) { + TKET_ASSERT(tqe_candidates_cost.size() > 0); + size_t n_costs = tqe_candidates_cost.begin()->second.size(); + TKET_ASSERT(n_costs == weights.size()); + // for each cost type, store its min and max + std::vector mins = tqe_candidates_cost.begin()->second; + std::vector maxs = tqe_candidates_cost.begin()->second; + for (const auto& pair : tqe_candidates_cost) { + TKET_ASSERT(pair.second.size() == n_costs); + for (unsigned cost_index = 0; cost_index < n_costs; cost_index++) { + if (pair.second[cost_index] < mins[cost_index]) { + mins[cost_index] = pair.second[cost_index]; + } + if (pair.second[cost_index] > maxs[cost_index]) { + maxs[cost_index] = pair.second[cost_index]; + } + } + } + // valid_indices stores the indices of the costs where min!=max + std::vector valid_indices; + for (unsigned cost_index = 0; cost_index < n_costs; cost_index++) { + if (mins[cost_index] != maxs[cost_index]) { + valid_indices.push_back(cost_index); + } + } + // if all have the same cost, return the first one + if (valid_indices.size() == 0) { + TQE min_tqe = tqe_candidates_cost.begin()->first; + return min_tqe; + } + // if only one cost variable, no need to normalise + if (valid_indices.size() == 1) { + auto it = tqe_candidates_cost.begin(); + double min_cost = it->second[valid_indices[0]]; + TQE min_tqe = it->first; + for (; it != tqe_candidates_cost.end(); it++) { + if (it->second[valid_indices[0]] < min_cost) { + min_tqe = it->first; + min_cost = it->second[valid_indices[0]]; + } + } + return min_tqe; + } + // find the tqe with the minimum normalised cost + auto it = tqe_candidates_cost.begin(); + double min_cost = 0; + TQE min_tqe = it->first; + // initialise min_cost + for (const auto& cost_index : valid_indices) { + min_cost += weights[cost_index] * + (it->second[cost_index] - mins[cost_index]) / + (maxs[cost_index] - mins[cost_index]); + } + it++; + // iterate all tqes + for (; it != tqe_candidates_cost.end(); it++) { + double cost = 0; + for (const auto& cost_index : valid_indices) { + cost += weights[cost_index] * + (it->second[cost_index] - mins[cost_index]) / + (maxs[cost_index] - mins[cost_index]); + } + if (cost < min_cost) { + min_cost = cost; + min_tqe = it->first; + } + } + return min_tqe; +} + +static TQE select_pauliexp_tqe( + const std::map>& tqe_candidates_cost, + double depth_weight) { + return minmax_selection(tqe_candidates_cost, {1, depth_weight}); +} + +static TQE select_tableau_tqe( + const std::map>& tqe_candidates_cost, + double depth_weight) { + return minmax_selection(tqe_candidates_cost, {1, depth_weight}); +} + +// simple struct that tracks the depth on each qubit +struct DepthTracker { + std::vector qubit_depth; + unsigned max_depth; + DepthTracker(unsigned n) : qubit_depth(n, 0), max_depth(0) {}; + + unsigned gate_depth(unsigned a, unsigned b) const { + return std::max(qubit_depth[a], qubit_depth[b]) + 1; + }; + void add_1q_gate(unsigned a) { + qubit_depth[a]++; + if (qubit_depth[a] > max_depth) { + max_depth = qubit_depth[a]; + } + }; + void add_2q_gate(unsigned a, unsigned b) { + unsigned new_gate_depth = gate_depth(a, b); + qubit_depth[a] = new_gate_depth; + qubit_depth[b] = new_gate_depth; + if (new_gate_depth > max_depth) { + max_depth = new_gate_depth; + } + }; +}; + +/** + * @brief Given a tableau that is identity up to local Cliffords, qubit + * permutation, and signs, transform it to exact identity and adding gates to + * a circuit + */ +static void tableau_cleanup( + std::vector& rows, UnitaryRevTableau& tab, Circuit& circ) { + // apply local Cliffords + for (const TableauRowNode& node : rows) { + unsigned q_index, supp; + std::tie(q_index, supp) = node.first_support(); + Qubit q(q_index); + std::vector local_cliffords = + FACTOR_STRONG_TO_LOCALS.at(supp); + for (const LocalCliffordType& lc : local_cliffords) { + switch (lc) { + case LocalCliffordType::H: + tab.apply_gate_at_end(OpType::H, {q}); + circ.add_op(OpType::H, {q}); + break; + case LocalCliffordType::S: + tab.apply_gate_at_end(OpType::S, {q}); + circ.add_op(OpType::S, {q}); + break; + case LocalCliffordType::V: + tab.apply_gate_at_end(OpType::V, {q}); + circ.add_op(OpType::V, {q}); + break; + } + } + } + // remove signs + for (const Qubit& q : circ.all_qubits()) { + if (cast_coeff(tab.get_xrow(q).coeff) != 1.) { + tab.apply_gate_at_end(OpType::Z, {q}); + circ.add_op(OpType::Z, {q}); + } + if (cast_coeff(tab.get_zrow(q).coeff) != 1.) { + tab.apply_gate_at_end(OpType::X, {q}); + circ.add_op(OpType::X, {q}); + } + } + // remove permutations + // 1. find perm + unsigned n_qubits = circ.n_qubits(); + std::vector perm(n_qubits); + for (unsigned i = 0; i < n_qubits; i++) { + QubitPauliMap z_row_string = tab.get_zrow(Qubit(i)).string; + for (auto it = z_row_string.begin(); it != z_row_string.end(); it++) { + if (it->second == Pauli::Z) { + perm[it->first.index()[0]] = i; + break; + } + } + } + // 2. traverse transpositions + std::unordered_set done; + for (unsigned k = 0; k < n_qubits; k++) { + if (done.find(k) != done.end()) { + continue; + } + unsigned head = k; + unsigned current = k; + unsigned next = perm[k]; + while (true) { + if (next == head) { + done.insert(current); + break; + } + // the SWAP gates will be later converted to wire swaps + tab.apply_gate_at_end(OpType::SWAP, {Qubit(current), Qubit(next)}); + circ.add_op(OpType::SWAP, {current, next}); + done.insert(current); + current = next; + next = perm[current]; + } + } +} + +/** + * @brief Synthesise a vector of TableauRowNode + */ +static void tableau_row_nodes_synthesis( + std::vector& rows, UnitaryRevTableau& tab, Circuit& circ, + double depth_weight, DepthTracker& depth_tracker) { + // only consider nodes with a non-zero cost + std::vector remaining_indices; + for (unsigned i = 0; i < rows.size(); i++) { + if (rows[i].tqe_cost() > 0) { + remaining_indices.push_back(i); + } + } + while (remaining_indices.size() != 0) { + // get nodes with min cost + std::vector min_nodes_indices = {remaining_indices[0]}; + unsigned min_cost = rows[remaining_indices[0]].tqe_cost(); + for (unsigned i = 1; i < remaining_indices.size(); i++) { + unsigned node_cost = rows[remaining_indices[i]].tqe_cost(); + if (node_cost == min_cost) { + min_nodes_indices.push_back(remaining_indices[i]); + } else if (node_cost < min_cost) { + min_nodes_indices = {remaining_indices[i]}; + min_cost = node_cost; + } + } + // for each node with min cost, find the list of tqe gates that can reduce + // its cost + std::set tqe_candidates; + TKET_ASSERT(min_nodes_indices.size() > 0); + for (const unsigned& index : min_nodes_indices) { + std::vector node_reducing_tqes = rows[index].reduction_tqes(); + tqe_candidates.insert( + node_reducing_tqes.begin(), node_reducing_tqes.end()); + } + // for each tqe we compute a vector of cost factors which will + // be combined to make the final decision. + // we currently only consider tqe_cost and gate_depth. + std::map> tqe_candidates_cost; + for (const TQE& tqe : tqe_candidates) { + tqe_candidates_cost.insert( + {tqe, + {default_tableau_tqe_cost(rows, remaining_indices, tqe), + static_cast(depth_tracker.gate_depth( + std::get<1>(tqe), std::get<2>(tqe)))}}); + } + TKET_ASSERT(tqe_candidates_cost.size() > 0); + // select the best one + TQE selected_tqe = select_tableau_tqe(tqe_candidates_cost, depth_weight); + // apply TQE + apply_tqe_to_circ(selected_tqe, circ); + apply_tqe_to_tableau(selected_tqe, tab); + // update depth tracker + depth_tracker.add_2q_gate( + std::get<1>(selected_tqe), std::get<2>(selected_tqe)); + // remove finished nodes + for (unsigned i = remaining_indices.size(); i-- > 0;) { + unsigned node_index = remaining_indices[i]; + rows[node_index].update(selected_tqe); + if (rows[node_index].tqe_cost() == 0) { + remaining_indices.erase(remaining_indices.begin() + i); + } + } + } + tableau_cleanup(rows, tab, circ); +} + +/** + * @brief Given a vector of sets of PauliExpNode, implement any node in the + * first set where the tqe_cost is zero. Remove implemented nodes and the first + * set if empty. + * + * @param rotation_sets + * @param tab + * @param circ + * @return true if the first set is now empty and removed + * @return false + */ +static bool consume_available_rotations( + std::vector>& rotation_sets, + UnitaryRevTableau& tab, Circuit& circ, DepthTracker& depth_tracker) { + std::vector bin; + if (rotation_sets.size() == 0) { + return false; + } + std::vector& first_set = rotation_sets[0]; + for (unsigned i = 0; i < first_set.size(); i++) { + PauliExpNode& node = first_set[i]; + if (node.tqe_cost() > 0) continue; + unsigned q_index, supp; + std::tie(q_index, supp) = node.first_support(); + Qubit q(q_index); + depth_tracker.add_1q_gate(q_index); + switch (supp) { + case 3: { + // we apply S gate only to the frame, then check the sign, then Sdg + // if + apply f.Sdg; circ.Ry(-a) + // if - apply f.Sdg; circ.Ry(a) + tab.apply_gate_at_end(OpType::S, {q}); + Complex x_coeff = + cast_coeff(tab.get_xrow(q).coeff); + tab.apply_gate_at_end(OpType::Sdg, {q}); + if (x_coeff == 1.) { + circ.add_op(OpType::Ry, -node.theta(), {q}); + } else { + circ.add_op(OpType::Ry, node.theta(), {q}); + } + break; + } + case 1: { + Complex z_coeff = + cast_coeff(tab.get_zrow(q).coeff); + if (z_coeff == 1.) { + circ.add_op(OpType::Rz, node.theta(), {q}); + } else { + circ.add_op(OpType::Rz, -node.theta(), {q}); + } + break; + } + case 2: { + Complex x_coeff = + cast_coeff(tab.get_xrow(q).coeff); + if (x_coeff == 1.) { + circ.add_op(OpType::Rx, node.theta(), {q}); + } else { + circ.add_op(OpType::Rx, -node.theta(), {q}); + } + break; + } + default: + // support can't be Pauli::I + TKET_ASSERT(false); + } + bin.push_back(i); + } + if (bin.size() == 0) return false; + // sort the bin so we remove elements from back to front + std::sort(bin.begin(), bin.end(), std::greater()); + for (const unsigned& index : bin) { + first_set.erase(first_set.begin() + index); + } + if (first_set.size() == 0) { + rotation_sets.erase(rotation_sets.begin()); + return true; + } + return false; +} + +/** + * @brief Synthesise a vector of unordered rotation sets + */ +static void pauli_exps_synthesis( + std::vector>& rotation_sets, + std::vector& rows, UnitaryRevTableau& tab, Circuit& circ, + double discount_rate, double depth_weight, DepthTracker& depth_tracker) { + while (true) { + while (consume_available_rotations( + rotation_sets, tab, circ, depth_tracker)); // do nothing + if (rotation_sets.size() == 0) break; + std::vector& first_set = rotation_sets[0]; + // get nodes with min cost + std::vector min_nodes_indices = {0}; + unsigned min_cost = first_set[0].tqe_cost(); + for (unsigned i = 1; i < first_set.size(); i++) { + unsigned node_cost = first_set[i].tqe_cost(); + if (node_cost == min_cost) { + min_nodes_indices.push_back(i); + } else if (node_cost < min_cost) { + min_nodes_indices = {i}; + min_cost = node_cost; + } + } + std::set tqe_candidates; + for (const unsigned& index : min_nodes_indices) { + std::vector node_reducing_tqes = first_set[index].reduction_tqes(); + tqe_candidates.insert( + node_reducing_tqes.begin(), node_reducing_tqes.end()); + } + // for each tqe we compute costs which might subject to normalisation + std::map> tqe_candidates_cost; + for (const TQE& tqe : tqe_candidates) { + tqe_candidates_cost.insert( + {tqe, + {default_pauliexp_tqe_cost(discount_rate, rotation_sets, rows, tqe), + static_cast(depth_tracker.gate_depth( + std::get<1>(tqe), std::get<2>(tqe)))}}); + } + // select the best one + TQE selected_tqe = select_pauliexp_tqe(tqe_candidates_cost, depth_weight); + // apply TQE + apply_tqe_to_circ(selected_tqe, circ); + apply_tqe_to_tableau(selected_tqe, tab); + depth_tracker.add_2q_gate( + std::get<1>(selected_tqe), std::get<2>(selected_tqe)); + for (std::vector& rotation_set : rotation_sets) { + for (PauliExpNode& node : rotation_set) { + node.update(selected_tqe); + } + } + for (TableauRowNode& row : rows) { + row.update(selected_tqe); + } + } +} + +// convert a Pauli exponential to a PauliExpNode +static PauliExpNode get_node_from_exp( + const std::vector& paulis, const Expr& theta, + const qubit_vector_t& args, unsigned n, const UnitaryTableau& forward_tab, + const UnitaryRevTableau& tab) { + std::map pauli_map; + for (unsigned i = 0; i < args.size(); i++) { + pauli_map.insert({args[i], paulis[i]}); + } + // this has the effect of bringing the final clifford + // forward past the Pauli exponential + SpPauliStabiliser pstab = + forward_tab.get_row_product(SpPauliStabiliser(pauli_map)); + Complex sign = cast_coeff(pstab.coeff); + + std::vector support_vec; + for (unsigned i = 0; i < n; i++) { + SpPauliStabiliser zrow = tab.get_zrow(Qubit(i)); + SpPauliStabiliser xrow = tab.get_xrow(Qubit(i)); + bool z_supp = !zrow.commutes_with(pstab); + bool x_supp = !xrow.commutes_with(pstab); + if (!z_supp && !x_supp) { + support_vec.push_back(0); + } else if (!z_supp && x_supp) { + support_vec.push_back(1); + } else if (z_supp && !x_supp) { + support_vec.push_back(2); + } else if (z_supp && x_supp) { + support_vec.push_back(3); + } + } + return PauliExpNode(support_vec, sign.real() * theta); +} + +// detect trivial pauli exps, if true then return the global phase +static std::pair is_trivial_pauliexp( + const std::vector& paulis, const Expr& theta) { + if (static_cast(std::count( + paulis.begin(), paulis.end(), Pauli::I)) == paulis.size()) { + // If all identity term + return {true, -theta / 2}; + } + if (equiv_0(theta, 2)) { + if (equiv_0(theta, 4)) { + return {true, 0}; + } else { + return {true, -1}; + } + } + return {false, 0}; +} + +Circuit greedy_pauli_graph_synthesis( + const Circuit& circ, double discount_rate, double depth_weight) { + // c is the circuit we are trying to build + Circuit c(circ.all_qubits(), circ.all_bits()); + std::optional name = circ.get_name(); + if (name != std::nullopt) { + c.set_name(name.value()); + } + c.add_phase(circ.get_phase()); + unit_map_t unit_map = c.flatten_registers(); + Circuit measure_circ(c.n_qubits(), c.n_bits()); + Circuit cliff(c.n_qubits()); + + // circuit used to iterate the original commands with flattened registers + Circuit circ_flat(circ); + circ_flat.flatten_registers(); + std::vector commands = circ_flat.get_commands(); + // extract the final clifford and the measurement circuits + for (const Command& cmd : commands) { + OpType optype = cmd.get_op_ptr()->get_type(); + switch (optype) { + case OpType::Measure: { + measure_circ.add_op(OpType::Measure, cmd.get_args()); + break; + } + default: { + if (optype == OpType::PauliExpBox || + optype == OpType::PauliExpPairBox || + optype == OpType::PauliExpCommutingSetBox) + break; + TKET_ASSERT(is_clifford_type(optype) && is_gate_type(optype)); + cliff.add_op(optype, cmd.get_args()); + } + } + } + std::vector> rotation_sets; + std::vector rows; + // use forward Tableau to update the paulis by commuting the tableau to the + // front + UnitaryTableau forward_tab = circuit_to_unitary_tableau(cliff); + // Tableau used for tracking Cliffords throughout the synthesis + // TODO: this can be potentially made redundant + UnitaryRevTableau tab = circuit_to_unitary_rev_tableau(cliff).dagger(); + unsigned n_qubits = c.n_qubits(); + // extract the Pauli exps + for (const Command& cmd : commands) { + OpType optype = cmd.get_op_ptr()->get_type(); + switch (optype) { + case OpType::PauliExpBox: { + const PauliExpBox& pbox = + static_cast(*cmd.get_op_ptr()); + const Expr phase = pbox.get_phase(); + const std::vector paulis = pbox.get_paulis(); + auto [trivial, global_phase] = is_trivial_pauliexp(paulis, phase); + if (trivial) { + c.add_phase(global_phase); + } else { + rotation_sets.push_back({get_node_from_exp( + paulis, phase, cmd.get_qubits(), n_qubits, forward_tab, tab)}); + } + break; + } + case OpType::PauliExpPairBox: { + const PauliExpPairBox& pbox = + static_cast(*cmd.get_op_ptr()); + const auto [paulis1, paulis2] = pbox.get_paulis_pair(); + const auto [phase1, phase2] = pbox.get_phase_pair(); + auto [trivial1, global_phase1] = is_trivial_pauliexp(paulis1, phase1); + auto [trivial2, global_phase2] = is_trivial_pauliexp(paulis2, phase2); + std::vector rotation_set; + if (trivial1) { + c.add_phase(global_phase1); + } else { + rotation_set.push_back(get_node_from_exp( + paulis1, phase1, cmd.get_qubits(), n_qubits, forward_tab, tab)); + } + if (trivial2) { + c.add_phase(global_phase2); + } else { + rotation_set.push_back(get_node_from_exp( + paulis2, phase2, cmd.get_qubits(), n_qubits, forward_tab, tab)); + } + if (!rotation_set.empty()) { + rotation_sets.push_back(rotation_set); + } + break; + } + case OpType::PauliExpCommutingSetBox: { + const PauliExpCommutingSetBox& pbox = + static_cast(*cmd.get_op_ptr()); + const std::vector gadgets = pbox.get_pauli_gadgets(); + std::vector rotation_set; + for (const SymPauliTensor& pt : gadgets) { + const std::vector paulis = pt.string; + const Expr phase = pt.coeff; + auto [trivial, global_phase] = is_trivial_pauliexp(paulis, phase); + if (trivial) { + c.add_phase(global_phase); + } else { + rotation_set.push_back(get_node_from_exp( + paulis, phase, cmd.get_qubits(), n_qubits, forward_tab, tab)); + } + } + if (rotation_set.size() > 0) { + rotation_sets.push_back(rotation_set); + } + break; + } + default: + break; + } + } + // add identity TableauRowNodes + for (unsigned i = 0; i < n_qubits; i++) { + std::vector support_vec; + // identity rows + std::map p; + std::map q; + for (unsigned j = 0; j < n_qubits; j++) { + if (j == i) { + p.insert({Qubit(j), Pauli::Z}); + q.insert({Qubit(j), Pauli::X}); + } else { + p.insert({Qubit(j), Pauli::I}); + q.insert({Qubit(j), Pauli::I}); + } + } + SpPauliStabiliser stab_p(p); + SpPauliStabiliser stab_q(q); + for (unsigned row_index = 0; row_index < n_qubits; row_index++) { + SpPauliStabiliser zrow = tab.get_zrow(Qubit(row_index)); + SpPauliStabiliser xrow = tab.get_xrow(Qubit(row_index)); + bool lpx = !xrow.commutes_with(stab_p); + bool lpz = !zrow.commutes_with(stab_p); + bool lqx = !xrow.commutes_with(stab_q); + bool lqz = !zrow.commutes_with(stab_q); + support_vec.push_back(8 * lpx + 4 * lpz + 2 * lqx + lqz); + } + rows.push_back(TableauRowNode(support_vec)); + } + DepthTracker depth_tracker(n_qubits); + // synthesise Pauli exps + pauli_exps_synthesis( + rotation_sets, rows, tab, c, discount_rate, depth_weight, depth_tracker); + // synthesise the tableau + tableau_row_nodes_synthesis(rows, tab, c, depth_weight, depth_tracker); + unit_map_t rev_unit_map; + for (const auto& pair : unit_map) { + rev_unit_map.insert({pair.second, pair.first}); + } + c.append(measure_circ); + c.rename_units(rev_unit_map); + c.replace_SWAPs(); + return c; +} + +} // namespace GreedyPauliSimp + +Transform greedy_pauli_optimisation(double discount_rate, double depth_weight) { + return Transform([discount_rate, depth_weight](Circuit& circ) { + synthesise_pauli_graph(PauliSynthStrat::Sets, CXConfigType::Snake) + .apply(circ); + circ = GreedyPauliSimp::greedy_pauli_graph_synthesis( + circ, discount_rate, depth_weight); + singleq_clifford_sweep().apply(circ); + return true; + }); +} + +} // namespace Transforms + +} // namespace tket diff --git a/tket/src/Transformations/Rebase.cpp b/tket/src/Transformations/Rebase.cpp index a6f62cff0a..497dc7452f 100644 --- a/tket/src/Transformations/Rebase.cpp +++ b/tket/src/Transformations/Rebase.cpp @@ -287,6 +287,14 @@ Transform rebase_UMD() { CircPool::CX_using_XXPhase_0(), CircPool::tk1_to_PhasedXRz); } +// Multiqs: AAMS +// Singleqs: GPI, GPI2 +Transform rebase_ionq() { + return rebase_factory( + {OpType::GPI, OpType::GPI2, OpType::AAMS}, CircPool::CX_using_AAMS(), + CircPool::TK1_using_GPI); +} + } // namespace Transforms } // namespace tket diff --git a/tket/src/Transformations/Replacement.cpp b/tket/src/Transformations/Replacement.cpp index ceda73f655..8c44674d7f 100644 --- a/tket/src/Transformations/Replacement.cpp +++ b/tket/src/Transformations/Replacement.cpp @@ -37,6 +37,12 @@ Circuit multi_controlled_to_2q( case OpType::CnRy: c = CircPool::CnRy_normal_decomp(op, n_qubits); break; + case OpType::CnRx: + c = CircPool::CnRx_normal_decomp(op, n_qubits); + break; + case OpType::CnRz: + c = CircPool::CnRz_normal_decomp(op, n_qubits); + break; case OpType::CnX: case OpType::CnZ: case OpType::CnY: @@ -87,6 +93,8 @@ Circuit TK2_circ_from_multiq(const Op_ptr op) { "Can only build replacement circuits for basic gates", desc.type()); switch (desc.type()) { case OpType::CnRy: + case OpType::CnRx: + case OpType::CnRz: case OpType::CnX: case OpType::CnZ: case OpType::CnY: @@ -110,6 +118,8 @@ Circuit CX_circ_from_multiq(const Op_ptr op) { "Can only build replacement circuits for basic gates", desc.type()); switch (desc.type()) { case OpType::CnRy: + case OpType::CnRx: + case OpType::CnRz: case OpType::CnX: case OpType::CnZ: case OpType::CnY: @@ -288,6 +298,8 @@ Circuit CX_ZX_circ_from_op(const Op_ptr op) { case OpType::ZZPhase: case OpType::YYPhase: case OpType::CnRy: + case OpType::CnRx: + case OpType::CnRz: case OpType::CnX: case OpType::ESWAP: case OpType::FSim: diff --git a/tket/test/CMakeLists.txt b/tket/test/CMakeLists.txt index 65cf8824ef..ecfa0dd601 100644 --- a/tket/test/CMakeLists.txt +++ b/tket/test/CMakeLists.txt @@ -169,6 +169,7 @@ add_executable(test-tket src/test_SteinerForest.cpp src/test_wasm.cpp src/test_RoundAngles.cpp + src/test_GreedyPauli.cpp src/ZX/test_ZXDiagram.cpp src/ZX/test_ZXAxioms.cpp src/ZX/test_ZXSimp.cpp diff --git a/tket/test/src/Circuit/test_Boxes.cpp b/tket/test/src/Circuit/test_Boxes.cpp index bfaed1f186..d60824782e 100644 --- a/tket/test/src/Circuit/test_Boxes.cpp +++ b/tket/test/src/Circuit/test_Boxes.cpp @@ -933,17 +933,22 @@ SCENARIO("QControlBox", "[boxes]") { REQUIRE(*c == d); } - GIVEN("controlled phase_gadget") { + GIVEN("controlled phase_gadget, numerical") { Expr a; - WHEN("numerical") { a = 0.3; } - WHEN("symbolic") { - Sym s = SymEngine::symbol("a"); - a = Expr(s); - } + a = 0.3; QControlBox qbox(get_op_ptr(OpType::PhaseGadget, {a}, 2)); std::shared_ptr c = qbox.to_circuit(); REQUIRE(c->count_gates(OpType::CX) == 4); } + GIVEN("controlled phase_gadget, symbolic") { + Expr a; + Sym s = SymEngine::symbol("a"); + a = Expr(s); + QControlBox qbox(get_op_ptr(OpType::PhaseGadget, {a}, 2)); + std::shared_ptr c = qbox.to_circuit(); + REQUIRE(c->count_gates(OpType::CX) == 2); + REQUIRE(c->count_gates(OpType::CRz) == 1); + } GIVEN("controlled PauliExpBox") { // https://github.com/CQCL/tket/issues/1109 PauliExpBox pbox( diff --git a/tket/test/src/Circuit/test_Circ.cpp b/tket/test/src/Circuit/test_Circ.cpp index a59d77692e..d1724bdd13 100644 --- a/tket/test/src/Circuit/test_Circ.cpp +++ b/tket/test/src/Circuit/test_Circ.cpp @@ -37,6 +37,7 @@ #include "tket/Transformations/Replacement.hpp" #include "tket/Transformations/Transform.hpp" #include "tket/Utils/MatrixAnalysis.hpp" +#include "tket/Utils/UnitID.hpp" namespace tket { namespace test_Circ { @@ -1498,6 +1499,19 @@ SCENARIO("Test circuit.transpose() method") { REQUIRE(matrices_are_equal(ubox_t->get_matrix(), m.transpose())); REQUIRE(*cx_t_ptr == *get_op_ptr(OpType::CX)); } + GIVEN("Circuit with barriers") { + Circuit circ(2); + circ.add_op(OpType::Y, {0}); + circ.add_barrier({0, 1}, {}, "comment"); + circ.add_op(OpType::CX, {0, 1}); + Circuit correct_transposed(2); + correct_transposed.add_op(OpType::CX, {0, 1}); + correct_transposed.add_barrier({0, 1}, {}, "comment"); + correct_transposed.add_op(OpType::U3, {3, 0.5, 0.5}, {0}); + Circuit transposed = circ.transpose(); + REQUIRE(transposed == correct_transposed); + transposed.assert_valid(); + } } SCENARIO("Test circuit.dagger() method") { @@ -1534,6 +1548,19 @@ SCENARIO("Test circuit.dagger() method") { const Eigen::MatrixXcd udag = tket_sim::get_unitary(daggered); REQUIRE(u.adjoint().isApprox(udag, ERR_EPS)); } + GIVEN("Circuit with barriers") { + Circuit circ(2); + circ.add_op(OpType::Sdg, {0}); + circ.add_barrier({0, 1}, {}, "comment"); + circ.add_op(OpType::CX, {0, 1}); + Circuit correct_daggered(2); + correct_daggered.add_op(OpType::CX, {0, 1}); + correct_daggered.add_barrier({0, 1}, {}, "comment"); + correct_daggered.add_op(OpType::S, {0}); + Circuit daggered = circ.dagger(); + REQUIRE(daggered == correct_daggered); + daggered.assert_valid(); + } } SCENARIO("Test conditional_circuit method") { @@ -2685,6 +2712,10 @@ SCENARIO("Confirm that LaTeX output compiles", "[latex][.long]") { c.add_conditional_gate(OpType::CnZ, {}, {0, 1, 2, 4, 3}, {}, 0); c.add_conditional_gate( OpType::CnRy, {-0.57}, {0, 3, 2, 4, 1}, {}, 0); + c.add_conditional_gate( + OpType::CnRx, {-0.57}, {0, 3, 2, 4, 1}, {}, 0); + c.add_conditional_gate( + OpType::CnRz, {-0.57}, {0, 3, 2, 4, 1}, {}, 0); c.add_conditional_gate(OpType::CH, {}, {1, 0}, {}, 0); c.add_conditional_gate(OpType::CY, {}, {2, 3}, {}, 0); c.add_conditional_gate(OpType::CRz, {1.42}, {0, 2}, {}, 0); @@ -2694,6 +2725,13 @@ SCENARIO("Confirm that LaTeX output compiles", "[latex][.long]") { c.add_conditional_gate( OpType::CU3, {1.04, 0.36, -0.36}, {0, 4}, {}, 0); + // https://github.com/CQCL/tket/issues/1363 + Qubit q1("q_1", 0); + Bit c1("c_1", 0); + c.add_qubit(q1); + c.add_bit(c1); + c.add_measure(q1, c1); + c.to_latex_file("circ.tex"); int response = std::system("latexmk -pdf circ.tex -quiet"); REQUIRE(response == 0); diff --git a/tket/test/src/Circuit/test_CircPool.cpp b/tket/test/src/Circuit/test_CircPool.cpp index 70ac4e1af0..d469525bda 100644 --- a/tket/test/src/Circuit/test_CircPool.cpp +++ b/tket/test/src/Circuit/test_CircPool.cpp @@ -45,6 +45,11 @@ SCENARIO("Simple CircPool identities") { orig.add_op(OpType::CX, {0, 1}); res = CircPool::H_CZ_H(); } + GIVEN("CX_using_AAMS") { + orig = Circuit(2); + orig.add_op(OpType::CX, {0, 1}); + res = CircPool::CX_using_AAMS(); + } auto u_orig = tket_sim::get_unitary(orig); auto u_res = tket_sim::get_unitary(res); @@ -234,5 +239,210 @@ SCENARIO("Test remove_noops") { } } +SCENARIO( + "Rx_using_GPI, Ry_using_GPI, Rz_using_GPI, XXPhase_using_AAMS," + "YYPhase_using_AAMS, ZZPhase_using_AAMS") { + Expr e1; + Sym asym = SymEngine::symbol("a"); + Expr a(asym); + + GIVEN("Normalised concrete angles (1)") { e1 = .3; } + GIVEN("Normalised concrete angles (2)") { e1 = -0.32; } + GIVEN("Not normalised concrete angles (1)") { e1 = 1.4; } + GIVEN("Not normalised concrete angles (2)") { e1 = -5.7; } + GIVEN("Symbolic angles (1)") { e1 = a; } + + Circuit rx_orig(1); + rx_orig.add_op(OpType::Rx, {e1}, {0}); + Circuit ry_orig(1); + ry_orig.add_op(OpType::Ry, {e1}, {0}); + Circuit rz_orig(1); + rz_orig.add_op(OpType::Rz, {e1}, {0}); + Circuit xxphase_orig(2); + xxphase_orig.add_op(OpType::XXPhase, {e1}, {0, 1}); + Circuit yyphase_orig(2); + yyphase_orig.add_op(OpType::YYPhase, {e1}, {0, 1}); + Circuit zzphase_orig(2); + zzphase_orig.add_op(OpType::ZZPhase, {e1}, {0, 1}); + std::vector circuits_orig = { + rx_orig, ry_orig, rz_orig, xxphase_orig, yyphase_orig, zzphase_orig}; + + Circuit rx_res = CircPool::Rx_using_GPI(e1); + Circuit ry_res = CircPool::Ry_using_GPI(e1); + Circuit rz_res = CircPool::Rz_using_GPI(e1); + Circuit xxphase_res = CircPool::XXPhase_using_AAMS(e1); + Circuit yyphase_res = CircPool::YYPhase_using_AAMS(e1); + Circuit zzphase_res = CircPool::ZZPhase_using_AAMS(e1); + std::vector circuits_res = {rx_res, ry_res, rz_res, + xxphase_res, yyphase_res, zzphase_res}; + + // check unitary identity + auto symset = circuits_orig[0].free_symbols(); + std::vector symbols(symset.begin(), symset.end()); + if (symbols.empty()) { + for (unsigned k = 0; k < 6; k++) { + auto u_orig = tket_sim::get_unitary(circuits_orig[k]); + auto u_res = tket_sim::get_unitary(circuits_res[k]); + REQUIRE(u_res.isApprox(u_orig)); + } + } else { + std::vector rands{0.1231, 2.3124, 34.23, 2.23, 3.15, 1.2, 0.93}; + // substitute random values for symbolics and check equality + unsigned i = 0; + while (i + symbols.size() <= rands.size()) { + symbol_map_t symmap; + for (unsigned j = 0; j < symbols.size(); ++j) { + symmap[symbols[j]] = rands[i + j]; + } + for (unsigned k = 0; k < 6; ++k) { + Circuit orig_sub = circuits_orig[k]; + orig_sub.symbol_substitution(symmap); + auto u_orig = tket_sim::get_unitary(orig_sub); + Circuit res_sub = circuits_res[k]; + res_sub.symbol_substitution(symmap); + auto u_res = tket_sim::get_unitary(res_sub); + REQUIRE(u_res.isApprox(u_orig)); + } + ++i; + } + } +} + +SCENARIO("TK1_using_GPI, TK2_using_AAMS") { + Expr e1, e2, e3; + Sym asym = SymEngine::symbol("a"); + Expr a(asym); + Sym bsym = SymEngine::symbol("b"); + Expr b(bsym); + Sym csym = SymEngine::symbol("c"); + Expr c(csym); + + GIVEN("Normalised concrete angles (1)") { + e1 = .3; + e2 = .1; + e3 = .05; + } + GIVEN("Normalised concrete angles (2)") { + e1 = 0.32; + e2 = 0.31; + e3 = -0.3; + } + GIVEN("Not normalised concrete angles (1)") { + e1 = .3; + e2 = .4; + e3 = .45; + } + GIVEN("Not normalised concrete angles (2)") { + e1 = .3; + e2 = 1.4; + e3 = .489; + } + GIVEN("Not normalised concrete angles (3)") { + e1 = 2.3; + e2 = 3.4; + e3 = .489; + } + GIVEN("Not normalised concrete angles (4)") { + e1 = .3; + e2 = -.2; + e3 = .1; + } + GIVEN("Not normalised concrete angles (5)") { + e1 = -.3; + e2 = -.2; + e3 = .1; + } + GIVEN("Not normalised concrete angles (6)") { + e1 = .3; + e2 = .2; + e3 = -.3; + } + GIVEN("Not normalised concrete angles (7)") { + e1 = 0; + e2 = 0; + e3 = -1.2; + } + GIVEN("Not normalised concrete angles (8)") { + e1 = 0.1; + e2 = 0.3; + e3 = 0.2; + } + GIVEN("Symbolic angles (1)") { + e1 = a; + e2 = 3.4; + e3 = .489; + } + GIVEN("Symbolic angles (2)") { + e1 = a; + e2 = b; + e3 = 2.42; + } + GIVEN("Symbolic angles (3)") { + e1 = 2.3; + e2 = b; + e3 = 1.489; + } + GIVEN("Symbolic angles (4)") { + e1 = 2.3; + e2 = 123.08174; + e3 = c; + } + GIVEN("Symbolic angles (5)") { + e1 = a; + e2 = 123.08174; + e3 = c; + } + GIVEN("Symbolic angles (6)") { + e1 = 0.10012; + e2 = b; + e3 = c; + } + + Circuit tk1_orig(1); + tk1_orig.add_op(OpType::TK1, {e1, e2, e3}, {0}); + Circuit tk1_res = CircPool::TK1_using_GPI(e1, e2, e3); + + Circuit tk2_orig(2); + tk2_orig.add_op(OpType::TK2, {e1, e2, e3}, {0, 1}); + Circuit tk2_res = CircPool::TK2_using_AAMS(e1, e2, e3); + + // check unitary identity + auto symset = tk1_orig.free_symbols(); + std::vector symbols(symset.begin(), symset.end()); + if (symbols.empty()) { + auto u_tk1_orig = tket_sim::get_unitary(tk1_orig); + auto u_tk2_orig = tket_sim::get_unitary(tk2_orig); + auto u_tk1_res = tket_sim::get_unitary(tk1_res); + auto u_tk2_res = tket_sim::get_unitary(tk2_res); + REQUIRE(u_tk1_res.isApprox(u_tk1_orig)); + REQUIRE(u_tk2_res.isApprox(u_tk2_orig)); + } else { + std::vector rands{0.1231, 2.3124, 34.23, 2.23, 3.15, 1.2, 0.93}; + // substitute random values for symbolics and check equality + unsigned i = 0; + while (i + symbols.size() <= rands.size()) { + symbol_map_t symmap; + for (unsigned j = 0; j < symbols.size(); ++j) { + symmap[symbols[j]] = rands[i + j]; + } + Circuit tk1_orig_sub = tk1_orig; + Circuit tk2_orig_sub = tk2_orig; + tk1_orig_sub.symbol_substitution(symmap); + tk2_orig_sub.symbol_substitution(symmap); + auto u_tk1_orig = tket_sim::get_unitary(tk1_orig_sub); + auto u_tk2_orig = tket_sim::get_unitary(tk2_orig_sub); + Circuit tk1_res_sub = tk1_res; + Circuit tk2_res_sub = tk2_res; + tk1_res_sub.symbol_substitution(symmap); + tk2_res_sub.symbol_substitution(symmap); + auto u_tk1_res = tket_sim::get_unitary(tk1_res_sub); + auto u_tk2_res = tket_sim::get_unitary(tk2_res_sub); + REQUIRE(u_tk1_res.isApprox(u_tk1_orig)); + REQUIRE(u_tk2_res.isApprox(u_tk2_orig)); + ++i; + } + } +} + } // namespace test_CircPool } // namespace tket diff --git a/tket/test/src/Circuit/test_Symbolic.cpp b/tket/test/src/Circuit/test_Symbolic.cpp index 4e95122770..2389786d6e 100644 --- a/tket/test/src/Circuit/test_Symbolic.cpp +++ b/tket/test/src/Circuit/test_Symbolic.cpp @@ -207,5 +207,57 @@ SCENARIO("Symbolic squashing, correctness") { } } +SCENARIO("Symbolic GPI, GPI2, AAMS") { + Sym asym = SymEngine::symbol("a"); + Expr a(asym); + Sym bsym = SymEngine::symbol("b"); + Expr b(bsym); + Sym csym = SymEngine::symbol("c"); + Expr c(csym); + + Circuit gpi_orig(1); + gpi_orig.add_op(OpType::GPI, a, {0}); + Circuit gpi2_orig(1); + gpi2_orig.add_op(OpType::GPI2, a, {0}); + Circuit aams_orig(2); + aams_orig.add_op(OpType::AAMS, {a, b, c}, {0, 1}); + + std::vector rands{0.1231, 2.3124, 34.23, 2.23, 3.15, 1.2, 0.93}; + for (unsigned i = 0; i < rands.size(); ++i) { + Circuit gpi_orig_sub = gpi_orig; + Circuit gpi2_orig_sub = gpi2_orig; + double an = rands[i]; + symbol_map_t symmap; + symmap[asym] = an; + gpi_orig_sub.symbol_substitution(symmap); + gpi2_orig_sub.symbol_substitution(symmap); + auto u_gpi_orig = tket_sim::get_unitary(gpi_orig_sub); + auto u_gpi2_orig = tket_sim::get_unitary(gpi2_orig_sub); + Circuit gpi_res(1); + Circuit gpi2_res(1); + gpi_res.add_op(OpType::GPI, an, {0}); + gpi2_res.add_op(OpType::GPI2, an, {0}); + auto u_gpi_res = tket_sim::get_unitary(gpi_res); + auto u_gpi2_res = tket_sim::get_unitary(gpi2_res); + REQUIRE(u_gpi_res.isApprox(u_gpi_orig)); + REQUIRE(u_gpi2_res.isApprox(u_gpi2_orig)); + for (unsigned j = 0; j < rands.size(); ++j) { + double bn = rands[j]; + for (unsigned k = 0; k < rands.size(); ++k) { + double cn = rands[k]; + symmap[bsym] = bn; + symmap[csym] = cn; + Circuit aams_orig_sub = aams_orig; + aams_orig_sub.symbol_substitution(symmap); + auto u_aams_orig = tket_sim::get_unitary(aams_orig_sub); + Circuit aams_res(2); + aams_res.add_op(OpType::AAMS, {an, bn, cn}, {0, 1}); + auto u_aams_res = tket_sim::get_unitary(aams_res); + REQUIRE(u_aams_res.isApprox(u_aams_orig)); + } + } + } +} + } // namespace test_Symbolic } // namespace tket diff --git a/tket/test/src/Ops/test_Ops.cpp b/tket/test/src/Ops/test_Ops.cpp index 6078d78e76..b07654bbd5 100644 --- a/tket/test/src/Ops/test_Ops.cpp +++ b/tket/test/src/Ops/test_Ops.cpp @@ -134,6 +134,16 @@ SCENARIO("Check op retrieval overloads are working correctly.", "[ops]") { CHECK(cnry->get_name() == "CnRy(0.5)"); CHECK(cnry->get_params().size() == 1); REQUIRE(cnry->transpose()->get_params() == rhs); + const Op_ptr cnrx = (get_op_ptr(OpType::CnRx, 0.5)); + + std::vector rhs_same = {Expr(0.5)}; + CHECK(cnrx->get_name() == "CnRx(0.5)"); + CHECK(cnrx->get_params().size() == 1); + REQUIRE(cnrx->transpose()->get_params() == rhs_same); + const Op_ptr cnrz = (get_op_ptr(OpType::CnRz, 0.5)); + CHECK(cnrz->get_name() == "CnRz(0.5)"); + CHECK(cnrz->get_params().size() == 1); + REQUIRE(cnrz->transpose()->get_params() == rhs_same); const Op_ptr xxphase = (get_op_ptr(OpType::XXPhase, 0.5)); CHECK(xxphase->get_name() == "XXPhase(0.5)"); REQUIRE(*xxphase->transpose() == *xxphase); @@ -307,6 +317,8 @@ SCENARIO("Examples for is_singleq_unitary") { } GIVEN("Variable-qubit gates") { REQUIRE(!(get_op_ptr(OpType::CnRy, 0.2))->get_desc().is_singleq_unitary()); + REQUIRE(!(get_op_ptr(OpType::CnRx, 0.2))->get_desc().is_singleq_unitary()); + REQUIRE(!(get_op_ptr(OpType::CnRz, 0.2))->get_desc().is_singleq_unitary()); REQUIRE(!(get_op_ptr(OpType::PhaseGadget, Expr(0.4))) ->get_desc() .is_singleq_unitary()); diff --git a/tket/test/src/Passes/test_SynthesiseTK.cpp b/tket/test/src/Passes/test_SynthesiseTK.cpp index eb49eb03ca..b41c2a1a7d 100644 --- a/tket/test/src/Passes/test_SynthesiseTK.cpp +++ b/tket/test/src/Passes/test_SynthesiseTK.cpp @@ -90,6 +90,8 @@ SCENARIO("SynthesiseTK correctness") { c.add_op(OpType::CCX, {0, 1, 2}); c.add_op(OpType::CnX, {0, 1, 2, 3}); c.add_op(OpType::CnRy, 0.25, {0, 1, 2, 3}); + c.add_op(OpType::CnRx, 0.25, {0, 1, 2, 3}); + c.add_op(OpType::CnRz, 0.25, {0, 1, 2, 3}); c.add_op(OpType::CSWAP, {1, 2, 3}); c.add_op(OpType::BRIDGE, {1, 3, 0}); check_synthesise_tk(c); @@ -119,6 +121,8 @@ SCENARIO("SynthesiseTK correctness") { c.add_op(OpType::PhasedX, {a, a + 0.2}, {0}); c.add_op(OpType::NPhasedX, {a + 0.3, a}, {0, 1, 2}); c.add_op(OpType::CnRy, a - 0.3, {1, 2, 0}); + c.add_op(OpType::CnRx, a - 0.3, {1, 2, 0}); + c.add_op(OpType::CnRz, a - 0.3, {1, 2, 0}); c.add_op(OpType::ESWAP, a, {1, 2}); c.add_op(OpType::FSim, {a + 0.1, a + 0.2}, {2, 0}); check_synthesise_tk(c); diff --git a/tket/test/src/Simulation/test_CircuitSimulator.cpp b/tket/test/src/Simulation/test_CircuitSimulator.cpp index f65bc069d7..a0355b0bf8 100644 --- a/tket/test/src/Simulation/test_CircuitSimulator.cpp +++ b/tket/test/src/Simulation/test_CircuitSimulator.cpp @@ -243,6 +243,8 @@ SCENARIO("Directly simulate circuits with >= 3 qubit gates") { circ.add_op(OpType::BRIDGE, {0, 1, 2}); circ.add_op(OpType::CSWAP, {0, 1, 2}); circ.add_op(OpType::CnRy, 0.1234, {0, 1, 2, 3}); + circ.add_op(OpType::CnRx, 0.1234, {0, 1, 2, 3}); + circ.add_op(OpType::CnRz, 0.1234, {0, 1, 2, 3}); circ.add_op(OpType::CnX, {0, 1, 2, 3}); circ.add_op(OpType::PhaseGadget, 0.1, {0, 1, 2, 3}); const auto u = tket_sim::get_unitary(circ); diff --git a/tket/test/src/test_ControlDecomp.cpp b/tket/test/src/test_ControlDecomp.cpp index 3c61b5cdaf..9200554cd4 100644 --- a/tket/test/src/test_ControlDecomp.cpp +++ b/tket/test/src/test_ControlDecomp.cpp @@ -780,6 +780,8 @@ SCENARIO("Test decomp_arbitrary_controlled_gates") { Circuit circ(3); circ.add_op(OpType::CnRy, 0.33, {0, 1, 2}); + circ.add_op(OpType::CnRx, 0.33, {0, 1, 2}); + circ.add_op(OpType::CnRz, 0.33, {0, 1, 2}); circ.add_op(OpType::CnY, {0, 1, 2}); circ.add_op(OpType::CnZ, {1, 0, 2}); circ.add_op(OpType::CnX, {0, 2, 1}); @@ -787,6 +789,8 @@ SCENARIO("Test decomp_arbitrary_controlled_gates") { auto u = tket_sim::get_unitary(circ); REQUIRE(Transforms::decomp_arbitrary_controlled_gates().apply(circ)); REQUIRE(circ.count_gates(OpType::CnRy) == 0); + REQUIRE(circ.count_gates(OpType::CnRx) == 0); + REQUIRE(circ.count_gates(OpType::CnRz) == 0); REQUIRE(circ.count_gates(OpType::CnY) == 0); REQUIRE(circ.count_gates(OpType::CnZ) == 0); REQUIRE(circ.count_gates(OpType::CnX) == 0); diff --git a/tket/test/src/test_GreedyPauli.cpp b/tket/test/src/test_GreedyPauli.cpp new file mode 100644 index 0000000000..2cca0e178a --- /dev/null +++ b/tket/test/src/test_GreedyPauli.cpp @@ -0,0 +1,294 @@ +// Copyright 2019-2024 Cambridge Quantum Computing +// +// 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 + +#include "testutil.hpp" +#include "tket/Circuit/Circuit.hpp" +#include "tket/Circuit/PauliExpBoxes.hpp" +#include "tket/Circuit/Simulation/CircuitSimulator.hpp" +#include "tket/Gate/SymTable.hpp" +#include "tket/PauliGraph/PauliGraph.hpp" +#include "tket/Predicates/PassGenerators.hpp" +#include "tket/Transformations/Decomposition.hpp" +#include "tket/Transformations/GreedyPauliOptimisation.hpp" +#include "tket/Utils/Expression.hpp" + +namespace tket { +namespace test_GreedyPauliSimp { + +SCENARIO("Unsupported circuits") { + GIVEN("Circuit with mid-circ measurements") { + Circuit circ(2, 2); + circ.add_op(OpType::H, {0}); + circ.add_op(OpType::Rx, 0.5, {1}); + circ.add_op(OpType::Measure, {0, 0}); + circ.add_op(OpType::CX, {0, 1}); + REQUIRE_THROWS_MATCHES( + Transforms::greedy_pauli_optimisation().apply(circ), + MidCircuitMeasurementNotAllowed, + MessageContains( + "PauliGraph does not support mid-circuit measurements")); + } + GIVEN("Circuit with resets") { + Circuit circ(1); + circ.add_op(OpType::H, {0}); + circ.add_op(OpType::Reset, {0}); + REQUIRE_THROWS_MATCHES( + Transforms::greedy_pauli_optimisation().apply(circ), BadOpType, + MessageContains("Cannot add gate to PauliGraph")); + } + GIVEN("Circuit with conditional gates") { + Circuit circ(2, 2); + circ.add_conditional_gate(OpType::Rz, {0.5}, {0}, {0}, 0); + REQUIRE_THROWS_MATCHES( + Transforms::greedy_pauli_optimisation().apply(circ), BadOpType, + MessageContains( + "Can only make a PauliGraph from a circuit of basic gates")); + } +} +SCENARIO("Clifford synthesis") { + GIVEN("Empty circuit") { + Circuit circ(3); + Circuit d(circ); + REQUIRE(Transforms::greedy_pauli_optimisation().apply(d)); + REQUIRE(test_unitary_comparison(circ, d, true)); + } + GIVEN("1Q Simple Clifford") { + Circuit circ(1); + circ.add_op(OpType::Sdg, {0}); + Circuit d(circ); + REQUIRE(Transforms::greedy_pauli_optimisation().apply(d)); + REQUIRE(test_unitary_comparison(circ, d, true)); + } + GIVEN("2Q Simple Clifford") { + Circuit circ(2); + circ.add_op(OpType::Y, {0}); + circ.add_op(OpType::Vdg, {1}); + circ.add_op(OpType::CX, {0, 1}); + Circuit d(circ); + REQUIRE(Transforms::greedy_pauli_optimisation().apply(d)); + REQUIRE(test_unitary_comparison(circ, d, true)); + } + GIVEN("3Q Simple Clifford") { + Circuit circ(3); + circ.add_op(OpType::Y, {0}); + circ.add_op(OpType::Sdg, {2}); + circ.add_op(OpType::H, {1}); + circ.add_op(OpType::CX, {1, 2}); + circ.add_op(OpType::CZ, {0, 2}); + Circuit d(circ); + REQUIRE(Transforms::greedy_pauli_optimisation().apply(d)); + REQUIRE(test_unitary_comparison(circ, d, true)); + } + GIVEN("5Q Simple Clifford") { + Circuit circ(5); + circ.add_op(OpType::H, {0}); + circ.add_op(OpType::S, {1}); + circ.add_op(OpType::CX, {2, 3}); + circ.add_op(OpType::CZ, {1, 2}); + circ.add_op(OpType::V, {1}); + circ.add_op(OpType::X, {3}); + circ.add_op(OpType::CZ, {0, 4}); + circ.add_op(OpType::CY, {0, 1}); + circ.add_op(OpType::H, {2}); + circ.add_op(OpType::Z, {2}); + circ.add_op(OpType::Y, {4}); + circ.add_op(OpType::CY, {3, 4}); + circ.add_op(OpType::CX, {2, 0}); + Circuit d(circ); + REQUIRE(Transforms::greedy_pauli_optimisation().apply(d)); + REQUIRE(test_unitary_comparison(circ, d, true)); + } + GIVEN("Clifford with swaps") { + Circuit circ(4); + circ.add_op(OpType::X, {0}); + circ.add_op(OpType::SWAP, {1, 2}); + circ.add_op(OpType::CX, {0, 2}); + circ.add_op(OpType::SWAP, {2, 3}); + circ.add_op(OpType::H, {3}); + circ.add_op(OpType::CZ, {1, 3}); + circ.add_op(OpType::H, {2}); + circ.add_op(OpType::X, {0}); + circ.add_op(OpType::SWAP, {0, 1}); + circ.add_op(OpType::Z, {2}); + circ.add_op(OpType::SWAP, {3, 1}); + circ.add_op(OpType::CY, {0, 2}); + circ.add_op(OpType::SWAP, {1, 2}); + Circuit d(circ); + REQUIRE(Transforms::greedy_pauli_optimisation().apply(d)); + REQUIRE(test_unitary_comparison(circ, d, true)); + } +} +SCENARIO("Complete synthesis") { + GIVEN("1Q Simple Circuit") { + Circuit circ(1); + circ.add_op(OpType::Sdg, {0}); + circ.add_op(OpType::Rx, 0.3, {0}); + Circuit d(circ); + REQUIRE(Transforms::greedy_pauli_optimisation().apply(d)); + REQUIRE(test_unitary_comparison(circ, d, true)); + } + GIVEN("Symbolic Circuit") { + Circuit circ(2); + auto a = SymTable::fresh_symbol("a"); + auto b = SymTable::fresh_symbol("b"); + auto ea = Expr(a); + auto eb = Expr(b); + circ.add_op(OpType::Sdg, {0}); + circ.add_op(OpType::H, {0}); + circ.add_op(OpType::Ry, eb, {1}); + circ.add_op(OpType::CX, {0, 1}); + circ.add_op(OpType::Rx, ea, {0}); + Circuit d(circ); + symbol_map_t symbol_map; + symbol_map[a] = Expr(0.5); + symbol_map[b] = Expr(0.7); + REQUIRE(Transforms::greedy_pauli_optimisation().apply(d)); + circ.symbol_substitution(symbol_map); + d.symbol_substitution(symbol_map); + REQUIRE(test_unitary_comparison(circ, d, true)); + } + GIVEN("4Q PauliExp Circuit") { + Circuit circ(4); + circ.add_box( + PauliExpBox(SymPauliTensor({Pauli::X, Pauli::X}, 0.3)), {0, 1}); + circ.add_box( + PauliExpBox(SymPauliTensor({Pauli::Z, Pauli::Y}, -0.1)), {2, 3}); + circ.add_box( + PauliExpPairBox( + SymPauliTensor({Pauli::X, Pauli::Z}, 1.0), + SymPauliTensor({Pauli::Z, Pauli::X}, 0.4)), + {0, 2}); + circ.add_box( + PauliExpCommutingSetBox({ + {{Pauli::I, Pauli::Y, Pauli::I}, -0.1}, + {{Pauli::X, Pauli::Y, Pauli::Z}, -1.2}, + {{Pauli::X, Pauli::Y, Pauli::Z}, 0.5}, + }), + {1, 2, 3}); + circ.add_op(OpType::CX, {0, 2}); + circ.add_op(OpType::SWAP, {2, 3}); + circ.add_op(OpType::H, {3}); + circ.add_op(OpType::CZ, {1, 3}); + Circuit d = Transforms::GreedyPauliSimp::greedy_pauli_graph_synthesis(circ); + REQUIRE(test_unitary_comparison(circ, d, true)); + } + GIVEN("Arbitrary Circuit") { + Circuit circ(5); + circ.add_op(OpType::X, {0}); + circ.add_op(OpType::SWAP, {1, 2}); + circ.add_op(OpType::Rz, 0.1, {1}); + circ.add_op(OpType::CX, {0, 2}); + circ.add_op(OpType::SWAP, {2, 3}); + circ.add_op(OpType::Ry, 0.2, {3}); + circ.add_op(OpType::Ry, 0.15, {2}); + circ.add_op(OpType::H, {3}); + circ.add_op(OpType::Rz, 0.3, {4}); + circ.add_op(OpType::CZ, {1, 4}); + circ.add_op(OpType::ZZMax, {1, 2}); + circ.add_op(OpType::T, {4}); + circ.add_op(OpType::X, {0}); + circ.add_op(OpType::ZZPhase, 0.7, {3, 2}); + circ.add_op(OpType::T, {3}); + circ.add_op(OpType::SWAP, {0, 1}); + circ.add_op(OpType::Z, {2}); + circ.add_op(OpType::SWAP, {3, 1}); + circ.add_op(OpType::CX, {1, 4}); + circ.add_op(OpType::T, {0}); + circ.add_op(OpType::CY, {0, 2}); + circ.add_op(OpType::SWAP, {1, 2}); + Circuit d(circ); + REQUIRE(Transforms::greedy_pauli_optimisation().apply(d)); + REQUIRE(test_unitary_comparison(circ, d, true)); + } + GIVEN("Circuit with trivial Pauli exps") { + Circuit circ(4); + circ.add_box(PauliExpBox(SymPauliTensor({Pauli::X, Pauli::X}, 2)), {0, 1}); + circ.add_box( + PauliExpPairBox( + SymPauliTensor({Pauli::I, Pauli::I}, 1.2), + SymPauliTensor({Pauli::Z, Pauli::X}, -2)), + {0, 2}); + circ.add_box( + PauliExpCommutingSetBox({ + {{Pauli::I, Pauli::Y, Pauli::I}, 0}, + {{Pauli::X, Pauli::Y, Pauli::Z}, 0}, + {{Pauli::I, Pauli::I, Pauli::I}, 0.5}, + }), + {1, 2, 3}); + Circuit d = Transforms::GreedyPauliSimp::greedy_pauli_graph_synthesis(circ); + REQUIRE(test_unitary_comparison(circ, d, true)); + REQUIRE(d.n_gates() == 0); + } + GIVEN("Circuit with non-default UnitIDs") { + Circuit circ; + register_t reg_a = circ.add_q_register("a", 2); + register_t reg_b = circ.add_q_register("b", 2); + circ.add_op(OpType::CX, {reg_a[0], reg_b[1]}); + circ.add_op(OpType::SWAP, {reg_b[0], reg_a[1]}); + circ.add_op(OpType::Rz, 0.3, {reg_a[1]}); + circ.add_op(OpType::CX, {reg_a[1], reg_b[1]}); + circ.add_op(OpType::Ry, 0.2, {reg_b[1]}); + circ.add_op(OpType::H, {reg_b[1]}); + circ.add_op(OpType::Rz, 0.3, {reg_a[0]}); + circ.add_op(OpType::CY, {reg_a[0], reg_a[1]}); + Circuit d(circ); + REQUIRE(Transforms::greedy_pauli_optimisation().apply(d)); + REQUIRE(test_unitary_comparison(circ, d, true)); + } + GIVEN("Circuit with measurements") { + Circuit circ(4, 4); + circ.add_op(OpType::X, {0}); + circ.add_op(OpType::SWAP, {1, 2}); + circ.add_op(OpType::Rz, 0.1, {1}); + circ.add_op(OpType::CX, {0, 2}); + circ.add_op(OpType::SWAP, {2, 3}); + circ.add_op(OpType::Ry, 0.2, {3}); + circ.add_op(OpType::Ry, 0.15, {2}); + circ.add_op(OpType::H, {3}); + circ.add_op(OpType::Rz, 0.3, {0}); + circ.add_op(OpType::CZ, {0, 1}); + circ.add_op(OpType::ZZMax, {1, 2}); + // For circuit d, we add measurement after synthesis + Circuit d(circ); + REQUIRE(Transforms::greedy_pauli_optimisation().apply(d)); + REQUIRE(d.has_implicit_wireswaps()); + for (unsigned i = 0; i < 4; i++) { + d.add_op(OpType::Measure, {Qubit(i), Bit(i)}); + } + // For circuit g, we add measurement before synthesis + Circuit g(circ); + for (unsigned i = 0; i < 4; i++) { + g.add_op(OpType::Measure, {Qubit(i), Bit(i)}); + } + REQUIRE(Transforms::greedy_pauli_optimisation().apply(g)); + REQUIRE(d == g); + } +} +SCENARIO("Test GreedyPauliSimp pass construction") { + // test pass construction + GIVEN("A circuit") { + Circuit c(2); + c.add_op(OpType::CX, {0, 1}); + c.add_op(OpType::Rz, 0.5, {1}); + CompilationUnit cu(c); + CHECK(gen_greedy_pauli_simp(0.3, 0.5)->apply(cu)); + REQUIRE(test_unitary_comparison(c, cu.get_circ_ref(), true)); + } +} +} // namespace test_GreedyPauliSimp +} // namespace tket diff --git a/tket/test/src/test_MappingManager.cpp b/tket/test/src/test_MappingManager.cpp index f0b30a523c..1e0ab6544d 100644 --- a/tket/test/src/test_MappingManager.cpp +++ b/tket/test/src/test_MappingManager.cpp @@ -23,7 +23,7 @@ namespace tket { class TokenSwappingTester : public RoutingMethod { public: - TokenSwappingTester(){}; + TokenSwappingTester() {}; /** * @param mapping_frontier Contains boundary of routed/unrouted circuit for diff --git a/tket/test/src/test_Synthesis.cpp b/tket/test/src/test_Synthesis.cpp index 124d92c85a..6c2138b326 100644 --- a/tket/test/src/test_Synthesis.cpp +++ b/tket/test/src/test_Synthesis.cpp @@ -1646,16 +1646,20 @@ SCENARIO("Test barrier blocks transforms successfully") { GIVEN("Controlled gates with barrier") { Circuit circ(8); circ.add_op(OpType::CnRy, 0.4, {0, 1, 2, 3, 4, 5, 6, 7}); + circ.add_op(OpType::CnRx, 0.4, {0, 1, 2, 3, 4, 5, 6, 7}); + circ.add_op(OpType::CnRz, 0.4, {0, 1, 2, 3, 4, 5, 6, 7}); circ.add_op(OpType::CX, {6, 7}); circ.add_barrier({0, 1, 2, 3}); circ.add_op(OpType::CX, {6, 7}); + circ.add_op(OpType::CnRz, -0.4, {0, 1, 2, 3, 4, 5, 6, 7}); + circ.add_op(OpType::CnRx, -0.4, {0, 1, 2, 3, 4, 5, 6, 7}); circ.add_op(OpType::CnRy, -0.4, {0, 1, 2, 3, 4, 5, 6, 7}); REQUIRE(verify_n_qubits_for_ops(circ)); - REQUIRE(circ.n_gates() == 5); + REQUIRE(circ.n_gates() == 9); REQUIRE(Transforms::remove_redundancies().apply(circ)); REQUIRE(verify_n_qubits_for_ops(circ)); REQUIRE(circ.depth_by_type(OpType::Barrier) == 1); - REQUIRE(circ.n_gates() == 3); // both CXs removed + REQUIRE(circ.n_gates() == 7); // both CXs removed Circuit rep(4); const Op_ptr bar = std::make_shared(op_signature_t(4, EdgeType::Quantum)); @@ -2201,6 +2205,8 @@ SCENARIO("Synthesis with conditional gates") { c.add_measure(1, 1); c.add_conditional_gate(OpType::U1, {0.25}, {1}, {0}, 1); c.add_conditional_gate(OpType::CnRy, {0.25}, {0, 1, 2}, {0, 1}, 0); + c.add_conditional_gate(OpType::CnRx, {0.25}, {0, 1, 2}, {0, 1}, 0); + c.add_conditional_gate(OpType::CnRz, {0.25}, {0, 1, 2}, {0, 1}, 0); c.add_measure(2, 2); check_conditions(SynthesiseOQC(), c); check_conditions(SynthesiseTK(), c); diff --git a/tket/test/src/test_json.cpp b/tket/test/src/test_json.cpp index be596579fb..238c1449ae 100644 --- a/tket/test/src/test_json.cpp +++ b/tket/test/src/test_json.cpp @@ -132,6 +132,8 @@ SCENARIO("Test Command serialization") { const Qubit a = Qubit("a", 1, 2); c.add_qubit(a); c.add_op(OpType::CnRy, 0.1, {q[0], a, q[1]}); + c.add_op(OpType::CnRx, 0.1, {q[0], a, q[1]}); + c.add_op(OpType::CnRz, 0.1, {q[0], a, q[1]}); c.add_barrier({q[0], a}); check_cases(c.get_commands()); @@ -964,6 +966,7 @@ SCENARIO("Test compiler pass serializations") { Transforms::AllowClassical::No, Transforms::CreateAllQubits::Yes, std::make_shared(CircPool::X()))) COMPPASSJSONTEST(PlacementPass, gen_placement_pass(place)) + COMPPASSJSONTEST(GreedyPauliSimp, gen_greedy_pauli_simp(0.3, 0.18)) // TKET-1419 COMPPASSJSONTEST(NoiseAwarePlacement, gen_placement_pass(na_place)) COMPPASSJSONTEST(NaivePlacementPass, gen_naive_placement_pass(arc))