diff --git a/pytket/binders/circuit/Circuit/main.cpp b/pytket/binders/circuit/Circuit/main.cpp index 867996beb1..1b8cd30ba6 100644 --- a/pytket/binders/circuit/Circuit/main.cpp +++ b/pytket/binders/circuit/Circuit/main.cpp @@ -472,15 +472,18 @@ void def_circuit(py::class_> &pyCircuit) { "\n\n:return: the circuit depth") .def( "n_gates_of_type", - [](const Circuit &circ, const OpType &_type) { - return circ.count_gates(_type); + [](const Circuit &circ, const OpType &_type, + const bool include_conditional) { + return circ.count_gates(_type, include_conditional); }, "Returns the number of vertices in the dag of a given " "operation type.\n\n>>> c.CX(0,1)\n>>> c.H(0)\n>>> " "c.CX(0,1)\n>>> c.n_gates_of_type(OpType.CX)\n2\n\n:param " - "type: The operation type to search for\n:return: the " - "number of operations matching `type`", - py::arg("type")) + "type: The operation type to search for\n\n:param " + "include_conditional: if set to true, conditional gates will " + "be counted, too\n\n:return: the number of operations " + "matching `type`", + py::arg("type"), py::arg("include_conditional") = false) .def( "n_1qb_gates", [](const Circuit &circ) { return circ.count_n_qubit_gates(1); }, diff --git a/pytket/conanfile.py b/pytket/conanfile.py index 094c0e3d89..e23892a53b 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.39@tket/stable") + self.requires("tket/1.3.40@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 df54b92f4e..756977bcc9 100644 --- a/pytket/docs/changelog.rst +++ b/pytket/docs/changelog.rst @@ -21,6 +21,8 @@ Fixes: * Fix `maxwidth` parameter of `circuit_from_qasm_str` * Add `scratch_reg_resize_pass` to `circuit_from_qasm_str` * Reject incompete classical registers in pytket to qasm conversion +* Add parameter `include_conditional` to `n_gates_of_type` to include + conditional gates in the count 1.34.0 (October 2024) --------------------- diff --git a/pytket/pytket/_tket/circuit.pyi b/pytket/pytket/_tket/circuit.pyi index 4cbc158def..4e514505a3 100644 --- a/pytket/pytket/_tket/circuit.pyi +++ b/pytket/pytket/_tket/circuit.pyi @@ -2235,7 +2235,7 @@ class Circuit: """ Returns the number of vertices in the dag with two quantum edges.Ignores Input, Create, Output, Discard, Reset, Measure and Barrier vertices. """ - def n_gates_of_type(self, type: OpType) -> int: + def n_gates_of_type(self, type: OpType, include_conditional: bool = False) -> int: """ Returns the number of vertices in the dag of a given operation type. @@ -2246,6 +2246,9 @@ class Circuit: 2 :param type: The operation type to search for + + :param include_conditional: if set to true, conditional gates will be counted, too + :return: the number of operations matching `type` """ def n_nqb_gates(self, size: int) -> int: diff --git a/pytket/tests/circuit_test.py b/pytket/tests/circuit_test.py index bd63087cbf..420ef07e94 100644 --- a/pytket/tests/circuit_test.py +++ b/pytket/tests/circuit_test.py @@ -1265,6 +1265,22 @@ def test_counting_n_qubit_gates() -> None: assert c.n_nqb_gates(5) == 1 +def test_counting_conditional_gates() -> None: + c = Circuit(5, 2).X(0).H(1).Y(2).Z(3).S(4).CX(0, 1).CX(1, 2).CX(2, 3).CX(3, 4) + c.add_gate(OpType.H, [Qubit(0)], condition=Bit(0)) + c.add_gate(OpType.H, [Qubit(1)], condition=(Bit(0) & Bit(1))) + c.add_gate(OpType.CX, [Qubit(0), Qubit(1)], condition=Bit(1)) + assert c.n_gates_of_type(OpType.H, include_conditional=True) == 3 + assert c.n_gates_of_type(OpType.H, include_conditional=False) == 1 + assert c.n_gates_of_type(OpType.H) == 1 + assert c.n_gates_of_type(OpType.X, include_conditional=True) == 1 + assert c.n_gates_of_type(OpType.X, include_conditional=False) == 1 + assert c.n_gates_of_type(OpType.X) == 1 + assert c.n_gates_of_type(OpType.CX, include_conditional=True) == 5 + assert c.n_gates_of_type(OpType.CX, include_conditional=False) == 4 + assert c.n_gates_of_type(OpType.CX) == 4 + + def test_qcontrol_box_constructors() -> None: # only one argument qcbox1 = QControlBox(Op.create(OpType.S)) diff --git a/tket/conanfile.py b/tket/conanfile.py index 147e674cb2..31633eef95 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "1.3.39" + version = "1.3.40" 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 64a4f338c9..038dc6bc7f 100644 --- a/tket/include/tket/Circuit/Circuit.hpp +++ b/tket/include/tket/Circuit/Circuit.hpp @@ -1118,7 +1118,8 @@ class Circuit { */ std::map op_counts() const; - unsigned count_gates(const OpType &op_type) const; + unsigned count_gates( + const OpType &op_type, const bool include_conditional = false) const; VertexSet get_gates_of_type(const OpType &op_type) const; /** diff --git a/tket/src/Circuit/macro_circ_info.cpp b/tket/src/Circuit/macro_circ_info.cpp index 5f6e2bf9f6..73fc0a3b31 100644 --- a/tket/src/Circuit/macro_circ_info.cpp +++ b/tket/src/Circuit/macro_circ_info.cpp @@ -51,11 +51,19 @@ std::map Circuit::op_counts() const { return counts; } -unsigned Circuit::count_gates(const OpType& op_type) const { +unsigned Circuit::count_gates( + const OpType& op_type, const bool include_conditional) const { unsigned counter = 0; BGL_FORALL_VERTICES(v, dag, DAG) { if (get_OpType_from_Vertex(v) == op_type) { ++counter; + } else if ( + include_conditional && + (get_OpType_from_Vertex(v) == OpType::Conditional) && + (static_cast(*get_Op_ptr_from_Vertex(v)) + .get_op() + ->get_type() == op_type)) { + ++counter; } } return counter; diff --git a/tket/test/src/Circuit/test_Circ.cpp b/tket/test/src/Circuit/test_Circ.cpp index e868668bd9..2f47486862 100644 --- a/tket/test/src/Circuit/test_Circ.cpp +++ b/tket/test/src/Circuit/test_Circ.cpp @@ -176,6 +176,25 @@ SCENARIO( } } +SCENARIO("test conditional count") { + GIVEN("conditional circ") { + Circuit circ; + register_t qreg = circ.add_q_register("qb", 2); + register_t creg = circ.add_c_register("b", 2); + circ.add_conditional_gate(OpType::H, {}, {qreg[1]}, {creg[0]}, 1); + circ.add_conditional_gate(OpType::H, {}, {qreg[1]}, {creg[0]}, 1); + circ.add_conditional_gate(OpType::H, {}, {qreg[1]}, {creg[0]}, 1); + circ.add_op(OpType::H, {Qubit(qreg[0])}); + circ.add_op(OpType::H, {Qubit(qreg[0])}); + REQUIRE(circ.n_qubits() == 2); + REQUIRE(circ.n_bits() == 2); + REQUIRE(circ.count_gates(OpType::CX, false) == 0); + REQUIRE(circ.count_gates(OpType::H, false) == 2); + REQUIRE(circ.count_gates(OpType::CX, true) == 0); + REQUIRE(circ.count_gates(OpType::H, true) == 5); + } +} + SCENARIO("Creating gates via Qubits and Registers") { GIVEN("A purely quantum circuit") { Circuit circ;