diff --git a/pytket/binders/circuit/Circuit/main.cpp b/pytket/binders/circuit/Circuit/main.cpp index 1b8cd30ba6..38c6f7c2bb 100644 --- a/pytket/binders/circuit/Circuit/main.cpp +++ b/pytket/binders/circuit/Circuit/main.cpp @@ -322,7 +322,12 @@ void def_circuit(py::class_> &pyCircuit) { .def( "flatten_registers", &Circuit::flatten_registers, "Combines all qubits into a single register namespace with " - "the default name, and likewise for bits") + "the default name, and likewise for bits" + "\n\n:param relabel_classical_expression: Determines whether python " + "classical expressions held in `ClassicalExpBox` have their " + "expression " + "relabelled to match relabelled Bit.", + py::arg("relabel_classical_expression") = true) // Circuit composition: .def( diff --git a/pytket/binders/passes.cpp b/pytket/binders/passes.cpp index 6768b6d3a9..3d96b982a9 100644 --- a/pytket/binders/passes.cpp +++ b/pytket/binders/passes.cpp @@ -752,9 +752,12 @@ PYBIND11_MODULE(passes, m) { "FlattenRelabelRegistersPass", &gen_flatten_relabel_registers_pass, "Removes empty Quantum wires from the Circuit and relabels all Qubit to " "a register from passed name. \n\n:param label: Name to relabel " - "remaining Qubit to, default 'q'.\n:return: A pass that removes empty " + "remaining Qubit to, default 'q'.\n:param relabel_classical_expressions: " + "Whether to relabel arguments of expressions held in `ClassicalExpBox`. " + "\n:return: A pass that removes empty " "wires and relabels.", - py::arg("label") = q_default_reg()); + py::arg("label") = q_default_reg(), + py::arg("relabel_classical_expressions") = true); m.def( "RenameQubitsPass", &gen_rename_qubits_pass, @@ -957,10 +960,12 @@ PYBIND11_MODULE(passes, m) { "\n:param allow_zzphase: If set to True, allows the algorithm to " "implement 2-qubit rotations using ZZPhase gates when deemed " "optimal. Defaults to False." + "\n:param timeout: Sets maximum out of time spent finding solution." "\n:return: a pass to perform the simplification", py::arg("discount_rate") = 0.7, py::arg("depth_weight") = 0.3, py::arg("max_lookahead") = 500, py::arg("max_tqe_candidates") = 500, - py::arg("seed") = 0, py::arg("allow_zzphase") = false); + py::arg("seed") = 0, py::arg("allow_zzphase") = false, + py::arg("timeout") = 100); m.def( "PauliSquash", &PauliSquash, "Applies :py:meth:`PauliSimp` followed by " diff --git a/pytket/binders/transform.cpp b/pytket/binders/transform.cpp index 21724759c3..cfd70bcec3 100644 --- a/pytket/binders/transform.cpp +++ b/pytket/binders/transform.cpp @@ -440,10 +440,12 @@ PYBIND11_MODULE(transform, m) { "\n:param allow_zzphase: If set to True, allows the algorithm to " "implement 2-qubit rotations using ZZPhase gates when deemed " "optimal. Defaults to False." + "\n:param timeout: Sets maximum out of time spent finding solution." "\n:return: a pass to perform the simplification", py::arg("discount_rate") = 0.7, py::arg("depth_weight") = 0.3, py::arg("max_tqe_candidates") = 500, py::arg("max_lookahead") = 500, - py::arg("seed") = 0, py::arg("allow_zzphase") = false) + py::arg("seed") = 0, py::arg("allow_zzphase") = false, + py::arg("timeout") = 100) .def_static( "ZZPhaseToRz", &Transforms::ZZPhase_to_Rz, "Fixes all ZZPhase gate angles to [-1, 1) half turns.") diff --git a/pytket/conanfile.py b/pytket/conanfile.py index 4332c2dc19..b12e296e0b 100644 --- a/pytket/conanfile.py +++ b/pytket/conanfile.py @@ -38,7 +38,7 @@ def requirements(self): self.requires("pybind11_json/0.2.14") self.requires("symengine/0.12.0") self.requires("tkassert/0.3.4@tket/stable") - self.requires("tket/1.3.40@tket/stable") + self.requires("tket/1.3.42@tket/stable") self.requires("tklog/0.3.3@tket/stable") self.requires("tkrng/0.3.3@tket/stable") self.requires("tktokenswap/0.3.9@tket/stable") diff --git a/pytket/docs/changelog.rst b/pytket/docs/changelog.rst index 756977bcc9..419b96f7f8 100644 --- a/pytket/docs/changelog.rst +++ b/pytket/docs/changelog.rst @@ -12,6 +12,9 @@ Features: conditions. * Add `custom_deserialisation` argument to `BasePass` and `SequencePass` `from_dict` method to support construction of `CustomPass` from json. +* Add `timeout` argument to `GreedyPauliSimp`. +* Add option to not relabel `ClassicalExpBox` when calling `rename_units` + and `flatten_registers` Fixes: diff --git a/pytket/pytket/_tket/circuit.pyi b/pytket/pytket/_tket/circuit.pyi index 4e514505a3..842014cd50 100644 --- a/pytket/pytket/_tket/circuit.pyi +++ b/pytket/pytket/_tket/circuit.pyi @@ -2104,9 +2104,11 @@ class Circuit: :param types: the set of operation types of interest :return: the circuit depth with respect to operations matching an element of `types` """ - def flatten_registers(self) -> dict[pytket._tket.unit_id.UnitID, pytket._tket.unit_id.UnitID]: + def flatten_registers(self, relabel_classical_expression: bool = True) -> dict[pytket._tket.unit_id.UnitID, pytket._tket.unit_id.UnitID]: """ Combines all qubits into a single register namespace with the default name, and likewise for bits + + :param relabel_classical_expression: Determines whether python classical expressions held in `ClassicalExpBox` have their expression relabelled to match relabelled Bit. """ def free_symbols(self) -> set[sympy.Symbol]: """ diff --git a/pytket/pytket/_tket/passes.pyi b/pytket/pytket/_tket/passes.pyi index 650273f020..b928a2e970 100644 --- a/pytket/pytket/_tket/passes.pyi +++ b/pytket/pytket/_tket/passes.pyi @@ -410,11 +410,12 @@ def FlattenRegisters() -> BasePass: """ Merges all quantum and classical registers into their respective default registers with contiguous indexing. """ -def FlattenRelabelRegistersPass(label: str = 'q') -> BasePass: +def FlattenRelabelRegistersPass(label: str = 'q', relabel_classical_expressions: bool = True) -> BasePass: """ Removes empty Quantum wires from the Circuit and relabels all Qubit to a register from passed name. :param label: Name to relabel remaining Qubit to, default 'q'. + :param relabel_classical_expressions: Whether to relabel arguments of expressions held in `ClassicalExpBox`. :return: A pass that removes empty wires and relabels. """ def FullMappingPass(arc: pytket._tket.architecture.Architecture, placer: pytket._tket.placement.Placement, config: typing.Sequence[pytket._tket.mapping.RoutingMethod]) -> BasePass: @@ -444,7 +445,7 @@ def GlobalisePhasedX(squash: bool = True) -> BasePass: It is not recommended to use this pass with symbolic expressions, as in certain cases a blow-up in symbolic expression sizes may occur. """ -def GreedyPauliSimp(discount_rate: float = 0.7, depth_weight: float = 0.3, max_lookahead: int = 500, max_tqe_candidates: int = 500, seed: int = 0, allow_zzphase: bool = False) -> BasePass: +def GreedyPauliSimp(discount_rate: float = 0.7, depth_weight: float = 0.3, max_lookahead: int = 500, max_tqe_candidates: int = 500, seed: int = 0, allow_zzphase: bool = False, timeout: int = 100) -> BasePass: """ Construct a pass that converts a circuit into a graph of Pauli gadgets to account for commutation and phase folding, and resynthesises them using a greedy algorithm adapted from arxiv.org/abs/2103.08602. The method for synthesising the final Clifford operator is adapted from arxiv.org/abs/2305.10966. @@ -454,6 +455,7 @@ def GreedyPauliSimp(discount_rate: float = 0.7, depth_weight: float = 0.3, max_l :param max_lookahead: Maximum lookahead when evaluating each Clifford gate candidate. Default to 500. :param seed: Unsigned integer seed used for sampling candidates and tie breaking. Default to 0. :param allow_zzphase: If set to True, allows the algorithm to implement 2-qubit rotations using ZZPhase gates when deemed optimal. Defaults to False. + :param timeout: Sets maximum out of time spent finding solution. :return: a pass to perform the simplification """ def GuidedPauliSimp(strat: pytket._tket.transform.PauliSynthStrat = pytket._tket.transform.PauliSynthStrat.Sets, cx_config: pytket._tket.circuit.CXConfigType = pytket._tket.circuit.CXConfigType.Snake) -> BasePass: diff --git a/pytket/pytket/_tket/transform.pyi b/pytket/pytket/_tket/transform.pyi index 4801b4238c..ce620128b2 100644 --- a/pytket/pytket/_tket/transform.pyi +++ b/pytket/pytket/_tket/transform.pyi @@ -165,7 +165,7 @@ class Transform: It is not recommended to use this transformation with symbolic expressions, as in certain cases a blow-up in symbolic expression sizes may occur. """ @staticmethod - def GreedyPauliSimp(discount_rate: float = 0.7, depth_weight: float = 0.3, max_tqe_candidates: int = 500, max_lookahead: int = 500, seed: int = 0, allow_zzphase: bool = False) -> Transform: + def GreedyPauliSimp(discount_rate: float = 0.7, depth_weight: float = 0.3, max_tqe_candidates: int = 500, max_lookahead: int = 500, seed: int = 0, allow_zzphase: bool = False, timeout: int = 100) -> Transform: """ Convert a circuit into a graph of Pauli gadgets to account for commutation and phase folding, and resynthesises them using a greedy algorithm adapted from arxiv.org/abs/2103.08602. The method for synthesising the final Clifford operator is adapted from arxiv.org/abs/2305.10966. @@ -175,6 +175,7 @@ class Transform: :param max_lookahead: Maximum lookahead when evaluating each Clifford gate candidate. Default to 500. :param seed: Unsigned integer seed used for sampling candidates and tie breaking. Default to 0. :param allow_zzphase: If set to True, allows the algorithm to implement 2-qubit rotations using ZZPhase gates when deemed optimal. Defaults to False. + :param timeout: Sets maximum out of time spent finding solution. :return: a pass to perform the simplification """ @staticmethod diff --git a/pytket/tests/passes_serialisation_test.py b/pytket/tests/passes_serialisation_test.py index 6f6f71bdff..14e2f42193 100644 --- a/pytket/tests/passes_serialisation_test.py +++ b/pytket/tests/passes_serialisation_test.py @@ -296,6 +296,7 @@ def nonparam_predicate_dict(name: str) -> Dict[str, Any]: "max_tqe_candidates": 100, "seed": 2, "allow_zzphase": True, + "timeout": 5000, } ), # lists must be sorted by OpType value diff --git a/pytket/tests/predicates_test.py b/pytket/tests/predicates_test.py index 47ac681396..cc818099de 100644 --- a/pytket/tests/predicates_test.py +++ b/pytket/tests/predicates_test.py @@ -1036,6 +1036,7 @@ def test_greedy_pauli_synth() -> None: ).SWAP(regb[1], rega[0]) d = circ.copy() pss = GreedyPauliSimp(0.5, 0.5) + assert not GreedyPauliSimp(0.5, 0.5, timeout=0).apply(d) assert pss.apply(d) assert np.allclose(circ.get_unitary(), d.get_unitary()) assert d.name == "test" @@ -1058,7 +1059,8 @@ def test_greedy_pauli_synth() -> None: circ.measure_all() circ.Reset(0) circ.add_pauliexpbox(pg1, [2, 3]) - assert GreedyPauliSimp(0.5, 0.5, 100, 100, 0, True).apply(circ) + assert not GreedyPauliSimp(0.5, 0.5, 100, 100, 0, True, 0).apply(circ) + assert GreedyPauliSimp(0.5, 0.5, 100, 100, 0, True, 100).apply(circ) # PauliExpBoxes implemented using ZZPhase d = Circuit(4, 4, name="test") d.H(0) diff --git a/schemas/compiler_pass_v1.json b/schemas/compiler_pass_v1.json index b8175c8b92..dbd68c9e18 100644 --- a/schemas/compiler_pass_v1.json +++ b/schemas/compiler_pass_v1.json @@ -373,6 +373,10 @@ "allow_zzphase": { "type": "boolean", "definition": "parameter controlling the use of ZZPhase gates in \"GreedyPauliSimp\"" + }, + "timeout": { + "type": "number", + "definition": "parameter controlling the maximum runtime of \"GreedyPauliSimp\"" } }, "required": [ @@ -644,9 +648,10 @@ }, "then": { "required": [ - "label" + "label", + "relabel_classical_registers" ], - "maxProperties": 2 + "maxProperties": 3 } }, { @@ -903,9 +908,10 @@ "max_lookahead", "max_tqe_candidates", "seed", - "allow_zzphase" + "allow_zzphase", + "timeout" ], - "maxProperties": 7 + "maxProperties": 8 } }, { diff --git a/tket/conanfile.py b/tket/conanfile.py index 31633eef95..a30f2f1de8 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "1.3.40" + version = "1.3.42" package_type = "library" license = "Apache 2" homepage = "https://github.com/CQCL/tket" diff --git a/tket/include/tket/Circuit/Circuit.hpp b/tket/include/tket/Circuit/Circuit.hpp index 038dc6bc7f..606c2c3b0f 100644 --- a/tket/include/tket/Circuit/Circuit.hpp +++ b/tket/include/tket/Circuit/Circuit.hpp @@ -749,9 +749,12 @@ class Circuit { /** * Convert all quantum and classical bits to use default registers. * + * @param relabel_classical_expression Whether expressions in ClassicalExpBox + * have their expr updated to match the input wires + * * @return mapping from old to new unit IDs */ - unit_map_t flatten_registers(); + unit_map_t flatten_registers(bool relabel_classical_expression = true); //_________________________________________________ @@ -1044,7 +1047,8 @@ class Circuit { * @return true iff circuit was modified */ template - bool rename_units(const std::map &qm); + bool rename_units( + const std::map &qm, bool relabel_classicalexpbox = true); /** Automatically rewire holes when removing vertices from the circuit? */ enum class GraphRewiring { Yes, No }; @@ -1719,7 +1723,8 @@ JSON_DECL(Circuit) /** Templated method definitions */ template -bool Circuit::rename_units(const std::map &qm) { +bool Circuit::rename_units( + const std::map &qm, bool relabel_classicalexpbox) { // Can only work for Unit classes static_assert(std::is_base_of::value); static_assert(std::is_base_of::value); @@ -1768,21 +1773,18 @@ bool Circuit::rename_units(const std::map &qm) { "Unit already exists in circuit: " + pair.first.repr()); TKET_ASSERT(modified); } - // For every ClassicalExpBox, update its logic expressions - if (!bm.empty()) { + if (!bm.empty() && relabel_classicalexpbox) { BGL_FORALL_VERTICES(v, dag, DAG) { Op_ptr op = get_Op_ptr_from_Vertex(v); if (op->get_type() == OpType::ClassicalExpBox) { const ClassicalExpBoxBase &cbox = static_cast(*op); // rename_units is marked as const to get around the Op_ptr - // cast, but it can still mutate a python object modified |= cbox.rename_units(bm); } } } - return modified; } diff --git a/tket/include/tket/Predicates/PassGenerators.hpp b/tket/include/tket/Predicates/PassGenerators.hpp index 9e7f87931c..699f9b9edc 100644 --- a/tket/include/tket/Predicates/PassGenerators.hpp +++ b/tket/include/tket/Predicates/PassGenerators.hpp @@ -110,7 +110,8 @@ PassPtr gen_clifford_push_through_pass(); * Qubits removed from the Circuit are preserved in the bimap, but not updated * to a new labelling. */ -PassPtr gen_flatten_relabel_registers_pass(const std::string& label); +PassPtr gen_flatten_relabel_registers_pass( + const std::string& label, bool relabel_classical_expressions = true); /** * Pass to rename some or all qubits according to the given map. * @@ -354,12 +355,13 @@ PassPtr gen_special_UCC_synthesis( * @param max_tqe_candidates * @param seed * @param allow_zzphase + * @param timeout * @return PassPtr */ PassPtr gen_greedy_pauli_simp( double discount_rate = 0.7, double depth_weight = 0.3, unsigned max_lookahead = 500, unsigned max_tqe_candidates = 500, - unsigned seed = 0, bool allow_zzphase = false); + unsigned seed = 0, bool allow_zzphase = false, unsigned timeout = 100); /** * Generate a pass to simplify the circuit where it acts on known basis states. diff --git a/tket/include/tket/Transformations/GreedyPauliOptimisation.hpp b/tket/include/tket/Transformations/GreedyPauliOptimisation.hpp index de6bb19d5c..3cc6348582 100644 --- a/tket/include/tket/Transformations/GreedyPauliOptimisation.hpp +++ b/tket/include/tket/Transformations/GreedyPauliOptimisation.hpp @@ -643,7 +643,7 @@ Circuit greedy_pauli_set_synthesis( Transform greedy_pauli_optimisation( double discount_rate = 0.7, double depth_weight = 0.3, unsigned max_lookahead = 500, unsigned max_tqe_candidates = 500, - unsigned seed = 0, bool allow_zzphase = false); + unsigned seed = 0, bool allow_zzphase = false, unsigned timeout = 100); } // namespace Transforms diff --git a/tket/src/Circuit/basic_circ_manip.cpp b/tket/src/Circuit/basic_circ_manip.cpp index ca3d27faa3..9bb8b11902 100644 --- a/tket/src/Circuit/basic_circ_manip.cpp +++ b/tket/src/Circuit/basic_circ_manip.cpp @@ -422,7 +422,7 @@ void Circuit::remove_edge(const Edge& edge) { boost::remove_edge(edge, this->dag); } -unit_map_t Circuit::flatten_registers() { +unit_map_t Circuit::flatten_registers(bool relabel_classical_expression) { unit_map_t rename_map; unsigned q_index = 0; unsigned c_index = 0; @@ -434,7 +434,7 @@ unit_map_t Circuit::flatten_registers() { } } try { - rename_units(rename_map); + rename_units(rename_map, relabel_classical_expression); } catch (const std::exception& e) { std::stringstream ss; ss << "Unable to flatten registers: " << e.what(); diff --git a/tket/src/Predicates/CompilerPass.cpp b/tket/src/Predicates/CompilerPass.cpp index f0a5461e4b..2caeafe08f 100644 --- a/tket/src/Predicates/CompilerPass.cpp +++ b/tket/src/Predicates/CompilerPass.cpp @@ -469,7 +469,8 @@ PassPtr deserialise( pp = gen_euler_pass(q, p, s); } else if (passname == "FlattenRelabelRegistersPass") { pp = gen_flatten_relabel_registers_pass( - content.at("label").get()); + content.at("label").get(), + content.at("relabel_classical_expressions").get()); } else if (passname == "RoutingPass") { Architecture arc = content.at("architecture").get(); std::vector con = content.at("routing_config"); @@ -521,9 +522,10 @@ PassPtr deserialise( unsigned max_lookahead = content.at("max_lookahead").get(); unsigned seed = content.at("seed").get(); bool allow_zzphase = content.at("allow_zzphase").get(); + unsigned timeout = content.at("timeout").get(); pp = gen_greedy_pauli_simp( discount_rate, depth_weight, max_lookahead, max_tqe_candidates, seed, - allow_zzphase); + allow_zzphase, timeout); } else if (passname == "PauliSimp") { // SEQUENCE PASS - DESERIALIZABLE ONLY diff --git a/tket/src/Predicates/PassGenerators.cpp b/tket/src/Predicates/PassGenerators.cpp index 610caabd84..eb5f50317b 100644 --- a/tket/src/Predicates/PassGenerators.cpp +++ b/tket/src/Predicates/PassGenerators.cpp @@ -354,7 +354,8 @@ PassPtr gen_clifford_push_through_pass() { return std::make_shared(precons, t, pc, j); } -PassPtr gen_flatten_relabel_registers_pass(const std::string& label) { +PassPtr gen_flatten_relabel_registers_pass( + const std::string& label, bool relabel_classical_expressions) { Transform t = Transform([=](Circuit& circuit, std::shared_ptr maps) { unsigned n_qubits = circuit.n_qubits(); @@ -366,7 +367,7 @@ PassPtr gen_flatten_relabel_registers_pass(const std::string& label) { relabelling_map.insert({all_qubits[i], Qubit(label, i)}); } - circuit.rename_units(relabelling_map); + circuit.rename_units(relabelling_map, relabel_classical_expressions); changed |= update_maps(maps, relabelling_map, relabelling_map); return changed; }); @@ -376,6 +377,7 @@ PassPtr gen_flatten_relabel_registers_pass(const std::string& label) { nlohmann::json j; j["name"] = "FlattenRelabelRegistersPass"; j["label"] = label; + j["relabel_classical_expressions"] = relabel_classical_expressions; return std::make_shared(precons, t, postcons, j); } @@ -1015,10 +1017,11 @@ PassPtr gen_synthesise_pauli_graph( PassPtr gen_greedy_pauli_simp( double discount_rate, double depth_weight, unsigned max_lookahead, - unsigned max_tqe_candidates, unsigned seed, bool allow_zzphase) { + unsigned max_tqe_candidates, unsigned seed, bool allow_zzphase, + unsigned timeout) { Transform t = Transforms::greedy_pauli_optimisation( discount_rate, depth_weight, max_lookahead, max_tqe_candidates, seed, - allow_zzphase); + allow_zzphase, timeout); OpTypeSet ins = { OpType::Z, OpType::X, @@ -1067,6 +1070,7 @@ PassPtr gen_greedy_pauli_simp( j["max_tqe_candidates"] = max_tqe_candidates; j["seed"] = seed; j["allow_zzphase"] = allow_zzphase; + j["timeout"] = timeout; return std::make_shared(precons, t, postcon, j); } diff --git a/tket/src/Transformations/GreedyPauliOptimisation.cpp b/tket/src/Transformations/GreedyPauliOptimisation.cpp index e052102656..bf88e4a265 100644 --- a/tket/src/Transformations/GreedyPauliOptimisation.cpp +++ b/tket/src/Transformations/GreedyPauliOptimisation.cpp @@ -15,6 +15,8 @@ #include "tket/Transformations/GreedyPauliOptimisation.hpp" #include +#include +#include #include #include "tket/Circuit/PauliExpBoxes.hpp" @@ -740,7 +742,6 @@ Circuit greedy_pauli_graph_synthesis( if (max_tqe_candidates == 0) { throw GreedyPauliSimpError("max_tqe_candidates must be greater than 0."); } - Circuit circ_flat(circ); unsigned n_qubits = circ_flat.n_qubits(); unsigned n_bits = circ_flat.n_bits(); @@ -750,7 +751,7 @@ Circuit greedy_pauli_graph_synthesis( if (name != std::nullopt) { new_circ.set_name(name.value()); } - unit_map_t unit_map = circ_flat.flatten_registers(); + unit_map_t unit_map = circ_flat.flatten_registers(false); unit_map_t rev_unit_map; for (const auto& pair : unit_map) { rev_unit_map.insert({pair.second, pair.first}); @@ -769,7 +770,7 @@ Circuit greedy_pauli_graph_synthesis( for (auto it = measures.begin(); it != measures.end(); ++it) { new_circ.add_measure(it->left, it->right); } - new_circ.rename_units(rev_unit_map); + new_circ.rename_units(rev_unit_map, false); new_circ.replace_SWAPs(); return new_circ; } @@ -778,15 +779,22 @@ Circuit greedy_pauli_graph_synthesis( Transform greedy_pauli_optimisation( double discount_rate, double depth_weight, unsigned max_lookahead, - unsigned max_tqe_candidates, unsigned seed, bool allow_zzphase) { + unsigned max_tqe_candidates, unsigned seed, bool allow_zzphase, + unsigned timeout) { return Transform([discount_rate, depth_weight, max_lookahead, - max_tqe_candidates, seed, allow_zzphase](Circuit& circ) { - circ = GreedyPauliSimp::greedy_pauli_graph_synthesis( - circ, discount_rate, depth_weight, max_lookahead, max_tqe_candidates, - seed, allow_zzphase); - // decompose the conditional CircBoxes - circ.decompose_boxes_recursively(); - return true; + max_tqe_candidates, seed, allow_zzphase, + timeout](Circuit& circ) { + std::future future = std::async( + std::launch::async, GreedyPauliSimp::greedy_pauli_graph_synthesis, circ, + discount_rate, depth_weight, max_lookahead, max_tqe_candidates, seed, + allow_zzphase); + if (future.wait_for(std::chrono::seconds(timeout)) == + std::future_status::ready) { + circ = future.get(); + circ.decompose_boxes_recursively(); + return true; + } + return false; }); } diff --git a/tket/test/src/test_GreedyPauli.cpp b/tket/test/src/test_GreedyPauli.cpp index 366143ece4..6d62f74bd5 100644 --- a/tket/test/src/test_GreedyPauli.cpp +++ b/tket/test/src/test_GreedyPauli.cpp @@ -619,9 +619,38 @@ SCENARIO("Complete synthesis") { PauliExpBox( SymPauliTensor({Pauli::Y, Pauli::Z, Pauli::Z, Pauli::X}, 0.125)), {1, 3, 5, 0}); + + circ.add_box( + PauliExpBox(SymPauliTensor( + {Pauli::X, Pauli::Z, Pauli::Y, Pauli::Y, Pauli::Z, Pauli::X}, + 0.125)), + {1, 3, 5, 0, 2, 4}); + + circ.add_box( + PauliExpBox(SymPauliTensor( + {Pauli::Z, Pauli::Y, Pauli::Y, Pauli::Z, Pauli::Z, Pauli::X}, + 0.125)), + {0, 1, 2, 3, 4, 5}); + + circ.add_box( + PauliExpBox(SymPauliTensor( + {Pauli::X, Pauli::Z, Pauli::Y, Pauli::Z, Pauli::Z, Pauli::X}, + 0.125)), + {5, 2, 4, 1, 3, 0}); + + circ.add_box( + PauliExpBox(SymPauliTensor( + {Pauli::X, Pauli::Z, Pauli::Y, Pauli::Y, Pauli::Z, Pauli::X}, + 0.125)), + {0, 5, 1, 4, 3, 2}); + Circuit d(circ); - REQUIRE(Transforms::greedy_pauli_optimisation(0.7, 0.3, 500, 500, 0, true) - .apply(d)); + REQUIRE( + !Transforms::greedy_pauli_optimisation(0.7, 0.3, 500, 500, 0, true, 0) + .apply(d)); + REQUIRE( + Transforms::greedy_pauli_optimisation(0.7, 0.3, 500, 500, 0, true, 10) + .apply(d)); REQUIRE(test_unitary_comparison(circ, d, true)); } GIVEN("Select TQE over ZZPhase") { @@ -709,6 +738,7 @@ SCENARIO("Test GreedyPauliSimp for individual gates") { REQUIRE(test_unitary_comparison(circ, d, true)); } } + SCENARIO("Test GreedyPauliSimp pass construction") { // test pass construction GIVEN("A circuit") {