From 25d0a600a2f3a5aadd0f3429ad6661a5015c5b00 Mon Sep 17 00:00:00 2001
From: Callum Macpherson <93673602+CalMacCQ@users.noreply.github.com>
Date: Wed, 17 Apr 2024 09:49:39 +0100
Subject: [PATCH 01/27] add yet more missing circuit methods (#1352)
---
pytket/docs/circuit_class.rst | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/pytket/docs/circuit_class.rst b/pytket/docs/circuit_class.rst
index 30f2ddc84d..1340b34c16 100644
--- a/pytket/docs/circuit_class.rst
+++ b/pytket/docs/circuit_class.rst
@@ -327,6 +327,12 @@ condition on a specified set of bit values.)
.. automethod:: ZZMax
+ .. automethod:: AAMS
+
+ .. automethod:: GPI
+
+ .. automethod:: GPI2
+
Methods for appending circuit boxes
-----------------------------------
@@ -347,6 +353,10 @@ condition on a specified set of bit values.)
.. automethod:: add_circbox
+ .. automethod:: add_circbox_regwise
+
+ .. automethod:: add_circbox_with_regmap
+
.. automethod:: add_unitary1qbox
.. automethod:: add_unitary2qbox
@@ -361,6 +371,8 @@ condition on a specified set of bit values.)
.. automethod:: add_pauliexpcommutingsetbox
+ .. automethod:: add_termsequencebox
+
.. automethod:: add_phasepolybox
.. automethod:: add_toffolibox
From 49f684c30a18f483af0e82905e1ded9c4ddf91e9 Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Thu, 18 Apr 2024 10:08:26 +0100
Subject: [PATCH 02/27] Update to pytket-circuit-renderer 0.8 (#1354)
---
pytket/docs/changelog.rst | 7 +++++++
pytket/pytket/circuit/display/static/head_imports.html | 4 ++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/pytket/docs/changelog.rst b/pytket/docs/changelog.rst
index 29ea0efdf9..97a0e4e449 100644
--- a/pytket/docs/changelog.rst
+++ b/pytket/docs/changelog.rst
@@ -1,6 +1,13 @@
Changelog
=========
+Unreleased
+----------
+
+Features:
+
+* Update to pytket-circuit-renderer 0.8.
+
1.27.0 (April 2024)
-------------------
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 @@
-
-
+
+
From 02887463250ce5f2acec49a2773b035ba2f700b6 Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Fri, 19 Apr 2024 10:52:09 +0100
Subject: [PATCH 03/27] Ensure MacOS arm64 wheels are compatible with MacOS 12
and above (#1359)
---
.github/workflows/release.yml | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 269c9b0d28..6cca5016ab 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -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,7 +132,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: 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
@@ -138,8 +140,7 @@ jobs:
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
From 297a0fb2abf93c1a8353febba93bfb1b957e4c20 Mon Sep 17 00:00:00 2001
From: Richard Morrison
<141632498+quantinuum-richard-morrison@users.noreply.github.com>
Date: Thu, 25 Apr 2024 14:57:55 +0100
Subject: [PATCH 04/27] Add "CANCELLING" and "RETRYING" statuses (#1364)
---
pytket/docs/changelog.rst | 1 +
pytket/pytket/backends/status.py | 2 ++
2 files changed, 3 insertions(+)
diff --git a/pytket/docs/changelog.rst b/pytket/docs/changelog.rst
index 97a0e4e449..a771bc3d77 100644
--- a/pytket/docs/changelog.rst
+++ b/pytket/docs/changelog.rst
@@ -7,6 +7,7 @@ Unreleased
Features:
* Update to pytket-circuit-renderer 0.8.
+* Add two new status values for circuits on backends: "CANCELLING" and "RETRYING".
1.27.0 (April 2024)
-------------------
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."
From 16514cc9a21da0b9887e84d0ecf98c550b704522 Mon Sep 17 00:00:00 2001
From: Silas Dilkes <36165522+sjdilkes@users.noreply.github.com>
Date: Mon, 29 Apr 2024 09:08:52 +0100
Subject: [PATCH 05/27] Run do-clang-format with clang-format 18.1.4 (#1367)
* run do-clang-format with clang-format 18.1.4
* bump
---
pytket/binders/include/UnitRegister.hpp | 2 +-
pytket/conanfile.py | 2 +-
tket/conanfile.py | 2 +-
tket/include/tket/Characterisation/Cycles.hpp | 2 +-
tket/include/tket/Circuit/ClassicalExpBox.hpp | 2 +-
tket/include/tket/Mapping/AASLabelling.hpp | 2 +-
tket/include/tket/Mapping/LexiLabelling.hpp | 2 +-
tket/include/tket/Mapping/RoutingMethod.hpp | 2 +-
tket/include/tket/Placement/Placement.hpp | 4 ++--
tket/include/tket/Predicates/CompilerPass.hpp | 2 +-
tket/include/tket/Predicates/Predicates.hpp | 2 +-
tket/src/Mapping/BoxDecomposition.cpp | 2 +-
tket/src/Mapping/LexiRouteRoutingMethod.cpp | 2 +-
tket/src/Mapping/RoutingMethodCircuit.cpp | 2 +-
tket/src/Placement/Placement.cpp | 2 +-
tket/test/src/test_MappingManager.cpp | 2 +-
16 files changed, 17 insertions(+), 17 deletions(-)
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/conanfile.py b/pytket/conanfile.py
index 0f2b30f322..84f221acbc 100644
--- a/pytket/conanfile.py
+++ b/pytket/conanfile.py
@@ -32,7 +32,7 @@ def package(self):
cmake.install()
def requirements(self):
- self.requires("tket/1.2.117@tket/stable")
+ self.requires("tket/1.2.118@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")
diff --git a/tket/conanfile.py b/tket/conanfile.py
index cb0f27dcba..32c996febb 100644
--- a/tket/conanfile.py
+++ b/tket/conanfile.py
@@ -23,7 +23,7 @@
class TketConan(ConanFile):
name = "tket"
- version = "1.2.117"
+ version = "1.2.118"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
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/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/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/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/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/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/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/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
From cf12bd02f2a3dd192651100addc6896445ec78ca Mon Sep 17 00:00:00 2001
From: Dan Mills <52407433+daniel-mills-cqc@users.noreply.github.com>
Date: Mon, 29 Apr 2024 11:06:35 +0100
Subject: [PATCH 06/27] ci: Add automated benchmarking workflow (#1365)
* Add automated benchmarking workflow
* Rename jobs
* Remove tket checkout
* Remove mac os 12 compatability
* Revert "Remove mac os 12 compatability"
This reverts commit ecca33b1ec68657f3fd8f948debe3b3575f7c8c7.
---
.github/workflows/pytket_benchmarking.yml | 107 ++++++++++++++++++++++
1 file changed, 107 insertions(+)
create mode 100644 .github/workflows/pytket_benchmarking.yml
diff --git a/.github/workflows/pytket_benchmarking.yml b/.github/workflows/pytket_benchmarking.yml
new file mode 100644
index 0000000000..e8dc45974f
--- /dev/null
+++ b/.github/workflows/pytket_benchmarking.yml
@@ -0,0 +1,107 @@
+name: Automated Benchmarks
+
+on:
+ pull_request:
+ branches:
+ - develop
+ 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.13
+ 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 }}
From 26050e60f20f4701d6600af9951566aa810f1739 Mon Sep 17 00:00:00 2001
From: Jake Arkinstall <65358059+jake-arkinstall@users.noreply.github.com>
Date: Thu, 2 May 2024 15:46:46 +0100
Subject: [PATCH 07/27] Set Nix workflow to run on PRs and commits (not just
weekly) (#1370)
---
.github/workflows/build-with-nix.yml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.github/workflows/build-with-nix.yml b/.github/workflows/build-with-nix.yml
index 08ac988e19..0280785bde 100644
--- a/.github/workflows/build-with-nix.yml
+++ b/.github/workflows/build-with-nix.yml
@@ -1,9 +1,15 @@
name: build with nix
+
on:
+ pull_request:
+ branches:
+ - main
+ - develop
schedule:
# 01:00 every Sunday morning
- cron: '0 1 * * 0'
workflow_dispatch: {}
+
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
From 9b16ccfabe0a5ee6649413da9d08ac61abe0705d Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Fri, 3 May 2024 10:41:56 +0100
Subject: [PATCH 08/27] Switch workflows to target `main` only (#1371)
---
.github/workflows/build-with-nix.yml | 1 -
.github/workflows/build_and_test.yml | 21 ++++++++++-----------
.github/workflows/build_libs.yml | 4 ++--
.github/workflows/coverage.yml | 8 ++++----
.github/workflows/docs.yml | 2 +-
.github/workflows/pytket_benchmarking.yml | 2 +-
.github/workflows/test_libs.yml | 8 ++++----
.github/workflows/valgrind.yml | 2 +-
CONTRIBUTING.md | 16 ++++++++--------
9 files changed, 31 insertions(+), 33 deletions(-)
diff --git a/.github/workflows/build-with-nix.yml b/.github/workflows/build-with-nix.yml
index 0280785bde..7a83d0b784 100644
--- a/.github/workflows/build-with-nix.yml
+++ b/.github/workflows/build-with-nix.yml
@@ -4,7 +4,6 @@ on:
pull_request:
branches:
- main
- - develop
schedule:
# 01:00 every Sunday morning
- cron: '0 1 * * 0'
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index 9df57f11f7..9651a62c7b 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'
@@ -63,7 +62,7 @@ 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:
@@ -138,7 +137,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
@@ -207,7 +206,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
@@ -319,7 +318,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
@@ -409,7 +408,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
@@ -521,7 +520,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
@@ -534,7 +533,7 @@ jobs:
name: Publish pytket coverage
needs: build_test_pytket_ubuntu
concurrency: gh_pages
- if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
+ if: github.event_name == 'push'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
@@ -562,7 +561,7 @@ 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'
+ if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
@@ -571,7 +570,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
diff --git a/.github/workflows/build_libs.yml b/.github/workflows/build_libs.yml
index 735058d515..eb0ac8cb91 100644
--- a/.github/workflows/build_libs.yml
+++ b/.github/workflows/build_libs.yml
@@ -2,10 +2,10 @@ name: build libraries
on:
push:
branches:
- - develop
+ - main
pull_request:
branches:
- - develop
+ - main
workflow_dispatch: {}
jobs:
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 59dea72bb4..be2ebec17a 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'
@@ -99,12 +99,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
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index d661c5743d..6edc995828 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -3,7 +3,7 @@ name: Deploy tket C++ documentation
on:
push:
branches:
- - develop
+ - main
paths:
- 'tket/src/**'
diff --git a/.github/workflows/pytket_benchmarking.yml b/.github/workflows/pytket_benchmarking.yml
index e8dc45974f..171e4188d4 100644
--- a/.github/workflows/pytket_benchmarking.yml
+++ b/.github/workflows/pytket_benchmarking.yml
@@ -3,7 +3,7 @@ name: Automated Benchmarks
on:
pull_request:
branches:
- - develop
+ - main
workflow_dispatch:
jobs:
diff --git a/.github/workflows/test_libs.yml b/.github/workflows/test_libs.yml
index abe72ad419..2091bafaf8 100644
--- a/.github/workflows/test_libs.yml
+++ b/.github/workflows/test_libs.yml
@@ -2,10 +2,10 @@ name: test libraries
on:
push:
branches:
- - develop
+ - main
pull_request:
branches:
- - develop
+ - main
workflow_dispatch: {}
env:
@@ -135,7 +135,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,7 +146,7 @@ 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) }}
diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml
index 8b2159e081..eaa78cca44 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:
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`.
From e599bf3a9548768cb6a8447bfd08be58cad92fc3 Mon Sep 17 00:00:00 2001
From: Alec Edgington
Date: Fri, 3 May 2024 11:26:28 +0100
Subject: [PATCH 09/27] Fix typo.
---
.github/workflows/build_and_test.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index 9651a62c7b..a8a738ef5b 100644
--- a/.github/workflows/build_and_test.yml
+++ b/.github/workflows/build_and_test.yml
@@ -318,7 +318,7 @@ jobs:
name: pytket_test_coverage
path: pytket/tests/htmlcov
- name: Upload package
- if: github.event_name == 'push && 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
From 1a273e5514daf4d7b4ed8cdbe56ed3b7579f0e14 Mon Sep 17 00:00:00 2001
From: Alec Edgington
Date: Fri, 3 May 2024 11:28:03 +0100
Subject: [PATCH 10/27] Bump tket version.
---
pytket/conanfile.py | 2 +-
tket/conanfile.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pytket/conanfile.py b/pytket/conanfile.py
index 84f221acbc..53331101db 100644
--- a/pytket/conanfile.py
+++ b/pytket/conanfile.py
@@ -32,7 +32,7 @@ def package(self):
cmake.install()
def requirements(self):
- self.requires("tket/1.2.118@tket/stable")
+ self.requires("tket/1.2.119@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")
diff --git a/tket/conanfile.py b/tket/conanfile.py
index 32c996febb..aa82ae4190 100644
--- a/tket/conanfile.py
+++ b/tket/conanfile.py
@@ -23,7 +23,7 @@
class TketConan(ConanFile):
name = "tket"
- version = "1.2.118"
+ version = "1.2.119"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
From f55ef839924e6d7c6fc680329f5181311f247f4c Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Fri, 3 May 2024 14:16:52 +0100
Subject: [PATCH 11/27] Show diff from clang-format. (#1373)
---
.github/workflows/build_and_test.yml | 3 ++-
libs/tklog/src/TketLog.cpp | 4 ++--
pytket/conanfile.py | 2 +-
tket/conanfile.py | 2 +-
tket/src/Architecture/DistancesFromArchitecture.cpp | 4 ++--
tket/src/Clifford/UnitaryTableau.cpp | 8 ++++----
tket/src/Predicates/Predicates.cpp | 3 +--
7 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index a8a738ef5b..c4ff3ef09f 100644
--- a/.github/workflows/build_and_test.yml
+++ b/.github/workflows/build_and_test.yml
@@ -88,7 +88,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)
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/pytket/conanfile.py b/pytket/conanfile.py
index 53331101db..8eff94e165 100644
--- a/pytket/conanfile.py
+++ b/pytket/conanfile.py
@@ -32,7 +32,7 @@ def package(self):
cmake.install()
def requirements(self):
- self.requires("tket/1.2.119@tket/stable")
+ self.requires("tket/1.2.120@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")
diff --git a/tket/conanfile.py b/tket/conanfile.py
index aa82ae4190..1e948b370d 100644
--- a/tket/conanfile.py
+++ b/tket/conanfile.py
@@ -23,7 +23,7 @@
class TketConan(ConanFile):
name = "tket"
- version = "1.2.119"
+ version = "1.2.120"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
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/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/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 = {
From 8fdb139880a1cd76f01d7af1ef6ec5729ec727e5 Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Tue, 7 May 2024 09:12:04 +0100
Subject: [PATCH 12/27] Remove workflow to automatically create Jira issues.
(#1378)
---
.github/workflows/issue.yml | 33 ---------------------------------
1 file changed, 33 deletions(-)
delete mode 100644 .github/workflows/issue.yml
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 }}
From 145b70dfd0374ecf577c6a2583c4426b8e30add1 Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Tue, 7 May 2024 11:20:01 +0100
Subject: [PATCH 13/27] Update libraries to boost 1.85.0 (#1379)
---
libs/tktokenswap/conanfile.py | 4 ++--
libs/tktokenswap/test/conanfile.py | 2 +-
libs/tkwsm/conanfile.py | 4 ++--
libs/tkwsm/test/conanfile.py | 2 +-
4 files changed, 6 insertions(+), 6 deletions(-)
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..9835d66138 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")
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..3041b8878e 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")
From 6bcfa0a5c2b6288c74f4f14ab8703f8e3509ea95 Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Tue, 7 May 2024 11:54:11 +0100
Subject: [PATCH 14/27] Update to catch2 3.6.0 (#1375)
---
.github/workflows/build-without-conan.yml | 6 +++---
build-without-conan.md | 6 +++---
libs/tkassert/test/conanfile.py | 2 +-
libs/tklog/test/conanfile.py | 2 +-
libs/tkrng/test/conanfile.py | 2 +-
libs/tktokenswap/test/conanfile.py | 2 +-
libs/tkwsm/test/conanfile.py | 2 +-
pytket/conanfile.py | 2 +-
tket/conanfile.py | 4 ++--
9 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/.github/workflows/build-without-conan.yml b/.github/workflows/build-without-conan.yml
index 1454e4d032..3a4fa6a4b9 100644
--- a/.github/workflows/build-without-conan.yml
+++ b/.github/workflows/build-without-conan.yml
@@ -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} ..
diff --git a/build-without-conan.md b/build-without-conan.md
index 5a40b5d2c4..2968e8e486 100644
--- a/build-without-conan.md
+++ b/build-without-conan.md
@@ -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} ..
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/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/test/conanfile.py b/libs/tktokenswap/test/conanfile.py
index 9835d66138..180daf55bb 100644
--- a/libs/tktokenswap/test/conanfile.py
+++ b/libs/tktokenswap/test/conanfile.py
@@ -61,4 +61,4 @@ def package(self):
def requirements(self):
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/test/conanfile.py b/libs/tkwsm/test/conanfile.py
index 3041b8878e..ab74d320ad 100644
--- a/libs/tkwsm/test/conanfile.py
+++ b/libs/tkwsm/test/conanfile.py
@@ -62,4 +62,4 @@ def requirements(self):
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/pytket/conanfile.py b/pytket/conanfile.py
index 8eff94e165..74890df4fe 100644
--- a/pytket/conanfile.py
+++ b/pytket/conanfile.py
@@ -32,7 +32,7 @@ def package(self):
cmake.install()
def requirements(self):
- self.requires("tket/1.2.120@tket/stable")
+ self.requires("tket/1.2.121@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")
diff --git a/tket/conanfile.py b/tket/conanfile.py
index 1e948b370d..60a0a9624d 100644
--- a/tket/conanfile.py
+++ b/tket/conanfile.py
@@ -23,7 +23,7 @@
class TketConan(ConanFile):
name = "tket"
- version = "1.2.120"
+ version = "1.2.121"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
@@ -121,7 +121,7 @@ def requirements(self):
self.requires("tktokenswap/0.3.7@tket/stable")
self.requires("tkwsm/0.3.7@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")
From 18ceee4ed7118ea714dabfbe1b07829b50e177e2 Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Tue, 7 May 2024 13:28:59 +0100
Subject: [PATCH 15/27] Update to boost 1.85.0 (#1381)
---
.github/workflows/build-without-conan.yml | 6 +++---
build-without-conan.md | 6 +++---
pytket/conanfile.py | 6 +++---
tket/conanfile.py | 8 ++++----
4 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/build-without-conan.yml b/.github/workflows/build-without-conan.yml
index 3a4fa6a4b9..dfacbaae7b 100644
--- a/.github/workflows/build-without-conan.yml
+++ b/.github/workflows/build-without-conan.yml
@@ -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
diff --git a/build-without-conan.md b/build-without-conan.md
index 2968e8e486..b6cff2efe9 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
diff --git a/pytket/conanfile.py b/pytket/conanfile.py
index 74890df4fe..e222e20965 100644
--- a/pytket/conanfile.py
+++ b/pytket/conanfile.py
@@ -32,12 +32,12 @@ def package(self):
cmake.install()
def requirements(self):
- self.requires("tket/1.2.121@tket/stable")
+ self.requires("tket/1.2.122@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")
diff --git a/tket/conanfile.py b/tket/conanfile.py
index 60a0a9624d..ed514e1483 100644
--- a/tket/conanfile.py
+++ b/tket/conanfile.py
@@ -23,7 +23,7 @@
class TketConan(ConanFile):
name = "tket"
- version = "1.2.121"
+ version = "1.2.122"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
@@ -111,15 +111,15 @@ 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.6.0")
if self.build_proptest():
From 23bb57e809afe79a689a799e559bb6c780179911 Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Fri, 10 May 2024 07:47:30 +0100
Subject: [PATCH 16/27] Use `lark` package instead of deprecated `lark-parser`
(#1386)
---
nix-support/pytket.nix | 2 +-
nix-support/third-party-python-packages.nix | 12 +++++++-----
pytket/docs/changelog.rst | 1 +
pytket/pytket/qasm/qasm.py | 4 ++--
pytket/pytket/quipper/quipper.py | 19 +++++++++++--------
pytket/setup.py | 2 +-
6 files changed, 23 insertions(+), 17 deletions(-)
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..de9b5e2e61 100644
--- a/nix-support/third-party-python-packages.nix
+++ b/nix-support/third-party-python-packages.nix
@@ -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/docs/changelog.rst b/pytket/docs/changelog.rst
index a771bc3d77..5b47149167 100644
--- a/pytket/docs/changelog.rst
+++ b/pytket/docs/changelog.rst
@@ -8,6 +8,7 @@ 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`.
1.27.0 (April 2024)
-------------------
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..f2be0abcf8 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:
@@ -284,18 +285,20 @@ def cdiscard(self, t: List) -> CDiscard:
return CDiscard(wire=t[0])
def subroutine_call(self, t: List) -> SubroutineCall:
+ for i, ti in enumerate(t):
+ print(f"t[{i}] = {ti}")
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/setup.py b/pytket/setup.py
index bd9ff5d8dd..a99ff83bd0 100755
--- a/pytket/setup.py
+++ b/pytket/setup.py
@@ -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",
From 9f2a073fe85e77ffa32423cfd1395f81d37975c7 Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Mon, 13 May 2024 10:16:52 +0100
Subject: [PATCH 17/27] Escape underscores when converting to latex (#1385)
---
pytket/conanfile.py | 2 +-
pytket/docs/changelog.rst | 4 ++++
tket/conanfile.py | 2 +-
tket/src/Circuit/latex_drawing.cpp | 7 +++++--
tket/test/src/Circuit/test_Circ.cpp | 8 ++++++++
5 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/pytket/conanfile.py b/pytket/conanfile.py
index e222e20965..4360bf35ea 100644
--- a/pytket/conanfile.py
+++ b/pytket/conanfile.py
@@ -32,7 +32,7 @@ def package(self):
cmake.install()
def requirements(self):
- self.requires("tket/1.2.122@tket/stable")
+ self.requires("tket/1.2.123@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")
diff --git a/pytket/docs/changelog.rst b/pytket/docs/changelog.rst
index 5b47149167..b8c043a465 100644
--- a/pytket/docs/changelog.rst
+++ b/pytket/docs/changelog.rst
@@ -10,6 +10,10 @@ Features:
* Add two new status values for circuits on backends: "CANCELLING" and "RETRYING".
* Use `lark` package instead of deprecated `lark-parser`.
+Fixes:
+
+* Escape underscores in qubit and bit names when converting to latex.
+
1.27.0 (April 2024)
-------------------
diff --git a/tket/conanfile.py b/tket/conanfile.py
index ed514e1483..91176e68ed 100644
--- a/tket/conanfile.py
+++ b/tket/conanfile.py
@@ -23,7 +23,7 @@
class TketConan(ConanFile):
name = "tket"
- version = "1.2.122"
+ version = "1.2.123"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
diff --git a/tket/src/Circuit/latex_drawing.cpp b/tket/src/Circuit/latex_drawing.cpp
index bd47547283..56fab702bc 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"
@@ -287,14 +288,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/test/src/Circuit/test_Circ.cpp b/tket/test/src/Circuit/test_Circ.cpp
index a59d77692e..c09122a9f2 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 {
@@ -2694,6 +2695,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);
From fede38dd2e2afdf4b91101feeae724bb4928c2bd Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Mon, 13 May 2024 11:00:48 +0100
Subject: [PATCH 18/27] Remove debug prints. (#1387)
---
pytket/pytket/quipper/quipper.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/pytket/pytket/quipper/quipper.py b/pytket/pytket/quipper/quipper.py
index f2be0abcf8..5c0d4d8328 100644
--- a/pytket/pytket/quipper/quipper.py
+++ b/pytket/pytket/quipper/quipper.py
@@ -285,8 +285,6 @@ def cdiscard(self, t: List) -> CDiscard:
return CDiscard(wire=t[0])
def subroutine_call(self, t: List) -> SubroutineCall:
- for i, ti in enumerate(t):
- print(f"t[{i}] = {ti}")
repetitions = 1
if t[0] is not None:
assert isinstance(t[0], int)
From aafcd59d85c6c94707dc9669cadf28b4ce87ef03 Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Tue, 14 May 2024 09:05:44 +0100
Subject: [PATCH 19/27] Update to pybind11_json 0.2.14 (#1389)
---
.github/workflows/build-without-conan.yml | 6 +++---
.github/workflows/build_and_test.yml | 6 +++---
.github/workflows/linuxbuildwheel | 2 +-
.github/workflows/pytket_benchmarking.yml | 2 +-
.github/workflows/release.yml | 6 +++---
build-without-conan.md | 6 +++---
nix-support/third-party-python-packages.nix | 4 ++--
pytket/CMakeLists.txt | 4 ----
pytket/README.md | 2 +-
pytket/conanfile.py | 4 ++--
recipes/pybind11_json/all/conandata.yml | 3 +++
recipes/pybind11_json/config.yml | 2 ++
tket/conanfile.py | 2 +-
13 files changed, 25 insertions(+), 24 deletions(-)
diff --git a/.github/workflows/build-without-conan.yml b/.github/workflows/build-without-conan.yml
index dfacbaae7b..311d153b41 100644
--- a/.github/workflows/build-without-conan.yml
+++ b/.github/workflows/build-without-conan.yml
@@ -107,9 +107,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 c4ff3ef09f..eca21c7f2a 100644
--- a/.github/workflows/build_and_test.yml
+++ b/.github/workflows/build_and_test.yml
@@ -257,7 +257,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
@@ -370,7 +370,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
@@ -490,7 +490,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
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/pytket_benchmarking.yml b/.github/workflows/pytket_benchmarking.yml
index 171e4188d4..afae4750b2 100644
--- a/.github/workflows/pytket_benchmarking.yml
+++ b/.github/workflows/pytket_benchmarking.yml
@@ -42,7 +42,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_arm64
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6cca5016ab..8b70da70c5 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -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
@@ -136,7 +136,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_arm64
@@ -179,7 +179,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
python -m pip install -U pip build
python -m build --outdir "${{ github.workspace }}/wheelhouse"
diff --git a/build-without-conan.md b/build-without-conan.md
index b6cff2efe9..16668345b4 100644
--- a/build-without-conan.md
+++ b/build-without-conan.md
@@ -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/nix-support/third-party-python-packages.nix b/nix-support/third-party-python-packages.nix
index de9b5e2e61..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 ];
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/conanfile.py b/pytket/conanfile.py
index 4360bf35ea..3e6f3676e6 100644
--- a/pytket/conanfile.py
+++ b/pytket/conanfile.py
@@ -32,7 +32,7 @@ def package(self):
cmake.install()
def requirements(self):
- self.requires("tket/1.2.123@tket/stable")
+ self.requires("tket/1.2.124@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")
@@ -42,4 +42,4 @@ def requirements(self):
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/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/tket/conanfile.py b/tket/conanfile.py
index 91176e68ed..cd153cc891 100644
--- a/tket/conanfile.py
+++ b/tket/conanfile.py
@@ -23,7 +23,7 @@
class TketConan(ConanFile):
name = "tket"
- version = "1.2.123"
+ version = "1.2.124"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
From 385d14936491a0f080219676fadf575163cafde9 Mon Sep 17 00:00:00 2001
From: Alec Edgington <54802828+cqc-alec@users.noreply.github.com>
Date: Tue, 14 May 2024 15:37:31 +0100
Subject: [PATCH 20/27] Add workflow to automatically add new issues to
project. (#1390)
---
.github/workflows/issue-to-project.yml | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 .github/workflows/issue-to-project.yml
diff --git a/.github/workflows/issue-to-project.yml b/.github/workflows/issue-to-project.yml
new file mode 100644
index 0000000000..5c8ba372c5
--- /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@v0.6.1
+ with:
+ project-url: https://github.com/orgs/CQCL-DEV/projects/19
+ github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
From 8aa12f140dfdf8959712fa6fce90669222038e66 Mon Sep 17 00:00:00 2001
From: cqc-melf <70640934+cqc-melf@users.noreply.github.com>
Date: Tue, 14 May 2024 16:27:26 +0100
Subject: [PATCH 21/27] update tket email (#1391)
---
pytket/package.md | 2 +-
pytket/setup.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
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/setup.py b/pytket/setup.py
index a99ff83bd0..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",
From 436d3e372aea20b41df7756f64383fb4c01089ec Mon Sep 17 00:00:00 2001
From: yao-cqc <75305462+yao-cqc@users.noreply.github.com>
Date: Tue, 14 May 2024 17:05:54 +0100
Subject: [PATCH 22/27] Feature/greedy pauli simp (#1384)
* Add header and lookup data
* Implement GreedyPauliSimp
* Add to pass generators
* Add c++ tests
* Add to python binder
* Add python tests
* Regenerate stubs
* Bump tket version
* Update changelog
* Rename the header file for lookups
* Replace pace with gate_depth
* Remove unused includes
* Minor changes & fix grammar issues
---
pytket/binders/passes.cpp | 13 +
pytket/binders/transform.cpp | 16 +
pytket/conanfile.py | 2 +-
pytket/docs/changelog.rst | 1 +
pytket/pytket/_tket/passes.pyi | 10 +-
pytket/pytket/_tket/transform.pyi | 9 +
pytket/tests/passes_serialisation_test.py | 4 +
pytket/tests/predicates_test.py | 15 +
schemas/compiler_pass_v1.json | 27 +-
tket/CMakeLists.txt | 3 +
tket/conanfile.py | 2 +-
.../tket/Predicates/PassGenerators.hpp | 9 +
.../GreedyPauliOptimisation.hpp | 216 +++
.../GreedyPauliOptimisationLookupTables.hpp | 1569 +++++++++++++++++
tket/src/Predicates/CompilerPass.cpp | 4 +
tket/src/Predicates/PassGenerators.cpp | 34 +
.../GreedyPauliOptimisation.cpp | 947 ++++++++++
tket/test/CMakeLists.txt | 1 +
tket/test/src/test_GreedyPauli.cpp | 294 +++
tket/test/src/test_json.cpp | 1 +
20 files changed, 3173 insertions(+), 4 deletions(-)
create mode 100644 tket/include/tket/Transformations/GreedyPauliOptimisation.hpp
create mode 100644 tket/include/tket/Transformations/GreedyPauliOptimisationLookupTables.hpp
create mode 100644 tket/src/Transformations/GreedyPauliOptimisation.cpp
create mode 100644 tket/test/src/test_GreedyPauli.cpp
diff --git a/pytket/binders/passes.cpp b/pytket/binders/passes.cpp
index 22f07ff06f..bd621e0cae 100644
--- a/pytket/binders/passes.cpp
+++ b/pytket/binders/passes.cpp
@@ -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/transform.cpp b/pytket/binders/transform.cpp
index 91a1c12276..b912b4ebec 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"
@@ -407,6 +408,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 3e6f3676e6..0fc08c2376 100644
--- a/pytket/conanfile.py
+++ b/pytket/conanfile.py
@@ -32,7 +32,7 @@ def package(self):
cmake.install()
def requirements(self):
- self.requires("tket/1.2.124@tket/stable")
+ self.requires("tket/1.2.125@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")
diff --git a/pytket/docs/changelog.rst b/pytket/docs/changelog.rst
index b8c043a465..a238901f10 100644
--- a/pytket/docs/changelog.rst
+++ b/pytket/docs/changelog.rst
@@ -9,6 +9,7 @@ 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.
Fixes:
diff --git a/pytket/pytket/_tket/passes.pyi b/pytket/pytket/_tket/passes.pyi
index 22bc51873e..a73bbee83c 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.
@@ -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..5fd1e85040 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:
"""
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/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/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 cd153cc891..180dfffec2 100644
--- a/tket/conanfile.py
+++ b/tket/conanfile.py
@@ -23,7 +23,7 @@
class TketConan(ConanFile):
name = "tket"
- version = "1.2.124"
+ version = "1.2.125"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
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/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/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/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/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/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