diff --git a/pytket/binders/circuit_library.cpp b/pytket/binders/circuit_library.cpp index 714a827d91..8ed5fc4c7f 100644 --- a/pytket/binders/circuit_library.cpp +++ b/pytket/binders/circuit_library.cpp @@ -68,6 +68,14 @@ PYBIND11_MODULE(circuit_library, library_m) { library_m.def( "CX_using_ZZMax", &CircPool::CX_using_ZZMax, "Equivalent to CX, using only ZZMax, Rx and Rz gates"); + library_m.def( + "CX_using_ISWAPMax", &CircPool::CX_using_ISWAPMax, + "Equivalent to CX, using only ISWAPMax and single-qubit gates"); + library_m.def( + "CX_using_ISWAPMax_and_swap", &CircPool::CX_using_ISWAPMax_and_swap, + "Equivalent to CX, using only ISWAPMax and single-qubit gates, up to a " + "wire swap that is encoded in the implicit qubit permutation of the " + "Circuit"); library_m.def( "CX_using_ZZPhase", &CircPool::CX_using_ZZPhase, "Equivalent to CX, using only ZZPhase, Rx and Rz gates"); @@ -213,6 +221,12 @@ PYBIND11_MODULE(circuit_library, library_m) { library_m.def( "ISWAP_using_CX", &CircPool::ISWAP_using_CX, "Equivalent to ISWAP, using CX, U3 and Rz gates"); + library_m.def( + "ISWAPMax_using_TK2", &CircPool::ISWAPMax_using_TK2, + "Equivalent to ISWAPMax, using a TK2 gate"); + library_m.def( + "ISWAPMax_using_CX", &CircPool::ISWAPMax_using_CX, + "Equivalent to ISWAPMax, using CX, U3 and Rz gates"); library_m.def( "XXPhase_using_TK2", &CircPool::XXPhase_using_TK2, "Equivalent to XXPhase, using a TK2 gate"); @@ -261,6 +275,14 @@ PYBIND11_MODULE(circuit_library, library_m) { "TK2_using_ZZMax_and_swap", &CircPool::TK2_using_ZZMax_and_swap, "Equivalent to TK2, up to a wire swap that is encoded in the implicit " "qubit permutation of the Circuit, using up to 3 ZZMax gates."); + library_m.def( + "TK2_using_ISWAPMax", &CircPool::TK2_using_ISWAPMax, + "Equivalent to TK2, using only ISWAPMax and single-qubit gates."); + library_m.def( + "TK2_using_ISWAPMax_and_swap", &CircPool::TK2_using_ISWAPMax_and_swap, + "Equivalent to TK2, using only ISWAPMax and single-qubit gates, up to a " + "wire swap that is encoded in the implicit qubit permutation of the " + "Circuit."); library_m.def( "XXPhase3_using_TK2", &CircPool::XXPhase3_using_TK2, "Equivalent to XXPhase3, using three TK2 gates"); diff --git a/pytket/conanfile.py b/pytket/conanfile.py index 6b87a6f43a..f468dd38a4 100644 --- a/pytket/conanfile.py +++ b/pytket/conanfile.py @@ -38,7 +38,7 @@ def requirements(self): self.requires("pybind11_json/tci-0.2.15@tket/stable") self.requires("symengine/tci-0.14.0@tket/stable") self.requires("tkassert/0.3.4@tket/stable") - self.requires("tket/2.1.1@tket/stable") + self.requires("tket/2.1.2@tket/stable") self.requires("tklog/0.3.3@tket/stable") self.requires("tkrng/0.3.3@tket/stable") self.requires("tktokenswap/0.3.11@tket/stable") diff --git a/pytket/docs/changelog.rst b/pytket/docs/changelog.rst index 117798c82c..672ad6e984 100644 --- a/pytket/docs/changelog.rst +++ b/pytket/docs/changelog.rst @@ -1,6 +1,12 @@ Changelog ========= +Unreleased +---------- + +* Add methods in `circuit_library` to convert `CX` and `TK2` to and from + `ISWAPMax`, and support for `AutoRebase` targeting `ISWAPMax`. + 2.1.0 (March 2025) ------------------ diff --git a/pytket/pytket/_tket/circuit_library.pyi b/pytket/pytket/_tket/circuit_library.pyi index 261cc52ed9..952f6d4e53 100644 --- a/pytket/pytket/_tket/circuit_library.pyi +++ b/pytket/pytket/_tket/circuit_library.pyi @@ -2,7 +2,7 @@ from __future__ import annotations import pytket._tket.circuit import sympy import typing -__all__ = ['BRIDGE', 'BRIDGE_using_CX_0', 'BRIDGE_using_CX_1', 'C3X_normal_decomp', 'C4X_normal_decomp', 'CCX', 'CCX_modulo_phase_shift', 'CCX_normal_decomp', 'CH_using_CX', 'CRx_using_CX', 'CRx_using_TK2', 'CRy_using_CX', 'CRy_using_TK2', 'CRz_using_CX', 'CRz_using_TK2', 'CSWAP_using_CX', 'CSX_using_CX', 'CSXdg_using_CX', 'CS_using_CX', 'CSdg_using_CX', 'CU1_using_CX', 'CU1_using_TK2', 'CU3_using_CX', 'CV_using_CX', 'CVdg_using_CX', 'CX', 'CX_S_CX_reduced', 'CX_S_V_XC_reduced', 'CX_VS_CX_reduced', 'CX_V_CX_reduced', 'CX_V_S_XC_reduced', 'CX_XC_reduced', 'CX_using_AAMS', 'CX_using_ECR', 'CX_using_TK2', 'CX_using_XXPhase_0', 'CX_using_XXPhase_1', 'CX_using_ZZMax', 'CX_using_ZZPhase', 'CX_using_flipped_CX', 'CY_using_CX', 'CZ_using_CX', 'CnX_vchain_decomp', 'ECR_using_CX', 'ESWAP_using_CX', 'ESWAP_using_TK2', 'FSim_using_CX', 'FSim_using_TK2', 'H_CZ_H', 'ISWAP_using_CX', 'ISWAP_using_TK2', 'NPhasedX_using_PhasedX', 'PhasedISWAP_using_CX', 'PhasedISWAP_using_TK2', 'Rx_using_GPI', 'Ry_using_GPI', 'Rz_using_GPI', 'SWAP_using_CX_0', 'SWAP_using_CX_1', 'TK1_to_PhasedXRz', 'TK1_to_RxRy', 'TK1_to_RzH', 'TK1_to_RzRx', 'TK1_to_RzSX', 'TK1_to_RzXSX', 'TK1_to_TK1', 'TK1_to_U3', 'TK1_using_GPI', 'TK2_using_3xCX', 'TK2_using_AAMS', 'TK2_using_CX', 'TK2_using_CX_and_swap', 'TK2_using_TK2', 'TK2_using_TK2_or_swap', 'TK2_using_ZZMax', 'TK2_using_ZZMax_and_swap', 'TK2_using_ZZPhase', 'TK2_using_ZZPhase_and_swap', 'TK2_using_normalised_TK2', 'X', 'X1_CX', 'XXPhase3_using_CX', 'XXPhase3_using_TK2', 'XXPhase_using_AAMS', 'XXPhase_using_CX', 'XXPhase_using_TK2', 'YYPhase_using_AAMS', 'YYPhase_using_CX', 'YYPhase_using_TK2', 'Z0_CX', 'ZZMax_using_CX', 'ZZPhase_using_AAMS', 'ZZPhase_using_CX', 'ZZPhase_using_TK2', 'approx_TK2_using_1xCX', 'approx_TK2_using_1xZZPhase', 'approx_TK2_using_2xCX', 'approx_TK2_using_2xZZPhase', 'ladder_down', 'ladder_down_2', 'ladder_up'] +__all__ = ['BRIDGE', 'BRIDGE_using_CX_0', 'BRIDGE_using_CX_1', 'C3X_normal_decomp', 'C4X_normal_decomp', 'CCX', 'CCX_modulo_phase_shift', 'CCX_normal_decomp', 'CH_using_CX', 'CRx_using_CX', 'CRx_using_TK2', 'CRy_using_CX', 'CRy_using_TK2', 'CRz_using_CX', 'CRz_using_TK2', 'CSWAP_using_CX', 'CSX_using_CX', 'CSXdg_using_CX', 'CS_using_CX', 'CSdg_using_CX', 'CU1_using_CX', 'CU1_using_TK2', 'CU3_using_CX', 'CV_using_CX', 'CVdg_using_CX', 'CX', 'CX_S_CX_reduced', 'CX_S_V_XC_reduced', 'CX_VS_CX_reduced', 'CX_V_CX_reduced', 'CX_V_S_XC_reduced', 'CX_XC_reduced', 'CX_using_AAMS', 'CX_using_ECR', 'CX_using_ISWAPMax', 'CX_using_ISWAPMax_and_swap', 'CX_using_TK2', 'CX_using_XXPhase_0', 'CX_using_XXPhase_1', 'CX_using_ZZMax', 'CX_using_ZZPhase', 'CX_using_flipped_CX', 'CY_using_CX', 'CZ_using_CX', 'CnX_vchain_decomp', 'ECR_using_CX', 'ESWAP_using_CX', 'ESWAP_using_TK2', 'FSim_using_CX', 'FSim_using_TK2', 'H_CZ_H', 'ISWAPMax_using_CX', 'ISWAPMax_using_TK2', 'ISWAP_using_CX', 'ISWAP_using_TK2', 'NPhasedX_using_PhasedX', 'PhasedISWAP_using_CX', 'PhasedISWAP_using_TK2', 'Rx_using_GPI', 'Ry_using_GPI', 'Rz_using_GPI', 'SWAP_using_CX_0', 'SWAP_using_CX_1', 'TK1_to_PhasedXRz', 'TK1_to_RxRy', 'TK1_to_RzH', 'TK1_to_RzRx', 'TK1_to_RzSX', 'TK1_to_RzXSX', 'TK1_to_TK1', 'TK1_to_U3', 'TK1_using_GPI', 'TK2_using_3xCX', 'TK2_using_AAMS', 'TK2_using_CX', 'TK2_using_CX_and_swap', 'TK2_using_ISWAPMax', 'TK2_using_ISWAPMax_and_swap', 'TK2_using_TK2', 'TK2_using_TK2_or_swap', 'TK2_using_ZZMax', 'TK2_using_ZZMax_and_swap', 'TK2_using_ZZPhase', 'TK2_using_ZZPhase_and_swap', 'TK2_using_normalised_TK2', 'X', 'X1_CX', 'XXPhase3_using_CX', 'XXPhase3_using_TK2', 'XXPhase_using_AAMS', 'XXPhase_using_CX', 'XXPhase_using_TK2', 'YYPhase_using_AAMS', 'YYPhase_using_CX', 'YYPhase_using_TK2', 'Z0_CX', 'ZZMax_using_CX', 'ZZPhase_using_AAMS', 'ZZPhase_using_CX', 'ZZPhase_using_TK2', 'approx_TK2_using_1xCX', 'approx_TK2_using_1xZZPhase', 'approx_TK2_using_2xCX', 'approx_TK2_using_2xZZPhase', 'ladder_down', 'ladder_down_2', 'ladder_up'] def BRIDGE() -> pytket._tket.circuit.Circuit: """ Just a BRIDGE[0,1,2] gate @@ -139,6 +139,14 @@ def CX_using_ECR() -> pytket._tket.circuit.Circuit: """ Equivalent to CX, using only ECR, Rx and U3 gates """ +def CX_using_ISWAPMax() -> pytket._tket.circuit.Circuit: + """ + Equivalent to CX, using only ISWAPMax and single-qubit gates + """ +def CX_using_ISWAPMax_and_swap() -> pytket._tket.circuit.Circuit: + """ + Equivalent to CX, using only ISWAPMax and single-qubit gates, up to a wire swap that is encoded in the implicit qubit permutation of the Circuit + """ def CX_using_TK2() -> pytket._tket.circuit.Circuit: """ Equivalent to CX, using a TK2 and single-qubit gates @@ -204,6 +212,14 @@ def H_CZ_H() -> pytket._tket.circuit.Circuit: """ H[1]; CZ[0,1]; H[1] """ +def ISWAPMax_using_CX() -> pytket._tket.circuit.Circuit: + """ + Equivalent to ISWAPMax, using CX, U3 and Rz gates + """ +def ISWAPMax_using_TK2() -> pytket._tket.circuit.Circuit: + """ + Equivalent to ISWAPMax, using a TK2 gate + """ def ISWAP_using_CX(arg0: sympy.Expr | float) -> pytket._tket.circuit.Circuit: """ Equivalent to ISWAP, using CX, U3 and Rz gates @@ -302,6 +318,14 @@ def TK2_using_CX_and_swap(arg0: sympy.Expr | float, arg1: sympy.Expr | float, ar The decomposition minimizes the number of CX gates. """ +def TK2_using_ISWAPMax(arg0: sympy.Expr | float, arg1: sympy.Expr | float, arg2: sympy.Expr | float) -> pytket._tket.circuit.Circuit: + """ + Equivalent to TK2, using only ISWAPMax and single-qubit gates. + """ +def TK2_using_ISWAPMax_and_swap(arg0: sympy.Expr | float, arg1: sympy.Expr | float, arg2: sympy.Expr | float) -> pytket._tket.circuit.Circuit: + """ + Equivalent to TK2, using only ISWAPMax and single-qubit gates, up to a wire swap that is encoded in the implicit qubit permutation of the Circuit. + """ def TK2_using_TK2(arg0: sympy.Expr | float, arg1: sympy.Expr | float, arg2: sympy.Expr | float) -> pytket._tket.circuit.Circuit: """ A circuit of a single TK2 gate with given parameters diff --git a/pytket/pytket/circuit_library/__init__.py b/pytket/pytket/circuit_library/__init__.py index 1c45edd9ff..dca6d94954 100644 --- a/pytket/pytket/circuit_library/__init__.py +++ b/pytket/pytket/circuit_library/__init__.py @@ -48,6 +48,8 @@ CX_using_AAMS, CX_using_ECR, CX_using_flipped_CX, + CX_using_ISWAPMax, + CX_using_ISWAPMax_and_swap, CX_using_TK2, CX_using_XXPhase_0, CX_using_XXPhase_1, @@ -66,6 +68,8 @@ FSim_using_TK2, ISWAP_using_CX, ISWAP_using_TK2, + ISWAPMax_using_CX, + ISWAPMax_using_TK2, NPhasedX_using_PhasedX, PhasedISWAP_using_CX, PhasedISWAP_using_TK2, @@ -84,6 +88,8 @@ TK2_using_AAMS, TK2_using_CX, TK2_using_CX_and_swap, + TK2_using_ISWAPMax, + TK2_using_ISWAPMax_and_swap, TK2_using_normalised_TK2, TK2_using_TK2_or_swap, TK2_using_ZZMax, diff --git a/pytket/tests/predicates_test.py b/pytket/tests/predicates_test.py index 33ff66ca1d..7e3c476a49 100644 --- a/pytket/tests/predicates_test.py +++ b/pytket/tests/predicates_test.py @@ -859,6 +859,12 @@ def test_rz_sx_decomp() -> None: assert c == comp +def test_iswapmax_autorebase() -> None: + c = Circuit(2).H(0).CX(0, 1) + assert AutoRebase({OpType.ISWAPMax, OpType.TK1}).apply(c) + assert c.n_gates_of_type(OpType.ISWAPMax) <= 2 + + def test_flatten_relabel_pass() -> None: c = Circuit(3) c.H(1).H(2) diff --git a/tket/conanfile.py b/tket/conanfile.py index 21804c6816..a49265e109 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "2.1.1" + version = "2.1.2" package_type = "library" license = "Apache 2" homepage = "https://github.com/CQCL/tket" diff --git a/tket/include/tket/Circuit/CircPool.hpp b/tket/include/tket/Circuit/CircPool.hpp index b5570f75f4..df67ec4c40 100644 --- a/tket/include/tket/Circuit/CircPool.hpp +++ b/tket/include/tket/Circuit/CircPool.hpp @@ -40,6 +40,14 @@ const Circuit &CX_using_ECR(); /** Equivalent to CX, using only ZZMax, Rx and Rz gates */ const Circuit &CX_using_ZZMax(); +/** Equivalent to CX, using only ISWAPMax and single-qubit gates */ +const Circuit &CX_using_ISWAPMax(); + +/** Equivalent to CX, using only ISWAPMax and single-qubit gates, with an + * implicit swap. + */ +const Circuit &CX_using_ISWAPMax_and_swap(); + /** Equivalent to CX, using only ZZPhase, Rx and Rz gates */ const Circuit &CX_using_ZZPhase(); @@ -196,6 +204,12 @@ const Circuit &ECR_using_CX(); /** Equivalent to ZZMax, using CX, Rz and U3 gates */ const Circuit &ZZMax_using_CX(); +/** Equivalent to ISWAPMax, using a TK2 gate **/ +const Circuit &ISWAPMax_using_TK2(); + +/** Equivalent to ISWAPMax, using CX, Rz and U3 gates **/ +const Circuit &ISWAPMax_using_CX(); + /** Equivalent to CRz, using a TK2 and TK1 gates */ Circuit CRz_using_TK2(const Expr &alpha); @@ -424,6 +438,16 @@ Circuit TK2_using_ZZMax(const Expr &alpha, const Expr &beta, const Expr &gamma); Circuit TK2_using_ZZMax_and_swap( const Expr &alpha, const Expr &beta, const Expr &gamma); +/** Equivalent to TK2, using only ISWAPMax and single-qubit gates */ +Circuit TK2_using_ISWAPMax( + const Expr &alpha, const Expr &beta, const Expr &gamma); + +/** Equivalent to TK2, using only ISWAPMax and single-qubit gates, with an + * implicit swap. + */ +Circuit TK2_using_ISWAPMax_and_swap( + const Expr &alpha, const Expr &beta, const Expr &gamma); + /** Equivalent to XXPhase3, using three TK2 gates */ Circuit XXPhase3_using_TK2(const Expr &alpha); diff --git a/tket/src/Circuit/CircPool.cpp b/tket/src/Circuit/CircPool.cpp index 3d78eda2e0..027f5060f6 100644 --- a/tket/src/Circuit/CircPool.cpp +++ b/tket/src/Circuit/CircPool.cpp @@ -105,6 +105,34 @@ const Circuit &CX_using_ZZMax() { return *C; } +const Circuit &CX_using_ISWAPMax() { + static std::unique_ptr C = std::make_unique([]() { + Circuit c(2); + c.add_op(OpType::ISWAPMax, {0, 1}); + c.add_op(OpType::H, {0}); + c.add_op(OpType::ISWAPMax, {0, 1}); + c.add_op(OpType::Sdg, {0}); + c.add_op(OpType::V, {1}); + return c; + }()); + return *C; +} + +const Circuit &CX_using_ISWAPMax_and_swap() { + static std::unique_ptr C = std::make_unique([]() { + Circuit c(2); + c.add_op(OpType::H, {1}); + c.add_op(OpType::Sdg, {0}); + c.add_op(OpType::Sdg, {1}); + c.add_op(OpType::ISWAPMax, {0, 1}); + c.add_op(OpType::H, {0}); + c.add_op(OpType::SWAP, {0, 1}); + c.replace_SWAPs(); + return c; + }()); + return *C; +} + const Circuit &CX_using_ZZPhase() { static std::unique_ptr C = std::make_unique([]() { Circuit c(2); @@ -684,6 +712,31 @@ const Circuit &ZZMax_using_CX() { return *C; } +const Circuit &ISWAPMax_using_TK2() { + static std::unique_ptr C = std::make_unique([]() { + Circuit c(2); + c.add_op(OpType::TK2, {-0.5, -0.5, 0}, {0, 1}); + return c; + }()); + return *C; +} + +const Circuit &ISWAPMax_using_CX() { + static std::unique_ptr C = std::make_unique([]() { + Circuit c(2); + c.add_op(OpType::U3, {0.5, -0.5, 0.5}, {0}); + c.add_op(OpType::U3, {0.5, -0.5, 0.5}, {1}); + c.add_op(OpType::CX, {0, 1}); + c.add_op(OpType::U3, {-0.5, -0.5, 0.5}, {0}); + c.add_op(OpType::Rz, -0.5, {1}); + c.add_op(OpType::CX, {0, 1}); + c.add_op(OpType::U3, {-0.5, -0.5, 0.5}, {0}); + c.add_op(OpType::U3, {-0.5, -0.5, 0.5}, {1}); + return c; + }()); + return *C; +} + Circuit CRz_using_TK2(const Expr &alpha) { Circuit c(2); c.add_op(OpType::TK1, {0.5, 0.5, 1}, {0}); @@ -1116,6 +1169,41 @@ Circuit TK2_using_ZZMax_and_swap( return TK2_using_ZZMax(alpha, beta, gamma); } +Circuit TK2_using_ISWAPMax( + const Expr &alpha, const Expr &beta, const Expr &gamma) { + Circuit c = TK2_using_CX(alpha, beta, gamma); + // Find the CX gates and replace them with ISWAPMax. + VertexSet bin; + BGL_FORALL_VERTICES(v, c.dag, DAG) { + Op_ptr op = c.get_Op_ptr_from_Vertex(v); + if (op->get_type() == OpType::CX) { + c.substitute(CX_using_ISWAPMax(), v, Circuit::VertexDeletion::No); + bin.insert(v); + } + } + c.remove_vertices( + bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes); + return c; +} + +Circuit TK2_using_ISWAPMax_and_swap( + const Expr &alpha, const Expr &beta, const Expr &gamma) { + Circuit c = TK2_using_CX_and_swap(alpha, beta, gamma); + // Find the CX gates and replace them with ISWAPMax. + VertexSet bin; + BGL_FORALL_VERTICES(v, c.dag, DAG) { + Op_ptr op = c.get_Op_ptr_from_Vertex(v); + if (op->get_type() == OpType::CX) { + c.substitute( + CX_using_ISWAPMax_and_swap(), v, Circuit::VertexDeletion::No); + bin.insert(v); + } + } + c.remove_vertices( + bin, Circuit::GraphRewiring::No, Circuit::VertexDeletion::Yes); + return c; +} + Circuit XXPhase3_using_TK2(const Expr &alpha) { Circuit c(3); c.add_op(OpType::TK2, {alpha, 0, 0}, {0, 1}); diff --git a/tket/src/Circuit/CircUtils.cpp b/tket/src/Circuit/CircUtils.cpp index 744d770eab..48d80805d7 100644 --- a/tket/src/Circuit/CircUtils.cpp +++ b/tket/src/Circuit/CircUtils.cpp @@ -475,6 +475,8 @@ Circuit with_TK2(Gate_ptr op) { switch (op->get_type()) { case OpType::ISWAP: return CircPool::ISWAP_using_TK2(params[0]); + case OpType::ISWAPMax: + return CircPool::ISWAPMax_using_TK2(); case OpType::PhasedISWAP: return CircPool::PhasedISWAP_using_TK2(params[0], params[1]); case OpType::XXPhase: @@ -603,7 +605,7 @@ Circuit with_CX(Gate_ptr op) { case OpType::Sycamore: return CircPool::FSim_using_CX(1. / 2., 1. / 6.); case OpType::ISWAPMax: - return CircPool::ISWAP_using_CX(1.); + return CircPool::ISWAPMax_using_CX(); case OpType::PhasedISWAP: return CircPool::PhasedISWAP_using_CX(params[0], params[1]); case OpType::NPhasedX: diff --git a/tket/src/Predicates/PassGenerators.cpp b/tket/src/Predicates/PassGenerators.cpp index b50d0d0933..049a188294 100644 --- a/tket/src/Predicates/PassGenerators.cpp +++ b/tket/src/Predicates/PassGenerators.cpp @@ -163,13 +163,17 @@ find_tk1_replacement(const OpTypeSet& gateset) { throw Unsupported("No known decomposition from TK1 to available gateset."); } -static Circuit find_cx_replacement(const OpTypeSet& gateset) { +static Circuit find_cx_replacement(const OpTypeSet& gateset, bool allow_swaps) { if (gateset.contains(OpType::CX)) { return CircPool::CX(); } if (gateset.contains(OpType::ZZMax)) { return CircPool::CX_using_ZZMax(); } + if (gateset.contains(OpType::ISWAPMax)) { + return allow_swaps ? CircPool::CX_using_ISWAPMax_and_swap() + : CircPool::CX_using_ISWAPMax(); + } if (gateset.contains(OpType::XXPhase)) { return CircPool::CX_using_XXPhase_0(); } @@ -187,35 +191,28 @@ static Circuit find_cx_replacement(const OpTypeSet& gateset) { static std::function find_tk2_replacement(const OpTypeSet& gateset, bool allow_swaps) { - if (!allow_swaps) { - if (gateset.contains(OpType::TK2)) { - return CircPool::TK2_using_TK2; - } - if (gateset.contains(OpType::ZZPhase)) { - return CircPool::TK2_using_ZZPhase; - } - if (gateset.contains(OpType::CX)) { - return CircPool::TK2_using_CX; - } - if (gateset.contains(OpType::ZZMax)) { - return CircPool::TK2_using_ZZMax; - } - if (gateset.contains(OpType::AAMS)) { - return CircPool::TK2_using_AAMS; - } - } else { - if (gateset.contains(OpType::TK2)) { - return CircPool::TK2_using_TK2_or_swap; - } - if (gateset.contains(OpType::ZZPhase)) { - return CircPool::TK2_using_ZZPhase_and_swap; - } - if (gateset.contains(OpType::CX)) { - return CircPool::TK2_using_CX_and_swap; - } - if (gateset.contains(OpType::ZZMax)) { - return CircPool::TK2_using_ZZMax_and_swap; - } + if (gateset.contains(OpType::TK2)) { + return allow_swaps ? CircPool::TK2_using_TK2_or_swap + : CircPool::TK2_using_TK2; + } + if (gateset.contains(OpType::ZZPhase)) { + return allow_swaps ? CircPool::TK2_using_ZZPhase_and_swap + : CircPool::TK2_using_ZZPhase; + } + if (gateset.contains(OpType::CX)) { + return allow_swaps ? CircPool::TK2_using_CX_and_swap + : CircPool::TK2_using_CX; + } + if (gateset.contains(OpType::ZZMax)) { + return allow_swaps ? CircPool::TK2_using_ZZMax_and_swap + : CircPool::TK2_using_ZZMax; + } + if (gateset.contains(OpType::ISWAPMax)) { + return allow_swaps ? CircPool::TK2_using_ISWAPMax_and_swap + : CircPool::TK2_using_ISWAPMax; + } + if (gateset.contains(OpType::AAMS)) { + return CircPool::TK2_using_AAMS; } throw Unsupported("No known decomposition from TK2 to available gateset."); } @@ -236,7 +233,8 @@ PassPtr gen_auto_rebase_pass(const OpTypeSet& allowed_gates, bool allow_swaps) { } try { return Transforms::rebase_factory( - allowed_gates, find_cx_replacement(allowed_gates), tk1_replacement); + allowed_gates, find_cx_replacement(allowed_gates, allow_swaps), + tk1_replacement); } catch (const Unsupported&) { throw Unsupported( "No known decomposition from CX or TK2 to available gateset."); diff --git a/tket/test/src/Circuit/test_CircPool.cpp b/tket/test/src/Circuit/test_CircPool.cpp index ae356e1565..0aae85c8f4 100644 --- a/tket/test/src/Circuit/test_CircPool.cpp +++ b/tket/test/src/Circuit/test_CircPool.cpp @@ -64,6 +64,36 @@ SCENARIO("Simple CircPool identities") { orig.add_op(OpType::TK1, {0.2, 0.3, 0.4}, {0}); res = CircPool::tk1_to_rxry(0.2, 0.3, 0.4); } + GIVEN("CX_using_ISWAPMax") { + orig = Circuit(2); + orig.add_op(OpType::CX, {0, 1}); + res = CircPool::CX_using_ISWAPMax(); + } + GIVEN("CX_using_ISWAPMax_and_swap") { + orig = Circuit(2); + orig.add_op(OpType::CX, {0, 1}); + res = CircPool::CX_using_ISWAPMax_and_swap(); + } + GIVEN("TK2_using_ISWAPMax") { + orig = Circuit(2); + orig.add_op(OpType::TK2, {0.2, 0.3, 0.4}, {0, 1}); + res = CircPool::TK2_using_ISWAPMax(0.2, 0.3, 0.4); + } + GIVEN("TK2_using_ISWAPMax_and_swap") { + orig = Circuit(2); + orig.add_op(OpType::TK2, {0.2, 0.3, 0.4}, {0, 1}); + res = CircPool::TK2_using_ISWAPMax_and_swap(0.2, 0.3, 0.4); + } + GIVEN("ISWAPMax_using_TK2") { + orig = Circuit(2); + orig.add_op(OpType::ISWAPMax, {0, 1}); + res = CircPool::ISWAPMax_using_TK2(); + } + GIVEN("ISWAPMax_using_CX") { + orig = Circuit(2); + orig.add_op(OpType::ISWAPMax, {0, 1}); + res = CircPool::ISWAPMax_using_CX(); + } auto u_orig = tket_sim::get_unitary(orig); auto u_res = tket_sim::get_unitary(res); REQUIRE(u_res.isApprox(u_orig)); diff --git a/tket/test/src/test_CompilerPass.cpp b/tket/test/src/test_CompilerPass.cpp index 27f5db6002..e16a6d8587 100644 --- a/tket/test/src/test_CompilerPass.cpp +++ b/tket/test/src/test_CompilerPass.cpp @@ -2289,6 +2289,21 @@ SCENARIO("AutoRebase") { gen_auto_rebase_pass({OpType::CRz, OpType::TK1}, false), Unsupported); REQUIRE_THROWS_AS(gen_auto_rebase_pass({}, false), Unsupported); } + GIVEN("Rebasing to ISWAPMax") { + Circuit circ(2); + circ.add_op(OpType::CZ, {0, 1}); + Circuit circ1 = circ; + PassPtr p_noswaps = + gen_auto_rebase_pass({OpType::ISWAPMax, OpType::TK1}, false); + PassPtr p_swapsok = + gen_auto_rebase_pass({OpType::ISWAPMax, OpType::TK1}, true); + CompilationUnit cu(circ); + CompilationUnit cu1(circ1); + CHECK(p_noswaps->apply(cu)); + CHECK(p_swapsok->apply(cu1)); + REQUIRE(test_unitary_comparison(circ, cu.get_circ_ref())); + REQUIRE(test_unitary_comparison(circ1, cu1.get_circ_ref())); + } } SCENARIO("AutoSquash") {