From 76d08c06a026da7495dfa62af5a065bd91246aaf Mon Sep 17 00:00:00 2001 From: "A.C.E07" Date: Thu, 4 Jun 2026 11:43:25 +0800 Subject: [PATCH 1/4] feature: Added counts based on operator name and qubits specified to `Circuit` --- src/braket/circuits/circuit.py | 51 +++++++++++++++++++ .../braket/circuits/test_circuit.py | 15 ++++++ 2 files changed, 66 insertions(+) diff --git a/src/braket/circuits/circuit.py b/src/braket/circuits/circuit.py index b656763c3..8a851a114 100644 --- a/src/braket/circuits/circuit.py +++ b/src/braket/circuits/circuit.py @@ -1626,6 +1626,57 @@ def _add_fixed_argument_calibrations( }) return additional_calibrations + def count( + self, + operator: str | None = None, + qubits: QubitSet | None = None, + ) -> int | Counter[str]: + """Counts circuit instructions by operator name, optionally filtered by specific + operators and/or qubits. + + Args: + operator (str | None): Optional operator name to count. Matching is case-insensitive. + If not provided, returns counts for all operator names. + qubits (QubitSet | None): Optional set of qubits to consider. If not provided, + considers all qubits. + + Returns: + int | Counter[str]: The count for ``operator`` if provided, otherwise a ``Counter`` + keyed by operator name. + + Raises: + ValueError: If any qubits in ``qubits`` are not present in the circuit + + Examples: + >>> circuit = Circuit().h(0).h(1).cnot(0, 1) + >>> circuit.count("cnot") + 1 + >>> circuit.count() + Counter({'cnot': 1, 'h': 2}) + >>> circuit.count(qubits={0}) + Counter({'cnot': 1, 'h': 1}) + >>> circuit.count(qubits={0}, operator="h") + 1 + """ + counts: dict[str, int] = {} + + if qubits and qubits.intersection(self.qubits) != qubits: + raise ValueError( + "All qubits in the 'qubits' argument must be present in the circuit. " + f"Invalid qubits: {qubits - self.qubits}" + ) + + for instruction in self.instructions: + if qubits and not set(instruction.target).intersection(qubits): + continue + name = instruction.operator.name.lower() + counts[name] = counts.get(name, 0) + 1 + + if operator: + return counts.get(operator.lower(), 0) + + return Counter(counts) + def to_unitary(self) -> np.ndarray: """Returns the unitary matrix representation of the entire circuit. diff --git a/test/unit_tests/braket/circuits/test_circuit.py b/test/unit_tests/braket/circuits/test_circuit.py index aca5adc04..a7218ffb2 100644 --- a/test/unit_tests/braket/circuits/test_circuit.py +++ b/test/unit_tests/braket/circuits/test_circuit.py @@ -3831,3 +3831,18 @@ def test_barrier_jaqcd_export_fails(): pytest.raises(NotImplementedError, match="Barrier is not supported in JAQCD"), ): circ.to_ir(IRType.JAQCD) + + +def test_circuit_count_ops(): + circ = Circuit().h(0).h(1).cnot(0, 1).measure([0, 1]) + assert circ.count("cnot") == 1 + assert circ.count("h") == 2 + assert circ.count() == {"cnot": 1, "h": 2, "measure": 2} + assert circ.count(qubits={0}) == {"cnot": 1, "h": 1, "measure": 1} + assert circ.count(qubits={0}, operator="h") == 1 + + with pytest.raises( + ValueError, + match="All qubits in the 'qubits' argument must be present in the circuit", + ): + circ.count(qubits={2}) From d8f982e770633ba53b4535fcff02a3073da4c133 Mon Sep 17 00:00:00 2001 From: "A.C.E07" Date: Wed, 17 Jun 2026 20:14:28 +0800 Subject: [PATCH 2/4] Added inclusion/exclusion for noise operators --- src/braket/circuits/circuit.py | 20 ++++++++++++++++--- .../braket/circuits/test_circuit.py | 16 ++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/braket/circuits/circuit.py b/src/braket/circuits/circuit.py index 8a851a114..54e07590e 100644 --- a/src/braket/circuits/circuit.py +++ b/src/braket/circuits/circuit.py @@ -1630,6 +1630,7 @@ def count( self, operator: str | None = None, qubits: QubitSet | None = None, + include_noise: bool = False, ) -> int | Counter[str]: """Counts circuit instructions by operator name, optionally filtered by specific operators and/or qubits. @@ -1639,6 +1640,8 @@ def count( If not provided, returns counts for all operator names. qubits (QubitSet | None): Optional set of qubits to consider. If not provided, considers all qubits. + include_noise (bool): Whether to include noise instructions in the count. + Default is False. Returns: int | Counter[str]: The count for ``operator`` if provided, otherwise a ``Counter`` @@ -1648,7 +1651,7 @@ def count( ValueError: If any qubits in ``qubits`` are not present in the circuit Examples: - >>> circuit = Circuit().h(0).h(1).cnot(0, 1) + >>> circuit = Circuit().h(0).h(1).cnot(0, 1).amplitude_damping(0, gamma=0.1) >>> circuit.count("cnot") 1 >>> circuit.count() @@ -1657,18 +1660,29 @@ def count( Counter({'cnot': 1, 'h': 1}) >>> circuit.count(qubits={0}, operator="h") 1 + >>> circuit.count(include_noise=True) + Counter({'cnot': 1, 'h': 2, 'amplitude_damping': 1}) """ counts: dict[str, int] = {} - if qubits and qubits.intersection(self.qubits) != qubits: + # to avoid erroring on qubits that are part of the circuit but not targeted + # by any instruction we construct the following set as opposed to just using + # :attr:`self.qubits` directly + circuit_qubits = set( + range(min(self.qubits), max(self.qubits) + 1) + ) if self.qubits else set() + + if qubits and qubits.intersection(circuit_qubits) != qubits: raise ValueError( "All qubits in the 'qubits' argument must be present in the circuit. " - f"Invalid qubits: {qubits - self.qubits}" + f"Invalid qubits: {qubits - circuit_qubits}" ) for instruction in self.instructions: if qubits and not set(instruction.target).intersection(qubits): continue + if not include_noise and isinstance(instruction.operator, Noise): + continue name = instruction.operator.name.lower() counts[name] = counts.get(name, 0) + 1 diff --git a/test/unit_tests/braket/circuits/test_circuit.py b/test/unit_tests/braket/circuits/test_circuit.py index a7218ffb2..6ed65fe37 100644 --- a/test/unit_tests/braket/circuits/test_circuit.py +++ b/test/unit_tests/braket/circuits/test_circuit.py @@ -3834,15 +3834,25 @@ def test_barrier_jaqcd_export_fails(): def test_circuit_count_ops(): - circ = Circuit().h(0).h(1).cnot(0, 1).measure([0, 1]) + circ = Circuit().h(0).h(1).cnot(0, 1).measure([0, 1]).gphase(0.5) assert circ.count("cnot") == 1 assert circ.count("h") == 2 - assert circ.count() == {"cnot": 1, "h": 2, "measure": 2} + assert circ.count() == {"cnot": 1, "h": 2, "measure": 2, "gphase": 1} assert circ.count(qubits={0}) == {"cnot": 1, "h": 1, "measure": 1} assert circ.count(qubits={0}, operator="h") == 1 + circ = Circuit().cnot(0, 2) + assert circ.count(qubits={1}) == {} + + circ = Circuit().amplitude_damping(0, gamma=0.1) + + assert circ.count() == {} + assert circ.count(include_noise=True) == {"amplitudedamping": 1} + assert circ.count(qubits={0}, include_noise=True) == {"amplitudedamping": 1} + assert circ.count(operator="amplitudedamping", include_noise=True) == 1 + with pytest.raises( ValueError, match="All qubits in the 'qubits' argument must be present in the circuit", ): - circ.count(qubits={2}) + circ.count(qubits={3}) From 20193860af80f40f34ab8763db46ec3bae7ac589 Mon Sep 17 00:00:00 2001 From: "A.C.E07" Date: Wed, 17 Jun 2026 20:16:01 +0800 Subject: [PATCH 3/4] Fixed a docstring typo --- src/braket/circuits/circuit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/circuits/circuit.py b/src/braket/circuits/circuit.py index 54e07590e..f8b603799 100644 --- a/src/braket/circuits/circuit.py +++ b/src/braket/circuits/circuit.py @@ -1661,7 +1661,7 @@ def count( >>> circuit.count(qubits={0}, operator="h") 1 >>> circuit.count(include_noise=True) - Counter({'cnot': 1, 'h': 2, 'amplitude_damping': 1}) + Counter({'cnot': 1, 'h': 2, 'amplitudedamping': 1}) """ counts: dict[str, int] = {} From cdb4be9f7da4628a915bd34b181680ba724ac5b3 Mon Sep 17 00:00:00 2001 From: "A.C.E07" Date: Fri, 19 Jun 2026 15:25:27 +0800 Subject: [PATCH 4/4] Applied review notes --- src/braket/circuits/circuit.py | 4 ++-- test/unit_tests/braket/circuits/test_circuit.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/braket/circuits/circuit.py b/src/braket/circuits/circuit.py index f8b603799..13b6fa783 100644 --- a/src/braket/circuits/circuit.py +++ b/src/braket/circuits/circuit.py @@ -1669,8 +1669,8 @@ def count( # by any instruction we construct the following set as opposed to just using # :attr:`self.qubits` directly circuit_qubits = set( - range(min(self.qubits), max(self.qubits) + 1) - ) if self.qubits else set() + set(range(min(self.qubits), max(self.qubits) + 1)) if self.qubits else set() + ) if qubits and qubits.intersection(circuit_qubits) != qubits: raise ValueError( diff --git a/test/unit_tests/braket/circuits/test_circuit.py b/test/unit_tests/braket/circuits/test_circuit.py index 6ed65fe37..bc02fd575 100644 --- a/test/unit_tests/braket/circuits/test_circuit.py +++ b/test/unit_tests/braket/circuits/test_circuit.py @@ -3837,7 +3837,9 @@ def test_circuit_count_ops(): circ = Circuit().h(0).h(1).cnot(0, 1).measure([0, 1]).gphase(0.5) assert circ.count("cnot") == 1 assert circ.count("h") == 2 + assert circ.count("unknown") == 0 assert circ.count() == {"cnot": 1, "h": 2, "measure": 2, "gphase": 1} + assert circ.count(qubits={0, 1}) == {"cnot": 1, "h": 2, "measure": 2} assert circ.count(qubits={0}) == {"cnot": 1, "h": 1, "measure": 1} assert circ.count(qubits={0}, operator="h") == 1