diff --git a/pytket/conanfile.py b/pytket/conanfile.py index b90e3d65e1..0792fc47c5 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.3.24@tket/stable") + self.requires("tket/1.3.25@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 062c60c730..711deddd2f 100644 --- a/pytket/docs/changelog.rst +++ b/pytket/docs/changelog.rst @@ -10,6 +10,8 @@ Features: * DecomposeTK2 pass now has a json representation when it contains no functions. * Add support for rendering multiple circuits at once. * Add option to save circuit renderer options to pytket config. +* Make `CXMappingPass` into a `StandardPass` (with round-trip serialization and + deserialization). Fixes: diff --git a/pytket/tests/passes_serialisation_test.py b/pytket/tests/passes_serialisation_test.py index cf7423248c..f7d7d788b6 100644 --- a/pytket/tests/passes_serialisation_test.py +++ b/pytket/tests/passes_serialisation_test.py @@ -311,6 +311,16 @@ def nonparam_predicate_dict(name: str) -> Dict[str, Any]: "allow_swaps": True, } ), + "CXMappingPass": standard_pass_dict( + { + "name": "CXMappingPass", + "architecture": example_architecture, + "placement": example_placement, + "routing_config": example_routing_config, + "directed": True, + "delay_measures": True, + } + ), } # non-parametrized passes that satisfy pass.from_dict(d).to_dict()==d @@ -372,16 +382,6 @@ def nonparam_predicate_dict(name: str) -> Dict[str, Any]: "delay_measures": True, } ), - "CXMappingPass": standard_pass_dict( - { - "name": "CXMappingPass", - "architecture": example_architecture, - "placement": example_placement, - "routing_config": example_routing_config, - "directed": True, - "delay_measures": True, - } - ), "PauliSimp": standard_pass_dict( { "name": "PauliSimp", @@ -726,38 +726,6 @@ def tk1_rep(a: ParamType, b: ParamType, c: ParamType) -> Circuit: comppba_plac_pass.get_sequence()[1].to_dict()["StandardPass"]["name"] == "PlacementPass" ) - # CXMappingPass - cxm_pass = CXMappingPass(arc, placer, directed_cx=True, delay_measures=True) - assert cxm_pass.to_dict()["pass_class"] == "SequencePass" - assert isinstance(cxm_pass, SequencePass) - p0 = cxm_pass.get_sequence()[0] - p1 = cxm_pass.get_sequence()[1] - assert p0.to_dict()["pass_class"] == "SequencePass" - assert p1.to_dict()["StandardPass"]["name"] == "DecomposeSwapsToCXs" - assert p1.to_dict()["StandardPass"]["directed"] == True - assert isinstance(p0, SequencePass) - p00 = p0.get_sequence()[0] - p01 = p0.get_sequence()[1] - assert p00.to_dict()["pass_class"] == "SequencePass" - assert p01.to_dict()["StandardPass"]["name"] == "RebaseCustom" - assert p01.to_dict()["StandardPass"]["basis_cx_replacement"] == cx.to_dict() - assert isinstance(p00, SequencePass) - p000 = p00.get_sequence()[0] - p001 = p00.get_sequence()[1] - assert p000.to_dict()["pass_class"] == "SequencePass" - assert p001.to_dict()["StandardPass"]["name"] == "DelayMeasures" - assert p001.to_dict()["StandardPass"]["allow_partial"] == False - assert isinstance(p000, SequencePass) - p0000 = p000.get_sequence()[0] - p0001 = p000.get_sequence()[1] - assert p0000.to_dict()["StandardPass"]["name"] == "RebaseCustom" - assert p0001.to_dict()["pass_class"] == "SequencePass" - assert isinstance(p0001, SequencePass) - p00010 = p0001.get_sequence()[0] - p00011 = p0001.get_sequence()[1] - assert p00010.to_dict()["StandardPass"]["name"] == "PlacementPass" - assert p00011.to_dict()["StandardPass"]["name"] == "RoutingPass" - assert check_arc_dict(arc, p00011.to_dict()["StandardPass"]["architecture"]) # RepeatWithMetricPass def number_of_CX(circ: Circuit) -> int: diff --git a/tket/conanfile.py b/tket/conanfile.py index d65408a973..914c740558 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "1.3.24" + version = "1.3.25" package_type = "library" license = "Apache 2" homepage = "https://github.com/CQCL/tket" diff --git a/tket/src/Predicates/CompilerPass.cpp b/tket/src/Predicates/CompilerPass.cpp index f253da095f..6f5a9c6d20 100644 --- a/tket/src/Predicates/CompilerPass.cpp +++ b/tket/src/Predicates/CompilerPass.cpp @@ -538,7 +538,6 @@ void from_json(const nlohmann::json& j, PassPtr& pp) { bool delay_measures = content.at("delay_measures").get(); pp = gen_default_mapping_pass(arc, delay_measures); } else if (passname == "CXMappingPass") { - // SEQUENCE PASS - DESERIALIZABLE ONLY Architecture arc = content.at("architecture").get(); Placement::Ptr place = content.at("placement").get(); std::vector config = content.at("routing_config"); diff --git a/tket/src/Predicates/PassGenerators.cpp b/tket/src/Predicates/PassGenerators.cpp index 54b0d98683..0ecfd2fc16 100644 --- a/tket/src/Predicates/PassGenerators.cpp +++ b/tket/src/Predicates/PassGenerators.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -480,14 +481,54 @@ PassPtr gen_cx_mapping_pass( bool delay_measures) { OpTypeSet gate_set = all_single_qubit_types(); gate_set.insert(OpType::CX); - PassPtr rebase_pass = - gen_rebase_pass(gate_set, CircPool::CX(), CircPool::tk1_to_tk1); + PassPtr rebase_pass = gen_auto_rebase_pass(gate_set); PassPtr return_pass = rebase_pass >> gen_full_mapping_pass(arc, placement_ptr, config); if (delay_measures) return_pass = return_pass >> DelayMeasures(); return_pass = return_pass >> rebase_pass >> gen_decompose_routing_gates_to_cxs_pass(arc, directed_cx); - return return_pass; + Transform t{[=](Circuit& circ, std::shared_ptr maps) { + // Relabel all two-qubit gates + CompilationUnit cu(circ); + bool changed = rebase_pass->apply(cu); + circ = cu.get_circ_ref(); + // Now try placement, falling back on "LinePlacement" if "GraphPlacement" + // fails + try { + changed |= placement_ptr->place(circ, maps); + } catch (const std::runtime_error& e) { + std::stringstream ss; + ss << "PlacementPass failed with message: " << e.what() + << " Fall back to LinePlacement."; + tket_log()->warn(ss.str()); + Placement::Ptr line_placement_ptr = std::make_shared( + placement_ptr->get_architecture_ref()); + changed |= line_placement_ptr->place(circ, maps); + } + // Now route + MappingManager mm(std::make_shared(arc)); + changed |= mm.route_circuit_with_maps(circ, config, maps); + + // Now decompose routing gates to cx gates (this won't change maps) + CompilationUnit cu1(circ); + if (delay_measures) { + changed |= DelayMeasures()->apply(cu1); + } + changed |= + gen_decompose_routing_gates_to_cxs_pass(arc, directed_cx)->apply(cu1); + circ = cu1.get_circ_ref(); + return changed; + }}; + PassConditions conditions = return_pass->get_conditions(); + nlohmann::json j; + j["name"] = "CXMappingPass"; + j["architecture"] = arc; + j["placement"] = placement_ptr; + j["routing_config"] = config; + j["directed"] = directed_cx; + j["delay_measures"] = delay_measures; + return std::make_shared( + conditions.first, t, conditions.second, j); } PassPtr gen_routing_pass(