From 895d9fb3c134aa1fee4365e683e324ede708c08d Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Wed, 4 Jun 2025 13:39:08 -0700 Subject: [PATCH 1/6] Update RB to reduce the size of the generated circuits --- .../experiments/qubit_characterizations.py | 37 ++++++++++++++++--- .../qubit_characterizations_test.py | 9 +++-- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/cirq-core/cirq/experiments/qubit_characterizations.py b/cirq-core/cirq/experiments/qubit_characterizations.py index 5dbc22e9a6e..568e8b1436d 100644 --- a/cirq-core/cirq/experiments/qubit_characterizations.py +++ b/cirq-core/cirq/experiments/qubit_characterizations.py @@ -19,6 +19,7 @@ import itertools from typing import Any, cast, Iterator, Mapping, Sequence, TYPE_CHECKING +import attrs import numpy as np from matplotlib import pyplot as plt @@ -36,7 +37,31 @@ import cirq -@dataclasses.dataclass +def _canonize_clifford_sequences( + sequences: list[list[ops.SingleQubitCliffordGate]], +) -> list[list[ops.SingleQubitCliffordGate]]: + return [[_reduce_gate_seq(seq)] for seq in sequences] + + +@attrs.frozen +class _CliffordGateSequence: + gate_sequence: list[list[ops.SingleQubitCliffordGate]] + + @functools.cached_property + def _reduced_gate_sequence(self): + return _canonize_clifford_sequences(self.gate_sequence) + + def __iter__(self): + yield from self._reduced_gate_sequence + + def __getitem__(self, idx): + return self._reduced_gate_sequence[idx] + + def __len__(self): + return len(self._reduced_gate_sequence) + + +@attrs.frozen class Cliffords: """The single-qubit Clifford group, decomposed into elementary gates. @@ -54,11 +79,11 @@ class Cliffords: s1_y """ - c1_in_xy: list[list[ops.SingleQubitCliffordGate]] - c1_in_xz: list[list[ops.SingleQubitCliffordGate]] - s1: list[list[ops.SingleQubitCliffordGate]] - s1_x: list[list[ops.SingleQubitCliffordGate]] - s1_y: list[list[ops.SingleQubitCliffordGate]] + c1_in_xy: _CliffordGateSequence = attrs.field(converter=_CliffordGateSequence) + c1_in_xz: _CliffordGateSequence = attrs.field(converter=_CliffordGateSequence) + s1: _CliffordGateSequence = attrs.field(converter=_CliffordGateSequence) + s1_x: _CliffordGateSequence = attrs.field(converter=_CliffordGateSequence) + s1_y: _CliffordGateSequence = attrs.field(converter=_CliffordGateSequence) class RandomizedBenchMarkResult: diff --git a/cirq-core/cirq/experiments/qubit_characterizations_test.py b/cirq-core/cirq/experiments/qubit_characterizations_test.py index 6e792c16477..8f6a5e3f4cc 100644 --- a/cirq-core/cirq/experiments/qubit_characterizations_test.py +++ b/cirq-core/cirq/experiments/qubit_characterizations_test.py @@ -74,7 +74,7 @@ def check_distinct(unitaries): assert is_pauli(u @ p @ u.conj().T), str(u) # Check that XZ decomposition has at most one X gate per clifford. - for gates in cliffords.c1_in_xz: + for gates in cliffords.c1_in_xz.gate_sequence: num_i = len([gate for gate in gates if gate == cirq.ops.SingleQubitCliffordGate.I]) num_x = len( [ @@ -229,13 +229,16 @@ def test_tomography_plot_raises_for_incorrect_number_of_axes(): result.plot(axes) -def test_single_qubit_cliffords_gateset(): +@pytest.mark.parametrize('num_cliffords', range(5, 10)) +def test_single_qubit_cliffords_gateset(num_cliffords): qubits = [GridQubit(0, i) for i in range(4)] clifford_group = cirq.experiments.qubit_characterizations._single_qubit_cliffords() c = cirq.experiments.qubit_characterizations._create_parallel_rb_circuit( - qubits, 5, clifford_group.c1_in_xy + qubits, num_cliffords, clifford_group.c1_in_xy ) device = cirq.testing.ValidatingTestDevice( qubits=qubits, allowed_gates=(cirq.ops.PhasedXZGate, cirq.MeasurementGate) ) device.validate_circuit(c) + + assert len(c) == num_cliffords + 2 From 266cfcd1d399ed703b8ad7ef57a8a0a3470839cd Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Wed, 4 Jun 2025 13:45:02 -0700 Subject: [PATCH 2/6] mypy --- cirq-core/cirq/experiments/qubit_characterizations.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cirq-core/cirq/experiments/qubit_characterizations.py b/cirq-core/cirq/experiments/qubit_characterizations.py index 568e8b1436d..43f7d3d0e18 100644 --- a/cirq-core/cirq/experiments/qubit_characterizations.py +++ b/cirq-core/cirq/experiments/qubit_characterizations.py @@ -702,7 +702,9 @@ def _measurement(two_qubit_circuit: circuits.Circuit) -> np.ndarray: def _create_parallel_rb_circuit( - qubits: Sequence[cirq.Qid], num_cliffords: int, c1: list + qubits: Sequence[cirq.Qid], + num_cliffords: int, + c1: _CliffordGateSequence | list[list[ops.SingleQubitCliffordGate]], ) -> cirq.Circuit: sequences_to_zip = [_random_single_q_clifford(qubit, num_cliffords, c1) for qubit in qubits] # Ensure each sequence has the same number of moments. From 401449e869c359a549b0cb16d12c80df1108ddc8 Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Wed, 4 Jun 2025 14:34:04 -0700 Subject: [PATCH 3/6] mypy --- cirq-core/cirq/experiments/qubit_characterizations.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cirq-core/cirq/experiments/qubit_characterizations.py b/cirq-core/cirq/experiments/qubit_characterizations.py index 43f7d3d0e18..e40e1e32171 100644 --- a/cirq-core/cirq/experiments/qubit_characterizations.py +++ b/cirq-core/cirq/experiments/qubit_characterizations.py @@ -757,7 +757,9 @@ def _two_qubit_clifford_matrices(q_0: cirq.Qid, q_1: cirq.Qid, cliffords: Cliffo def _random_single_q_clifford( - qubit: cirq.Qid, num_cfds: int, cfds: Sequence[Sequence[cirq.ops.SingleQubitCliffordGate]] + qubit: cirq.Qid, + num_cfds: int, + cfds: Sequence[Sequence[cirq.ops.SingleQubitCliffordGate]] | _single_qubit_cliffords, ) -> list[cirq.Operation]: clifford_group_size = 24 operations = [[gate.to_phased_xz_gate()(qubit) for gate in gates] for gates in cfds] From 04847957286538fb66ccc3f264b2c49eaa447525 Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Wed, 4 Jun 2025 14:50:21 -0700 Subject: [PATCH 4/6] mypy --- cirq-core/cirq/experiments/qubit_characterizations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/experiments/qubit_characterizations.py b/cirq-core/cirq/experiments/qubit_characterizations.py index e40e1e32171..e57b40828da 100644 --- a/cirq-core/cirq/experiments/qubit_characterizations.py +++ b/cirq-core/cirq/experiments/qubit_characterizations.py @@ -759,7 +759,7 @@ def _two_qubit_clifford_matrices(q_0: cirq.Qid, q_1: cirq.Qid, cliffords: Cliffo def _random_single_q_clifford( qubit: cirq.Qid, num_cfds: int, - cfds: Sequence[Sequence[cirq.ops.SingleQubitCliffordGate]] | _single_qubit_cliffords, + cfds: Sequence[Sequence[cirq.ops.SingleQubitCliffordGate]] | _CliffordGateSequence, ) -> list[cirq.Operation]: clifford_group_size = 24 operations = [[gate.to_phased_xz_gate()(qubit) for gate in gates] for gates in cfds] From cfcb3d69aff556172458e37db77200d1c16ce6cb Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Thu, 5 Jun 2025 09:38:33 -0700 Subject: [PATCH 5/6] change default value of use_xy_basis and add docstring --- .../experiments/qubit_characterizations.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/cirq-core/cirq/experiments/qubit_characterizations.py b/cirq-core/cirq/experiments/qubit_characterizations.py index e57b40828da..00c580bd244 100644 --- a/cirq-core/cirq/experiments/qubit_characterizations.py +++ b/cirq-core/cirq/experiments/qubit_characterizations.py @@ -39,25 +39,31 @@ def _canonize_clifford_sequences( sequences: list[list[ops.SingleQubitCliffordGate]], -) -> list[list[ops.SingleQubitCliffordGate]]: - return [[_reduce_gate_seq(seq)] for seq in sequences] +) -> list[tuple[ops.SingleQubitCliffordGate]]: + return [(_reduce_gate_seq(seq),) for seq in sequences] @attrs.frozen class _CliffordGateSequence: + """Wrap around a list of sequences of clifford gates. + + This class wraps around a list of sequences of clifford gates and re-exposes them as + a list of tuple where each tuple contains a single clifford gates. + """ + gate_sequence: list[list[ops.SingleQubitCliffordGate]] @functools.cached_property - def _reduced_gate_sequence(self): + def _reduced_gate_sequence(self) -> list[tuple[ops.SingleQubitCliffordGate]]: return _canonize_clifford_sequences(self.gate_sequence) - def __iter__(self): + def __iter__(self) -> Iterator[tuple[ops.SingleQubitCliffordGate]]: yield from self._reduced_gate_sequence - def __getitem__(self, idx): + def __getitem__(self, idx) -> tuple[ops.SingleQubitCliffordGate]: return self._reduced_gate_sequence[idx] - def __len__(self): + def __len__(self) -> int: return len(self._reduced_gate_sequence) @@ -415,7 +421,7 @@ def single_qubit_randomized_benchmarking( def parallel_single_qubit_randomized_benchmarking( sampler: cirq.Sampler, qubits: Sequence[cirq.Qid], - use_xy_basis: bool = True, + use_xy_basis: bool = False, *, num_clifford_range: Sequence[int] = tuple( np.logspace(np.log10(5), np.log10(1000), 5, dtype=int) From 39ba4b4a7d9b4376c093fbe8752f04d5f0e0416f Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Thu, 5 Jun 2025 09:40:19 -0700 Subject: [PATCH 6/6] nit --- cirq-core/cirq/experiments/qubit_characterizations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/experiments/qubit_characterizations.py b/cirq-core/cirq/experiments/qubit_characterizations.py index 00c580bd244..4ee9c971d87 100644 --- a/cirq-core/cirq/experiments/qubit_characterizations.py +++ b/cirq-core/cirq/experiments/qubit_characterizations.py @@ -367,7 +367,7 @@ def plot( def single_qubit_randomized_benchmarking( sampler: cirq.Sampler, qubit: cirq.Qid, - use_xy_basis: bool = True, + use_xy_basis: bool = False, *, num_clifford_range: Sequence[int] = tuple(np.logspace(np.log10(5), 3, 5, dtype=int)), num_circuits: int = 10,