diff --git a/pytket/binders/mapping.cpp b/pytket/binders/mapping.cpp index d19ee7db01..b1f9622dcb 100644 --- a/pytket/binders/mapping.cpp +++ b/pytket/binders/mapping.cpp @@ -40,24 +40,23 @@ PYBIND11_MODULE(mapping, m) { "whole circuits.") .def( py::init< - const std::function( - const Circuit&, const ArchitecturePtr&)>&, - const std::function, + const std::function< + std::tuple( + const Circuit&, const ArchitecturePtr&)>&, unsigned, unsigned>(), "Constructor for a routing method defined by partially routing " "subcircuits.\n\n:param route_subcircuit: A function declaration " "that given a Circuit and Architecture object, returns a tuple " - "containing a new modified circuit, the initial logical to physical " + "containing a bool informing MappingManager whether to substitute " + "the returned circuit into the circuit being routed, " + "a new modified circuit, the initial logical to physical " "qubit mapping of the modified circuit and the permutation of " "logical to physical qubit mapping given operations in the " - "modified circuit\n:param check_subcircuit: A function declaration " - "that given a Circuit and Architecture object, returns a bool " - "stating whether the given method can modify the " - "given circuit\n:param max_size: The maximum number of gates " + "modified circuit\n:param max_size: The maximum number of gates " "permitted in a subcircuit\n:param max_depth: The maximum permitted " "depth of a subcircuit.", - py::arg("route_subcircuit"), py::arg("check_subcircuit"), - py::arg("max_size"), py::arg("max_depth")); + py::arg("route_subcircuit"), py::arg("max_size"), + py::arg("max_depth")); py::class_< LexiRouteRoutingMethod, std::shared_ptr, diff --git a/pytket/tests/mapping_test.py b/pytket/tests/mapping_test.py index e9079e4509..57ee0281b1 100644 --- a/pytket/tests/mapping_test.py +++ b/pytket/tests/mapping_test.py @@ -23,7 +23,7 @@ # simple deterministic heuristic used for testing purposes def route_subcircuit_func( circuit: Circuit, architecture: Architecture -) -> Tuple[Circuit, Dict[Node, Node], Dict[Node, Node]]: +) -> Tuple[bool, Circuit, Dict[Node, Node], Dict[Node, Node]]: # make a replacement circuit with identical unitds replacement_circuit = Circuit() for qb in circuit.qubits: @@ -60,7 +60,7 @@ def route_subcircuit_func( for com in circuit.get_commands(): rp_qubits = [permutation_map[relabelling_map[q]] for q in com.qubits] if len(com.qubits) > 2: - raise ValueError("Command must have maximum two qubits") + return (False, Circuit(), {}, {}) if len(com.qubits) == 1: replacement_circuit.add_gate(com.op.type, rp_qubits) if len(com.qubits) == 2: @@ -90,15 +90,13 @@ def route_subcircuit_func( replacement_circuit.add_gate(com.op.type, rp_qubits) - return (replacement_circuit, relabelling_map, permutation_map) + return (True, replacement_circuit, relabelling_map, permutation_map) -def check_subcircuit_func_true(circuit: Circuit, architecture: Architecture) -> bool: - return True - - -def check_subcircuit_func_false(circuit: Circuit, architecture: Architecture) -> bool: - return False +def route_subcircuit_func_false( + circuit: Circuit, architecture: Architecture +) -> Tuple[bool, Circuit, Dict[Node, Node], Dict[Node, Node]]: + return (False, Circuit(), {}, {}) def test_LexiRouteRoutingMethod() -> None: @@ -127,7 +125,7 @@ def test_RoutingMethodCircuit_custom() -> None: test_mm = MappingManager(test_a) test_mm.route_circuit( test_c, - [RoutingMethodCircuit(route_subcircuit_func, check_subcircuit_func_true, 5, 5)], + [RoutingMethodCircuit(route_subcircuit_func, 5, 5)], ) routed_commands = test_c.get_commands() @@ -152,9 +150,7 @@ def test_RoutingMethodCircuit_custom_list() -> None: test_mm.route_circuit( test_c, [ - RoutingMethodCircuit( - route_subcircuit_func, check_subcircuit_func_false, 5, 5 - ), + RoutingMethodCircuit(route_subcircuit_func_false, 5, 5), LexiRouteRoutingMethod(), ], ) @@ -173,9 +169,7 @@ def test_RoutingMethodCircuit_custom_list() -> None: test_mm.route_circuit( test_c, [ - RoutingMethodCircuit( - route_subcircuit_func, check_subcircuit_func_true, 5, 5 - ), + RoutingMethodCircuit(route_subcircuit_func, 5, 5), LexiRouteRoutingMethod(), ], ) diff --git a/tket/src/Mapping/LexiRoute.cpp b/tket/src/Mapping/LexiRoute.cpp index ed3b8480cd..890394d4c0 100644 --- a/tket/src/Mapping/LexiRoute.cpp +++ b/tket/src/Mapping/LexiRoute.cpp @@ -509,18 +509,12 @@ void LexiRoute::solve(unsigned lookahead) { LexiRouteRoutingMethod::LexiRouteRoutingMethod(unsigned _max_depth) : max_depth_(_max_depth){}; -bool LexiRouteRoutingMethod::check_method( - const std::shared_ptr& /*mapping_frontier*/, - const ArchitecturePtr& /*architecture*/) const { - return true; -} - -unit_map_t LexiRouteRoutingMethod::routing_method( +std::pair LexiRouteRoutingMethod::routing_method( std::shared_ptr& mapping_frontier, const ArchitecturePtr& architecture) const { LexiRoute lr(architecture, mapping_frontier); lr.solve(this->max_depth_); - return {}; + return {true, {}}; } unsigned LexiRouteRoutingMethod::get_max_depth() const { diff --git a/tket/src/Mapping/MappingManager.cpp b/tket/src/Mapping/MappingManager.cpp index c7864d64c5..7ae89751af 100644 --- a/tket/src/Mapping/MappingManager.cpp +++ b/tket/src/Mapping/MappingManager.cpp @@ -71,20 +71,19 @@ bool MappingManager::route_circuit_with_maps( bool circuit_modified = !check_finish(); while (!check_finish()) { // The order methods are passed in std::vector is - // the order they are iterated through to call "check_method" + // the order they are run // If a method performs better but only on specific subcircuits, // rank it earlier in the passed vector bool valid_methods = false; for (const auto& rm : routing_methods) { // true => can use held routing method - if (rm->check_method(mapping_frontier, this->architecture_)) { + std::pair bool_map = + rm->routing_method(mapping_frontier, this->architecture_); + if (bool_map.first) { valid_methods = true; - unit_map_t partial_permutation = - rm->routing_method(mapping_frontier, this->architecture_); - - if (partial_permutation.size() > 0) { + if (bool_map.second.size() > 0) { std::map node_map; - for (const auto& x : partial_permutation) { + for (const auto& x : bool_map.second) { node_map.insert({Node(x.first), Node(x.second)}); } for (const std::pair& swap : diff --git a/tket/src/Mapping/MultiGateReorder.cpp b/tket/src/Mapping/MultiGateReorder.cpp index 7065c15e75..7a3d539e92 100644 --- a/tket/src/Mapping/MultiGateReorder.cpp +++ b/tket/src/Mapping/MultiGateReorder.cpp @@ -185,7 +185,7 @@ static void partial_rewire( } } -void MultiGateReorder::solve(unsigned max_depth, unsigned max_size) { +bool MultiGateReorder::solve(unsigned max_depth, unsigned max_size) { // Assume the frontier has been advanced // store a copy of the original this->mapping_frontier_->quantum_boundray @@ -199,6 +199,9 @@ void MultiGateReorder::solve(unsigned max_depth, unsigned max_size) { // Get a subcircuit only for iterating vertices Subcircuit circ = this->mapping_frontier_->get_frontier_subcircuit(max_depth, max_size); + + // for return value + bool modification_made = false; // since we assume that the frontier has been advanced // we are certain that any multi-q vert lies after the frontier for (const Vertex &vert : circ.verts) { @@ -213,6 +216,7 @@ void MultiGateReorder::solve(unsigned max_depth, unsigned max_size) { this->mapping_frontier_->circuit_, this->u_frontier_edges_, vert); if (commute_pairs != std::nullopt) { + modification_made = true; partial_rewire( vert, this->mapping_frontier_->circuit_, (*commute_pairs).first, (*commute_pairs).second); @@ -227,44 +231,18 @@ void MultiGateReorder::solve(unsigned max_depth, unsigned max_size) { } // Return the quantum boundary to its original setting this->mapping_frontier_->set_quantum_boundary(copy); + return modification_made; } MultiGateReorderRoutingMethod::MultiGateReorderRoutingMethod( unsigned _max_depth, unsigned _max_size) : max_depth_(_max_depth), max_size_(_max_size) {} -bool MultiGateReorderRoutingMethod::check_method( - const std::shared_ptr &mapping_frontier, - const ArchitecturePtr &architecture) const { - const EdgeVec u_frontier_edges = - convert_u_frontier_to_edges(*frontier_convert_vertport_to_edge( - mapping_frontier->circuit_, mapping_frontier->quantum_boundary)); - - Subcircuit circ = mapping_frontier->get_frontier_subcircuit( - this->max_depth_, this->max_size_); - // since we assume that the frontier has been advanced - // we are certain that any multi-q vert lies after the frontier - for (const Vertex &vert : circ.verts) { - if (is_multiq_quantum_gate(mapping_frontier->circuit_, vert) && - is_physically_permitted(mapping_frontier, architecture, vert)) { - std::optional> commute_pairs = - try_find_commute_edges( - mapping_frontier->circuit_, u_frontier_edges, vert); - - if (commute_pairs != std::nullopt) { - return true; - } - } - } - return false; -} - -unit_map_t MultiGateReorderRoutingMethod::routing_method( +std::pair MultiGateReorderRoutingMethod::routing_method( std::shared_ptr &mapping_frontier, const ArchitecturePtr &architecture) const { MultiGateReorder mr(architecture, mapping_frontier); - mr.solve(this->max_depth_, this->max_size_); - return {}; + return {mr.solve(this->max_depth_, this->max_size_), {}}; } unsigned MultiGateReorderRoutingMethod::get_max_depth() const { diff --git a/tket/src/Mapping/RoutingMethodCircuit.cpp b/tket/src/Mapping/RoutingMethodCircuit.cpp index 474253a9d7..6657dfacad 100644 --- a/tket/src/Mapping/RoutingMethodCircuit.cpp +++ b/tket/src/Mapping/RoutingMethodCircuit.cpp @@ -17,32 +17,15 @@ namespace tket { RoutingMethodCircuit::RoutingMethodCircuit( - const std::function( + const std::function( const Circuit&, const ArchitecturePtr&)> _route_subcircuit, - const std::function - _check_subcircuit, unsigned _max_size, unsigned _max_depth) : route_subcircuit_(_route_subcircuit), - check_subcircuit_(_check_subcircuit), max_size_(_max_size), max_depth_(_max_depth){}; -bool RoutingMethodCircuit::check_method( - const std::shared_ptr& mapping_frontier, - const ArchitecturePtr& architecture) const { - // Get circuit, pass to held check method - Subcircuit frontier_subcircuit = mapping_frontier->get_frontier_subcircuit( - this->max_depth_, this->max_size_); - Circuit frontier_circuit = - mapping_frontier->circuit_.subcircuit(frontier_subcircuit); - frontier_circuit.rename_units( - mapping_frontier->get_default_to_quantum_boundary_unit_map()); - - return this->check_subcircuit_(frontier_circuit, architecture); -} - -unit_map_t RoutingMethodCircuit::routing_method( +std::pair RoutingMethodCircuit::routing_method( std::shared_ptr& mapping_frontier, const ArchitecturePtr& architecture) const { // Produce subcircuit and circuit @@ -54,15 +37,19 @@ unit_map_t RoutingMethodCircuit::routing_method( mapping_frontier->get_default_to_quantum_boundary_unit_map()); // get routed subcircuit - std::tuple routed_subcircuit = + std::tuple routed_subcircuit = this->route_subcircuit_(frontier_circuit, architecture); - unit_map_t new_labelling = std::get<1>(routed_subcircuit); + + if (!std::get<0>(routed_subcircuit)) { + return {false, {}}; + } // update unit id at boundary in case of relabelling - mapping_frontier->update_quantum_boundary_uids(new_labelling); + mapping_frontier->update_quantum_boundary_uids( + std::get<2>(routed_subcircuit)); unit_map_t swap_permutation; - for (const auto& pair : new_labelling) { + for (const auto& pair : std::get<2>(routed_subcircuit)) { if (pair.first != pair.second && architecture->node_exists(Node(pair.first))) { swap_permutation.insert(pair); @@ -70,14 +57,14 @@ unit_map_t RoutingMethodCircuit::routing_method( } // permute edges held by unitid at out boundary due to swaps mapping_frontier->permute_subcircuit_q_out_hole( - std::get<2>(routed_subcircuit), frontier_subcircuit); + std::get<3>(routed_subcircuit), frontier_subcircuit); // substitute old boundary with new cirucit - std::get<0>(routed_subcircuit).flatten_registers(); + std::get<1>(routed_subcircuit).flatten_registers(); mapping_frontier->circuit_.substitute( - std::get<0>(routed_subcircuit), frontier_subcircuit); + std::get<1>(routed_subcircuit), frontier_subcircuit); // return initial unit_map_t incase swap network required - return swap_permutation; + return {true, swap_permutation}; } } // namespace tket \ No newline at end of file diff --git a/tket/src/Mapping/include/Mapping/LexiRoute.hpp b/tket/src/Mapping/include/Mapping/LexiRoute.hpp index ad39ca26cd..99229895a3 100644 --- a/tket/src/Mapping/include/Mapping/LexiRoute.hpp +++ b/tket/src/Mapping/include/Mapping/LexiRoute.hpp @@ -169,21 +169,15 @@ class LexiRouteRoutingMethod : public RoutingMethod { */ LexiRouteRoutingMethod(unsigned _max_depth = 100); - /** - * @return true if method can route subcircuit, false if not - */ - bool check_method( - const std::shared_ptr& /*mapping_frontier*/, - const ArchitecturePtr& /*architecture*/) const override; - /** * @param mapping_frontier Contains boundary of routed/unrouted circuit for * modifying * @param architecture Architecture providing physical constraints - * @return Map between relabelled Qubit, always empty. + * + * @return true bool, map between relabelled Qubit, always empty. * */ - unit_map_t routing_method( + std::pair routing_method( std::shared_ptr& mapping_frontier, const ArchitecturePtr& architecture) const override; diff --git a/tket/src/Mapping/include/Mapping/MultiGateReorder.hpp b/tket/src/Mapping/include/Mapping/MultiGateReorder.hpp index cb7a51c300..63434fb383 100644 --- a/tket/src/Mapping/include/Mapping/MultiGateReorder.hpp +++ b/tket/src/Mapping/include/Mapping/MultiGateReorder.hpp @@ -34,8 +34,10 @@ class MultiGateReorder { * Try to commute any multi-qubit gates to the quantum frontier * @param max_depth Maximum number of layers of gates checked for commutation. * @param max_size Maximum number of gates checked for commutation. + * + * @return true if modification made */ - void solve(unsigned max_depth, unsigned max_size); + bool solve(unsigned max_depth, unsigned max_size); private: // Architecture all new physical operations must respect @@ -55,21 +57,15 @@ class MultiGateReorderRoutingMethod : public RoutingMethod { MultiGateReorderRoutingMethod( unsigned _max_depth = 10, unsigned _max_size = 10); - /** - * @return true if method can route subcircuit, false if not - */ - bool check_method( - const std::shared_ptr& /*mapping_frontier*/, - const ArchitecturePtr& /*architecture*/) const override; - /** * @param mapping_frontier Contains boundary of routed/unrouted circuit for * modifying * @param architecture Architecture providing physical constraints - * @return Logical to Physical mapping at boundary due to modification. + * @return Whether circuit is modified and Logical to Physical mapping at + * boundary due to modification (always empty) * */ - unit_map_t routing_method( + std::pair routing_method( std::shared_ptr& mapping_frontier, const ArchitecturePtr& architecture) const override; diff --git a/tket/src/Mapping/include/Mapping/RoutingMethod.hpp b/tket/src/Mapping/include/Mapping/RoutingMethod.hpp index 23041e2105..de4e440ebf 100644 --- a/tket/src/Mapping/include/Mapping/RoutingMethod.hpp +++ b/tket/src/Mapping/include/Mapping/RoutingMethod.hpp @@ -23,42 +23,29 @@ class RoutingMethod { public: RoutingMethod(){}; virtual ~RoutingMethod() {} - /** - * check_method returns true if held method can route given circuit. - * This is completed by converting boundary subcircuit to a Circuit object - * which is then passed to check_subcircuit_ as defined in constructor. - * - * Overloded parameter mapping_frontier contains boundary of gates to be - * checked for method. - * Overloaded parameter architecture is the architecture method works with - * if permitted. - * @return true if method can route subcircuit, false if not - */ - virtual bool check_method( - const std::shared_ptr& /*mapping_frontier*/, - const ArchitecturePtr& /*architecture*/) const { - return false; - } /** * routing_method modifies circuit held in mapping_frontier with gates for the * purpose of moving circuit closer to one physically permitted by given - * architecture. Returns new initial mapping of qubits incase permutation via - * swap network is then required, or new ancilla qubits are added. - * This is completed by converting boundaty subcircuit in mapping frontier to - * a Circuit object which is then passed to route_subcircuit_ as defined in - * the constructor. + * architecture. Returns a pair with a bool returning whether any modification + * was made and a new initial mapping of qubits in case permutation via swap + * network is then required, or new ancilla qubits are added. This is + * completed by converting boundary subcircuit in mapping frontier to a + * Circuit object which is then passed to route_subcircuit_ as defined in the + * constructor. * * Overloaded parameter mapping_frontier contains boundary of routed/unrouted * circuit for modifying. * Overloaded parameter architecture provides physical constraints - * @return Logical to Physical mapping at boundary due to modification. + * + * @return Whether circuit is modified and Logical to Physical mapping at + * boundary due to modification. * */ - virtual unit_map_t routing_method( + virtual std::pair routing_method( std::shared_ptr& /*mapping_frontier*/, const ArchitecturePtr& /*architecture*/) const { - return {}; + return {false, {}}; } virtual nlohmann::json serialize() const { diff --git a/tket/src/Mapping/include/Mapping/RoutingMethodCircuit.hpp b/tket/src/Mapping/include/Mapping/RoutingMethodCircuit.hpp index 63a5ca7b15..3189bb6504 100644 --- a/tket/src/Mapping/include/Mapping/RoutingMethodCircuit.hpp +++ b/tket/src/Mapping/include/Mapping/RoutingMethodCircuit.hpp @@ -26,27 +26,15 @@ class RoutingMethodCircuit : public RoutingMethod { * in the incremental routing of full circuits. * * @param _route_subcircuit Function ptr for partial routing method - * @param _check_subcircuit Function ptr for confirming if method sufficient * @param _max_size Max number of gates in partial routing circuit * @param _max_depth Max depth of partial routing circuit */ RoutingMethodCircuit( - const std::function( + const std::function( const Circuit&, const ArchitecturePtr&)> _route_subcircuit, - const std::function - _check_subcircuit, unsigned _max_size, unsigned _max_depth); - /** - * @param mapping_frontier Contains boundary of gates to be checked for method - * @param architecture Architecture method would work with if permitted - * @return true if method can route subcircuit, false if not - */ - bool check_method( - const std::shared_ptr& mapping_frontier, - const ArchitecturePtr& architecture) const; - /** * @param mapping_frontier Contains boundary of routed/unrouted circuit for * modifying @@ -54,16 +42,14 @@ class RoutingMethodCircuit : public RoutingMethod { * @return Logical to Physical mapping at boundary due to modification. * */ - unit_map_t routing_method( + std::pair routing_method( std::shared_ptr& mapping_frontier, const ArchitecturePtr& architecture) const; private: - const std::function( + const std::function( const Circuit&, const ArchitecturePtr&)> route_subcircuit_; - const std::function - check_subcircuit_; unsigned max_size_, max_depth_; }; diff --git a/tket/tests/test_LexiRoute.cpp b/tket/tests/test_LexiRoute.cpp index 77a74dee6d..ac20c92285 100644 --- a/tket/tests/test_LexiRoute.cpp +++ b/tket/tests/test_LexiRoute.cpp @@ -21,7 +21,6 @@ #include "Predicates/CompilerPass.hpp" #include "Predicates/PassGenerators.hpp" #include "Predicates/PassLibrary.hpp" -// #include "Transformations/Transform.hpp" #include "Transformations/Decomposition.hpp" #include "testutil.hpp" namespace tket { @@ -525,10 +524,10 @@ SCENARIO("Test LexiRouteRoutingMethod") { std::shared_ptr mf = std::make_shared(circ); LexiRouteRoutingMethod lrrm(100); - REQUIRE(lrrm.check_method(mf, shared_arc)); - - unit_map_t init_map = lrrm.routing_method(mf, shared_arc); - REQUIRE(init_map.size() == 0); + std::pair bool_init_map = + lrrm.routing_method(mf, shared_arc); + REQUIRE(bool_init_map.first); + REQUIRE(bool_init_map.second.size() == 0); std::vector commands = mf->circuit_.get_commands(); REQUIRE(commands.size() == 9); @@ -567,8 +566,10 @@ SCENARIO("Test LexiRouteRoutingMethod") { std::shared_ptr mf = std::make_shared(circ); LexiRouteRoutingMethod lrrm(100); - unit_map_t init_map = lrrm.routing_method(mf, shared_arc); - REQUIRE(init_map.size() == 0); + std::pair bool_init_map = + lrrm.routing_method(mf, shared_arc); + REQUIRE(bool_init_map.first); + REQUIRE(bool_init_map.second.size() == 0); std::vector commands = mf->circuit_.get_commands(); REQUIRE(commands.size() == 10); Command swap_c = commands[0]; @@ -630,7 +631,6 @@ SCENARIO("Test MappingManager::route_circuit with lc_route_subcircuit") { std::vector vrm = { std::make_shared(100)}; - REQUIRE(vrm[0]->check_method(mf, shared_arc)); bool res = mm.route_circuit(circ, vrm); diff --git a/tket/tests/test_MappingManager.cpp b/tket/tests/test_MappingManager.cpp index 6e9c03a4e9..17edafbead 100644 --- a/tket/tests/test_MappingManager.cpp +++ b/tket/tests/test_MappingManager.cpp @@ -25,12 +25,6 @@ class TokenSwappingTester : public RoutingMethod { public: TokenSwappingTester(){}; - bool check_method( - const std::shared_ptr& /*mapping_frontier*/, - const ArchitecturePtr& /*architecture*/) const { - return true; - } - /** * @param mapping_frontier Contains boundary of routed/unrouted circuit for * modifying @@ -38,11 +32,11 @@ class TokenSwappingTester : public RoutingMethod { * @return Logical to Physical mapping at boundary due to modification. * */ - unit_map_t routing_method( + std::pair routing_method( std::shared_ptr& /*mapping_frontier*/, const ArchitecturePtr& /*architecture*/) const { Node node0("test_node", 0), node1("test_node", 1), node2("test_node", 2); - return {{node0, node1}, {node1, node2}, {node2, node0}}; + return {true, {{node0, node1}, {node1, node2}, {node2, node0}}}; } }; diff --git a/tket/tests/test_MultiGateReorder.cpp b/tket/tests/test_MultiGateReorder.cpp index a51d569794..b8a9185aaa 100644 --- a/tket/tests/test_MultiGateReorder.cpp +++ b/tket/tests/test_MultiGateReorder.cpp @@ -282,10 +282,11 @@ SCENARIO("Test MultiGateReorderRoutingMethod") { std::make_shared(circ); mf->advance_frontier_boundary(shared_arc); MultiGateReorderRoutingMethod mrrm; - REQUIRE(mrrm.check_method(mf, shared_arc)); - unit_map_t init_map = mrrm.routing_method(mf, shared_arc); - REQUIRE(init_map.size() == 0); + std::pair bool_init_map = + mrrm.routing_method(mf, shared_arc); + REQUIRE(bool_init_map.first); + REQUIRE(bool_init_map.second.size() == 0); std::vector commands = circ.get_commands(); for (unsigned i = 0; i < 5; i++) { std::vector nodes; @@ -307,10 +308,11 @@ SCENARIO("Test MultiGateReorderRoutingMethod") { std::make_shared(circ2); mf2->advance_frontier_boundary(shared_arc); MultiGateReorderRoutingMethod mrrm2(4, 4); - REQUIRE(mrrm2.check_method(mf2, shared_arc)); - unit_map_t init_map2 = mrrm2.routing_method(mf2, shared_arc); - REQUIRE(init_map2.size() == 0); + std::pair bool_init_map2 = + mrrm2.routing_method(mf2, shared_arc); + REQUIRE(bool_init_map2.first); + REQUIRE(bool_init_map2.second.size() == 0); std::vector commands2 = circ2.get_commands(); for (unsigned i = 0; i < 4; i++) { std::vector nodes; diff --git a/tket/tests/test_RoutingMethod.cpp b/tket/tests/test_RoutingMethod.cpp index 3cc51cbb0a..56d9f82eca 100644 --- a/tket/tests/test_RoutingMethod.cpp +++ b/tket/tests/test_RoutingMethod.cpp @@ -15,9 +15,10 @@ SCENARIO("Test RoutingMethod default methods.") { ArchitecturePtr shared_arc = std::make_shared(arc); Circuit circ(3); std::shared_ptr mf = std::make_shared(circ); - REQUIRE(!rm.check_method(mf, shared_arc)); unit_map_t empty; - REQUIRE(rm.routing_method(mf, shared_arc) == empty); + std::pair rm_return = rm.routing_method(mf, shared_arc); + REQUIRE(!rm_return.first); + REQUIRE(rm_return.second == empty); } // These two method are not completely reflective of what is necessary for @@ -31,71 +32,84 @@ bool test_check_method(const Circuit& c, const ArchitecturePtr& a) { } } -std::tuple test_routing_method_mf_swap_perm( - const Circuit& c, const ArchitecturePtr& a) { - Circuit copy(c); - std::vector qs = copy.all_qubits(); - std::vector ns = a->get_all_nodes_vec(); - // enforce in tests that ns >= qs, this is testing purposes only so fine... - unit_map_t rename_map, final_map; - for (unsigned i = 0; i < qs.size(); i++) { - rename_map.insert({qs[i], ns[i]}); - final_map.insert({ns[i], ns[i]}); +std::tuple +test_routing_method_mf_swap_perm(const Circuit& c, const ArchitecturePtr& a) { + if (c.n_qubits() > 2 && a->n_nodes() > 2) { + Circuit copy(c); + std::vector qs = copy.all_qubits(); + std::vector ns = a->get_all_nodes_vec(); + // enforce in tests that ns >= qs, this is testing purposes only so fine... + unit_map_t rename_map, final_map; + for (unsigned i = 0; i < qs.size(); i++) { + rename_map.insert({qs[i], ns[i]}); + final_map.insert({ns[i], ns[i]}); + } + copy.rename_units(rename_map); + MappingFrontier mf(copy); + // n.b. add_swap permutes out edge of both boundaries, + mf.add_swap(Node("t", 0), Node("t", 1)); + + return {true, copy, rename_map, final_map}; + } else { + return {false, Circuit(), {}, {}}; } - copy.rename_units(rename_map); - MappingFrontier mf(copy); - // n.b. add_swap permutes out edge of both boundaries, - mf.add_swap(Node("t", 0), Node("t", 1)); - - return std::make_tuple(copy, rename_map, final_map); } -std::tuple test_routing_method_mf_swap_no_perm( +std::tuple +test_routing_method_mf_swap_no_perm( const Circuit& c, const ArchitecturePtr& a) { - Circuit copy(c); - std::vector qs = copy.all_qubits(); - std::vector ns = a->get_all_nodes_vec(); - // enforce in tests that ns >= qs, this is testing purposes only so fine... - unit_map_t rename_map, final_map; - for (unsigned i = 0; i < qs.size(); i++) { - rename_map.insert({qs[i], ns[i]}); - final_map.insert({ns[i], ns[i]}); + if (c.n_qubits() > 2 && a->n_nodes() > 2) { + Circuit copy(c); + std::vector qs = copy.all_qubits(); + std::vector ns = a->get_all_nodes_vec(); + // enforce in tests that ns >= qs, this is testing purposes only so fine... + unit_map_t rename_map, final_map; + for (unsigned i = 0; i < qs.size(); i++) { + rename_map.insert({qs[i], ns[i]}); + final_map.insert({ns[i], ns[i]}); + } + copy.rename_units(rename_map); + MappingFrontier mf(copy); + // n.b. add_swap permutes out edge of both boundaries, + mf.add_swap(Node("t", 0), Node("t", 1)); + final_map[Node("t", 0)] = Node("t", 1); + final_map[Node("t", 1)] = Node("t", 0); + + return {true, copy, rename_map, final_map}; + } else { + return {false, Circuit(), {}, {}}; } - copy.rename_units(rename_map); - MappingFrontier mf(copy); - // n.b. add_swap permutes out edge of both boundaries, - mf.add_swap(Node("t", 0), Node("t", 1)); - final_map[Node("t", 0)] = Node("t", 1); - final_map[Node("t", 1)] = Node("t", 0); - - return std::make_tuple(copy, rename_map, final_map); } -std::tuple test_routing_method_circuit_no_perm( +std::tuple +test_routing_method_circuit_no_perm( const Circuit& c, const ArchitecturePtr& a) { - Circuit copy(c.n_qubits()); - copy.add_op(OpType::SWAP, {0, 1}); - copy.add_op(OpType::CX, {1, 0}); - copy.add_op(OpType::CX, {1, 0}); - - std::vector qs = copy.all_qubits(); - std::vector ns = a->get_all_nodes_vec(); - // enforce in tests that ns >= qs, this is testing purposes only so fine... - unit_map_t rename_map, final_map; - for (unsigned i = 0; i < qs.size(); i++) { - rename_map.insert({qs[i], ns[i]}); - final_map.insert({ns[i], ns[i]}); + if (c.n_qubits() > 2 && a->n_nodes() > 2) { + Circuit copy(c.n_qubits()); + copy.add_op(OpType::SWAP, {0, 1}); + copy.add_op(OpType::CX, {1, 0}); + copy.add_op(OpType::CX, {1, 0}); + + std::vector qs = copy.all_qubits(); + std::vector ns = a->get_all_nodes_vec(); + // enforce in tests that ns >= qs, this is testing purposes only so fine... + unit_map_t rename_map, final_map; + for (unsigned i = 0; i < qs.size(); i++) { + rename_map.insert({qs[i], ns[i]}); + final_map.insert({ns[i], ns[i]}); + } + copy.rename_units(rename_map); + MappingFrontier mf(copy); + final_map[Node("t", 0)] = Node("t", 1); + final_map[Node("t", 1)] = Node("t", 0); + return {true, copy, rename_map, final_map}; + } else { + return {false, Circuit(), {}, {}}; } - copy.rename_units(rename_map); - MappingFrontier mf(copy); - final_map[Node("t", 0)] = Node("t", 1); - final_map[Node("t", 1)] = Node("t", 0); - return std::make_tuple(copy, rename_map, final_map); } -SCENARIO("Test RoutingMethodCircuit::check_method") { - RoutingMethodCircuit rmc( - test_routing_method_mf_swap_no_perm, test_check_method, 5, 5); +SCENARIO("Test RoutingMethodCircuit checking criteria") { + RoutingMethodCircuit rmc(test_routing_method_mf_swap_no_perm, 5, 5); Circuit c(2), circ3(3); c.add_op(OpType::CX, {0, 1}); circ3.add_op(OpType::CX, {0, 2}); @@ -108,27 +122,29 @@ SCENARIO("Test RoutingMethodCircuit::check_method") { {{Node("t", 1), Node("t", 0)}, {Node("t", 2), Node("t", 1)}}); ArchitecturePtr shared_arc = std::make_shared(arc); - REQUIRE(!rmc.check_method(mf2, shared_arc)); - REQUIRE(rmc.check_method(mf3, shared_arc)); + std::pair res0 = rmc.routing_method(mf2, shared_arc); + REQUIRE(!res0.first); + std::pair res1 = rmc.routing_method(mf3, shared_arc); + REQUIRE(res1.first); } -SCENARIO("Test RoutingMethodCircuit::route_method") { - Circuit comp(2); +SCENARIO("Test RoutingMethodCircuit::routing_method") { + Circuit comp(3); comp.add_op(OpType::SWAP, {0, 1}); comp.add_op(OpType::CX, {1, 0}); comp.add_op(OpType::CX, {1, 0}); comp.add_op(OpType::CX, {1, 0}); comp.add_op(OpType::CX, {1, 0}); auto qbs = comp.all_qubits(); - unit_map_t rename_map = {{qbs[0], Node("t", 0)}, {qbs[1], Node("t", 1)}}; + unit_map_t rename_map = { + {qbs[0], Node("t", 0)}, {qbs[1], Node("t", 1)}, {qbs[2], Node("t", 2)}}; comp.rename_units(rename_map); qubit_map_t permutation = { {Node("t", 0), Node("t", 1)}, {Node("t", 1), Node("t", 0)}}; comp.permute_boundary_output(permutation); GIVEN("Non-implicit Permutation method, using MappingFrontier::add_swap") { - RoutingMethodCircuit rmc( - test_routing_method_mf_swap_no_perm, test_check_method, 2, 2); - Circuit c(2); + RoutingMethodCircuit rmc(test_routing_method_mf_swap_no_perm, 2, 2); + Circuit c(3); c.add_op(OpType::CX, {0, 1}); c.add_op(OpType::CX, {0, 1}); c.add_op(OpType::CX, {0, 1}); @@ -138,14 +154,15 @@ SCENARIO("Test RoutingMethodCircuit::route_method") { Architecture arc( {{Node("t", 1), Node("t", 0)}, {Node("t", 2), Node("t", 1)}}); ArchitecturePtr shared_arc = std::make_shared(arc); - unit_map_t output = rmc.routing_method(mf, shared_arc), empty; - REQUIRE(output == empty); + std::pair output = rmc.routing_method(mf, shared_arc); + unit_map_t empty; + REQUIRE(output.first); + REQUIRE(output.second == empty); REQUIRE(c == comp); } GIVEN("Non-implicit Permutation method, using circuit replacement") { - RoutingMethodCircuit rmc( - test_routing_method_circuit_no_perm, test_check_method, 2, 2); - Circuit c(2); + RoutingMethodCircuit rmc(test_routing_method_circuit_no_perm, 2, 2); + Circuit c(3); c.add_op(OpType::CX, {0, 1}); c.add_op(OpType::CX, {0, 1}); c.add_op(OpType::CX, {0, 1}); @@ -155,14 +172,15 @@ SCENARIO("Test RoutingMethodCircuit::route_method") { Architecture arc( {{Node("t", 1), Node("t", 0)}, {Node("t", 2), Node("t", 1)}}); ArchitecturePtr shared_arc = std::make_shared(arc); - unit_map_t output = rmc.routing_method(mf, shared_arc), empty; - REQUIRE(output == empty); + std::pair output = rmc.routing_method(mf, shared_arc); + unit_map_t empty; + REQUIRE(output.first); + REQUIRE(output.second == empty); REQUIRE(c == comp); } GIVEN("Implicit Permutation method, using MappingFrontier::add_swap") { - RoutingMethodCircuit rmc( - test_routing_method_mf_swap_perm, test_check_method, 2, 2); - Circuit c(2); + RoutingMethodCircuit rmc(test_routing_method_mf_swap_perm, 2, 2); + Circuit c(3); c.add_op(OpType::CX, {0, 1}); c.add_op(OpType::CX, {0, 1}); c.add_op(OpType::CX, {0, 1}); @@ -172,17 +190,20 @@ SCENARIO("Test RoutingMethodCircuit::route_method") { Architecture arc( {{Node("t", 1), Node("t", 0)}, {Node("t", 2), Node("t", 1)}}); ArchitecturePtr shared_arc = std::make_shared(arc); - unit_map_t output = rmc.routing_method(mf, shared_arc), empty; - REQUIRE(output == empty); + std::pair output = rmc.routing_method(mf, shared_arc); + unit_map_t empty; + REQUIRE(output.first); + REQUIRE(output.second == empty); - Circuit comp1(2); + Circuit comp1(3); comp1.add_op(OpType::SWAP, {0, 1}); comp1.add_op(OpType::CX, {1, 0}); comp1.add_op(OpType::CX, {1, 0}); comp1.add_op(OpType::CX, {0, 1}); comp1.add_op(OpType::CX, {0, 1}); qbs = comp1.all_qubits(); - rename_map = {{qbs[0], Node("t", 0)}, {qbs[1], Node("t", 1)}}; + rename_map = { + {qbs[0], Node("t", 0)}, {qbs[1], Node("t", 1)}, {qbs[2], Node("t", 2)}}; comp1.rename_units(rename_map); REQUIRE(c == comp1); diff --git a/tket/tests/test_json.cpp b/tket/tests/test_json.cpp index 973db696b3..bbdec1822b 100644 --- a/tket/tests/test_json.cpp +++ b/tket/tests/test_json.cpp @@ -428,9 +428,13 @@ SCENARIO("Test RoutingMethod serializations") { RoutingMethod loaded_rm_j = rm_j.get(); Circuit c(2, 2); - CHECK(!loaded_rm_j.check_method( - std::make_shared(c), - std::make_shared(2, 2))); + c.add_op(OpType::CX, {0, 1}); + + MappingFrontier mf(c); + std::shared_ptr mf_sp = + std::make_shared(mf); + CHECK(!loaded_rm_j.routing_method(mf_sp, std::make_shared(2, 2)) + .first); std::vector rmp = { std::make_shared(rm), @@ -438,12 +442,12 @@ SCENARIO("Test RoutingMethod serializations") { nlohmann::json rmp_j = rmp; std::vector loaded_rmp_j = rmp_j.get>(); - CHECK(!loaded_rmp_j[0]->check_method( - std::make_shared(c), - std::make_shared(2, 2))); - CHECK(loaded_rmp_j[1]->check_method( - std::make_shared(c), - std::make_shared(2, 2))); + CHECK(!loaded_rmp_j[0] + ->routing_method(mf_sp, std::make_shared(2, 2)) + .first); + CHECK(loaded_rmp_j[1] + ->routing_method(mf_sp, std::make_shared(2, 2)) + .first); } SCENARIO("Test predicate serializations") {