Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add conditional parameter to gate counting #1662

Merged
merged 7 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions pytket/binders/circuit/Circuit/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,15 +472,18 @@ void def_circuit(py::class_<Circuit, std::shared_ptr<Circuit>> &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); },
Expand Down
2 changes: 1 addition & 1 deletion pytket/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 2 additions & 0 deletions pytket/docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
---------------------
Expand Down
5 changes: 4 additions & 1 deletion pytket/pytket/_tket/circuit.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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:
Expand Down
16 changes: 16 additions & 0 deletions pytket/tests/circuit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion tket/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
3 changes: 2 additions & 1 deletion tket/include/tket/Circuit/Circuit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1118,7 +1118,8 @@ class Circuit {
*/
std::map<OpType, unsigned> 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;

/**
Expand Down
10 changes: 9 additions & 1 deletion tket/src/Circuit/macro_circ_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,19 @@ std::map<OpType, unsigned> 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<const Conditional&>(*get_Op_ptr_from_Vertex(v))
.get_op()
->get_type() == op_type)) {
++counter;
}
}
return counter;
Expand Down
19 changes: 19 additions & 0 deletions tket/test/src/Circuit/test_Circ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<UnitID>(OpType::H, {}, {qreg[1]}, {creg[0]}, 1);
circ.add_conditional_gate<UnitID>(OpType::H, {}, {qreg[1]}, {creg[0]}, 1);
circ.add_conditional_gate<UnitID>(OpType::H, {}, {qreg[1]}, {creg[0]}, 1);
circ.add_op<Qubit>(OpType::H, {Qubit(qreg[0])});
circ.add_op<Qubit>(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;
Expand Down
Loading