diff --git a/tket/src/Predicates/PassGenerators.cpp b/tket/src/Predicates/PassGenerators.cpp index 2be0e53305..1273133df4 100644 --- a/tket/src/Predicates/PassGenerators.cpp +++ b/tket/src/Predicates/PassGenerators.cpp @@ -268,13 +268,18 @@ PassPtr gen_placement_pass_phase_poly(const Architecture& arc) { }; Transform t = Transform(trans); - PredicatePtrMap precons{}; + PredicatePtr no_wire_swap = std::make_shared(); + PredicatePtrMap precons{CompilationUnit::make_type_pair(no_wire_swap)}; + PredicatePtr placement_pred = std::make_shared(arc); PredicatePtr n_qubit_pred = std::make_shared(arc.n_nodes()); + PredicatePtrMap s_postcons{ CompilationUnit::make_type_pair(placement_pred), - CompilationUnit::make_type_pair(n_qubit_pred)}; + CompilationUnit::make_type_pair(n_qubit_pred), + CompilationUnit::make_type_pair(no_wire_swap)}; + PostConditions pc{s_postcons, {}, Guarantee::Preserve}; // record pass config nlohmann::json j; @@ -297,6 +302,10 @@ PassPtr aas_routing_pass( "Circuit has more qubits than the architecture has nodes."); } + // this pass is not able to handle implicit wire swaps + // this is additionally assured by a precondition of this pass + TKET_ASSERT(!circ.has_implicit_wireswaps()); + qubit_vector_t all_qu = circ.all_qubits(); Circuit input_circ = circ; @@ -379,9 +388,12 @@ PassPtr aas_routing_pass( PredicatePtr placedpred = std::make_shared(arc); PredicatePtr n_qubit_pred = std::make_shared(arc.n_nodes()); + PredicatePtr no_wire_swap = std::make_shared(); + PredicatePtrMap precons{ CompilationUnit::make_type_pair(placedpred), - CompilationUnit::make_type_pair(n_qubit_pred)}; + CompilationUnit::make_type_pair(n_qubit_pred), + CompilationUnit::make_type_pair(no_wire_swap)}; PredicatePtr postcon1 = std::make_shared(arc); std::pair pair1 = diff --git a/tket/src/Predicates/PassLibrary.cpp b/tket/src/Predicates/PassLibrary.cpp index 7abb46727e..b72a1c0d73 100644 --- a/tket/src/Predicates/PassLibrary.cpp +++ b/tket/src/Predicates/PassLibrary.cpp @@ -285,6 +285,8 @@ const PassPtr &ComposePhasePolyBoxes() { * converts a circuit containing all possible gates to a circuit * containing only phase poly boxes + H gates (and measure + reset + collapse * + barrier) + * this pass will replace all wire swaps in the given circuit and they will be + * included in the last or an additional phase poly boxes */ static const PassPtr pp([]() { Transform t = @@ -293,7 +295,13 @@ const PassPtr &ComposePhasePolyBoxes() { PredicatePtrMap precons{CompilationUnit::make_type_pair(noclas)}; - PostConditions postcon = {precons, {}, Guarantee::Clear}; + PredicatePtr no_wire_swap = std::make_shared(); + + PredicatePtrMap s_postcons{ + CompilationUnit::make_type_pair(noclas), + CompilationUnit::make_type_pair(no_wire_swap)}; + PostConditions postcon{s_postcons, {}, Guarantee::Preserve}; + nlohmann::json j; j["name"] = "ComposePhasePolyBoxes"; return std::make_shared(precons, t, postcon, j); diff --git a/tket/src/Predicates/include/Predicates/PassGenerators.hpp b/tket/src/Predicates/include/Predicates/PassGenerators.hpp index 36e873be56..09156c26b5 100644 --- a/tket/src/Predicates/include/Predicates/PassGenerators.hpp +++ b/tket/src/Predicates/include/Predicates/PassGenerators.hpp @@ -61,6 +61,7 @@ PassPtr gen_directed_cx_routing_pass( /** * execute architecture aware synthesis on a given architecture for an allready * place circuit, only for circuit which contains Cx+Rz+H gates + * this pass is not able to handle implicit wire swaps * @param arc architecture to route on * @param lookahead parameter for the recursion depth in the algorithm, the * value should be > 0 diff --git a/tket/src/Transformations/Decomposition.cpp b/tket/src/Transformations/Decomposition.cpp index 21b39e1eb4..ed63b20317 100644 --- a/tket/src/Transformations/Decomposition.cpp +++ b/tket/src/Transformations/Decomposition.cpp @@ -746,6 +746,17 @@ Transform decomp_boxes() { Transform compose_phase_poly_boxes() { return Transform([](Circuit &circ) { + // replace wireswaps with three CX + while (circ.has_implicit_wireswaps()) { + qubit_map_t perm = circ.implicit_qubit_permutation(); + for (const std::pair &pair : perm) { + if (pair.first != pair.second) { + circ.replace_implicit_wire_swap(pair.first, pair.second); + break; + } + } + } + CircToPhasePolyConversion conv = CircToPhasePolyConversion(circ); conv.convert(); circ = conv.get_circuit(); diff --git a/tket/tests/test_CompilerPass.cpp b/tket/tests/test_CompilerPass.cpp index 124077c896..90bec6ac8d 100644 --- a/tket/tests/test_CompilerPass.cpp +++ b/tket/tests/test_CompilerPass.cpp @@ -797,7 +797,7 @@ SCENARIO("rebase and decompose PhasePolyBox test") { Circuit result = cu.get_circ_ref(); REQUIRE(test_unitary_comparison(result, circ)); - REQUIRE(!NoWireSwapsPredicate().verify(result)); + REQUIRE(NoWireSwapsPredicate().verify(result)); } GIVEN("NoWireSwapsPredicate for ComposePhasePolyBoxes II") { Circuit circ(5); @@ -817,7 +817,73 @@ SCENARIO("rebase and decompose PhasePolyBox test") { Circuit result = cu.get_circ_ref(); REQUIRE(test_unitary_comparison(result, circ)); - REQUIRE(!NoWireSwapsPredicate().verify(result)); + REQUIRE(NoWireSwapsPredicate().verify(result)); + } + GIVEN("NoWireSwapsPredicate for ComposePhasePolyBoxes III") { + Circuit circ(5); + add_2qb_gates(circ, OpType::CX, {{0, 3}, {1, 4}}); + circ.add_op(OpType::SWAP, {3, 4}); + circ.add_op(OpType::CX, {2, 3}); + circ.add_op(OpType::Z, {3}); + circ.add_op(OpType::CX, {2, 3}); + circ.add_op(OpType::SWAP, {0, 1}); + circ.add_op(OpType::CX, {1, 4}); + circ.add_op(OpType::Z, {4}); + circ.add_op(OpType::CX, {1, 4}); + circ.add_op(OpType::SWAP, {1, 2}); + circ.add_op(OpType::SWAP, {2, 3}); + circ.add_op(OpType::CX, {0, 1}); + circ.add_op(OpType::CX, {1, 2}); + circ.add_op(OpType::CX, {2, 3}); + + REQUIRE(NoWireSwapsPredicate().verify(circ)); + circ.replace_SWAPs(); + REQUIRE(!NoWireSwapsPredicate().verify(circ)); + + CompilationUnit cu(circ); + REQUIRE(ComposePhasePolyBoxes()->apply(cu)); + Circuit result = cu.get_circ_ref(); + + REQUIRE(test_unitary_comparison(result, circ)); + REQUIRE(NoWireSwapsPredicate().verify(result)); + } + GIVEN("NoWireSwapsPredicate for aas I") { + std::vector nodes = {Node(0), Node(1), Node(2), Node(3), Node(4)}; + Architecture architecture( + {{nodes[0], nodes[1]}, + {nodes[1], nodes[2]}, + {nodes[2], nodes[3]}, + {nodes[3], nodes[4]}}); + + Circuit circ(5); + add_2qb_gates(circ, OpType::CX, {{0, 3}, {1, 4}}); + circ.add_op(OpType::SWAP, {3, 4}); + circ.add_op(OpType::CX, {2, 3}); + circ.add_op(OpType::Z, {3}); + circ.add_op(OpType::CX, {2, 3}); + circ.add_op(OpType::SWAP, {0, 1}); + circ.add_op(OpType::CX, {1, 4}); + circ.add_op(OpType::Z, {4}); + circ.add_op(OpType::CX, {1, 4}); + circ.add_op(OpType::SWAP, {1, 2}); + circ.add_op(OpType::SWAP, {2, 3}); + circ.add_op(OpType::CX, {0, 1}); + circ.add_op(OpType::CX, {1, 2}); + circ.add_op(OpType::CX, {2, 3}); + + REQUIRE(NoWireSwapsPredicate().verify(circ)); + circ.replace_SWAPs(); + REQUIRE(!NoWireSwapsPredicate().verify(circ)); + + CompilationUnit cu(circ); + + REQUIRE(gen_full_mapping_pass_phase_poly( + architecture, 1, aas::CNotSynthType::Rec) + ->apply(cu)); + Circuit result = cu.get_circ_ref(); + + REQUIRE(test_unitary_comparison(result, circ)); + REQUIRE(NoWireSwapsPredicate().verify(result)); } }