diff --git a/tket/src/CMakeLists.txt b/tket/src/CMakeLists.txt index 03ed3e3333..7871017f9e 100644 --- a/tket/src/CMakeLists.txt +++ b/tket/src/CMakeLists.txt @@ -212,6 +212,7 @@ set(TKET_SOURCES ${TKET_TRANSFORM_DIR}/MeasurePass.cpp ${TKET_TRANSFORM_DIR}/ContextualReduction.cpp ${TKET_TRANSFORM_DIR}/ThreeQubitSquash.cpp + ${TKET_TRANSFORM_DIR}/CZReordering.cpp # Routing ${TKET_ROUTING_DIR}/Qubit_Placement.cpp diff --git a/tket/src/Transformations/CZReordering.cpp b/tket/src/Transformations/CZReordering.cpp new file mode 100644 index 0000000000..d4724c461c --- /dev/null +++ b/tket/src/Transformations/CZReordering.cpp @@ -0,0 +1,59 @@ +// Copyright 2019-2021 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 "Transform.hpp" + +namespace tket { + + // For a gate vertex and an edge, traverse back to find the associated input vertex. + Vertex get_input_from_vertex_edge(Circuit &circ, const Vertex ¤t_vertex, const Edge ¤t_outedge) { + Edge current_e = current_outedge; + Vertex current_v = current_vertex; + while (true) { + if (is_initial_q_type(circ.get_OpType_from_Vertex(current_v))) { + return current_v; + } + std::tie(current_v, current_e) = circ.get_prev_pair(current_v, current_e); + } + } + // Assume the circuit only contains CZ gates as the two qubit gate + Transform Transform::reorder_cz(const ArchitecturePtr& architecture) { + return Transform([architecture](Circuit &circ) { + bool success = false; + BGL_FORALL_VERTICES(vert, circ.dag, DAG) { + if (circ.get_OpType_from_Vertex(vert) == OpType::CZ) + { + // Check if this operation is valid + Vertex input_1 = get_input_from_vertex_edge(circ, vert, circ.get_nth_out_edge(vert, 0)); + Vertex input_2 = get_input_from_vertex_edge(circ, vert, circ.get_nth_out_edge(vert, 1)); + UnitID q_1 = circ.get_id_from_in(input_1); + UnitID q_2 = circ.get_id_from_in(input_2); + if (architecture->valid_operation({Node(q_1), Node(q_2)})) { + // Remove the vertex + circ.remove_vertex( + vert, Circuit::GraphRewiring::Yes, + Circuit::VertexDeletion::No); + // Get input edges for in_q and out_q + Edge edge_1 = circ.get_nth_out_edge(input_1, 0); + Edge edge_2 = circ.get_nth_out_edge(input_2, 0); + // Move the gate to the front + circ.rewire(vert, {edge_1, edge_2}, {EdgeType::Quantum, EdgeType::Quantum}); + success = true; + } + } + } + return success; + }); + } +} // namespace tket \ No newline at end of file diff --git a/tket/src/Transformations/Transform.hpp b/tket/src/Transformations/Transform.hpp index 06bed251ea..13c08c8a22 100644 --- a/tket/src/Transformations/Transform.hpp +++ b/tket/src/Transformations/Transform.hpp @@ -542,6 +542,11 @@ class Transform { */ static Transform simplify_measured(); + /////////////// + // Reordering CZ// + /////////////// + static Transform reorder_cz(const ArchitecturePtr& architecture); + /////////////////////////////////////////////// // Minor components for other Transform passes// /////////////////////////////////////////////// diff --git a/tket/tests/test_ReorderingCZ.cpp b/tket/tests/test_ReorderingCZ.cpp new file mode 100644 index 0000000000..6d774978a6 --- /dev/null +++ b/tket/tests/test_ReorderingCZ.cpp @@ -0,0 +1,37 @@ +#include +#include "Transformations/Transform.hpp" + +namespace tket { + SCENARIO("Test Transform::reorder_cz") { + std::vector nodes = {Node("test_node", 0), Node("test_node", 1), + Node("test_node", 2), Node("node_test", 3)}; + + // n0 -- n1 -- n2 -- n3 + Architecture architecture( + {{nodes[0], nodes[1]}, + {nodes[1], nodes[2]}, + {nodes[2], nodes[3]}}); + ArchitecturePtr shared_arc = std::make_shared(architecture); + Circuit circ(4); + std::vector qubits = circ.all_qubits(); + // Physically invalid operations + circ.add_op(OpType::CZ, {qubits[0], qubits[2]}); + circ.add_op(OpType::CZ, {qubits[0], qubits[3]}); + // Physically valid operations + circ.add_op(OpType::CZ, {qubits[0], qubits[1]}); + circ.add_op(OpType::CZ, {qubits[2], qubits[3]}); + std::map rename_map = { + {qubits[0], nodes[0]}, {qubits[1], nodes[1]}, {qubits[2], nodes[2]}, + {qubits[3], nodes[3]}}; + circ.rename_units(rename_map); + std::cout< commands = circ.get_commands(); + Command c0 = commands[0]; + Command c1 = commands[1]; + REQUIRE(shared_arc->valid_operation({Node(c0.get_args()[0]), Node(c0.get_args()[1])})); + REQUIRE(shared_arc->valid_operation({Node(c1.get_args()[0]), Node(c1.get_args()[1])})); + +} +} \ No newline at end of file diff --git a/tket/tests/tkettestsfiles.cmake b/tket/tests/tkettestsfiles.cmake index b5dd764afc..551df817d4 100644 --- a/tket/tests/tkettestsfiles.cmake +++ b/tket/tests/tkettestsfiles.cmake @@ -23,6 +23,7 @@ set(TEST_SOURCES ${TKET_TESTS_DIR}/tests_main.cpp ${TKET_TESTS_DIR}/testutil.cpp ${TKET_TESTS_DIR}/CircuitsForTesting.cpp + ${TKET_TESTS_DIR}/test_ReorderingCZ.cpp ${TKET_TESTS_DIR}/Utils/test_MatrixAnalysis.cpp ${TKET_TESTS_DIR}/Utils/test_CosSinDecomposition.cpp ${TKET_TESTS_DIR}/Graphs/EdgeSequence.cpp