From 008f022f236adf03b2ef821f1538dde0461a2d8f Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Tue, 4 Nov 2025 22:19:38 +0000 Subject: [PATCH 01/13] Use cirq.q instead of str in analog --- .../analog_trajectory_util.py | 26 +++---- .../analog_trajectory_util_test.py | 77 +++++++++++-------- .../generic_analog_circuit.py | 18 ++--- .../generic_analog_circuit_test.py | 45 ++++++----- 4 files changed, 89 insertions(+), 77 deletions(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py index 9f60e034d74..420be40be40 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py @@ -40,8 +40,8 @@ class FrequencyMap: """ duration: su.ValueOrSymbol - qubit_freqs: dict[str, su.ValueOrSymbol | None] - couplings: dict[tuple[str, str], su.ValueOrSymbol] + qubit_freqs: dict[cirq.Qid, su.ValueOrSymbol | None] + couplings: dict[tuple[cirq.Qid, cirq.Qid], su.ValueOrSymbol] is_wait_step: bool def _is_parameterized_(self) -> bool: @@ -86,8 +86,8 @@ def __init__( self, *, full_trajectory: list[FrequencyMap], - qubits: list[str], - pairs: list[tuple[str, str]], + qubits: list[cirq.Qid], + pairs: list[tuple[cirq.Qid, cirq.Qid]], ): self.full_trajectory = full_trajectory self.qubits = qubits @@ -99,12 +99,12 @@ def from_sparse_trajectory( sparse_trajectory: list[ tuple[ tu.Value, - dict[str, su.ValueOrSymbol | None], - dict[tuple[str, str], su.ValueOrSymbol], + dict[cirq.Qid, su.ValueOrSymbol | None], + dict[cirq.Coupler, su.ValueOrSymbol], ], ], - qubits: list[str] | None = None, - pairs: list[tuple[str, str]] | None = None, + qubits: list[cirq.Qid] | None = None, + pairs: list[cirq.Coupler | tuple[cirq.Qid, cirq.Qid]] | None = None, ): """Construct AnalogTrajectory from sparse trajectory. @@ -121,8 +121,8 @@ def from_sparse_trajectory( pairs: The pairs in interest. If not provided, automatically parsed from trajectory. """ if qubits is None or pairs is None: - qubits_in_traj: list[str] = [] - pairs_in_traj: list[tuple[str, str]] = [] + qubits_in_traj: list[cirq.Qid] = [] + pairs_in_traj: list[tuple[cirq.Qid, cirq.Qid]] = [] for _, q, p in sparse_trajectory: qubits_in_traj.extend(q.keys()) pairs_in_traj.extend(p.keys()) @@ -130,8 +130,8 @@ def from_sparse_trajectory( pairs = list(set(pairs_in_traj)) full_trajectory: list[FrequencyMap] = [] - init_qubit_freq_dict: dict[str, tu.Value | None] = {q: None for q in qubits} - init_g_dict: dict[tuple[str, str], tu.Value] = {p: 0 * tu.MHz for p in pairs} + init_qubit_freq_dict: dict[cirq.Qid, tu.Value | None] = {q: None for q in qubits} + init_g_dict: dict[tuple[cirq.Qid, cirq.Qid], tu.Value] = {p: 0 * tu.MHz for p in pairs} full_trajectory.append(FrequencyMap(0 * tu.ns, init_qubit_freq_dict, init_g_dict, False)) for dt, qubit_freq_dict, g_dict in sparse_trajectory: @@ -142,7 +142,7 @@ def from_sparse_trajectory( q: qubit_freq_dict.get(q, full_trajectory[-1].qubit_freqs.get(q)) for q in qubits } # If no g provided, set equal to previous - new_g_dict: dict[tuple[str, str], tu.Value] = { + new_g_dict: dict[tuple[cirq.Qid, cirq.Qid], tu.Value] = { p: g_dict.get(p, full_trajectory[-1].couplings.get(p)) for p in pairs # type: ignore[misc] } diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py index d55afd19de0..5efb2b655ad 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py @@ -24,8 +24,11 @@ def freq_map() -> atu.FrequencyMap: return atu.FrequencyMap( 10 * tu.ns, - {"q0_0": 5 * tu.GHz, "q0_1": 6 * tu.GHz, "q0_2": sympy.Symbol("f_q0_2")}, - {("q0_0", "q0_1"): 5 * tu.MHz, ("q0_1", "q0_2"): sympy.Symbol("g_q0_1_q0_2")}, + {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 6 * tu.GHz, cirq.q(0, 2): sympy.Symbol("f_q0_2")}, + { + (cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, + (cirq.q(0, 1), cirq.q(0, 2)): sympy.Symbol("g_q0_1_q0_2"), + }, False, ) @@ -41,24 +44,26 @@ def test_freq_map_resolve(freq_map: atu.FrequencyMap) -> None: ) assert resolved_freq_map == atu.FrequencyMap( 10 * tu.ns, - {"q0_0": 5 * tu.GHz, "q0_1": 6 * tu.GHz, "q0_2": 6 * tu.GHz}, - {("q0_0", "q0_1"): 5 * tu.MHz, ("q0_1", "q0_2"): 7 * tu.MHz}, + {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 6 * tu.GHz, cirq.q(0, 2): 6 * tu.GHz}, + {(cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 7 * tu.MHz}, False, ) -FreqMapType = tuple[tu.Value, dict[str, tu.Value | None], dict[tuple[str, str], tu.Value]] +FreqMapType = tuple[ + tu.Value, dict[cirq.Qid, tu.Value | None], dict[tuple[cirq.Qid, cirq.Qid], tu.Value] +] @pytest.fixture def sparse_trajectory() -> list[FreqMapType]: - traj1: FreqMapType = (20 * tu.ns, {"q0_1": 5 * tu.GHz}, {}) - traj2: FreqMapType = (30 * tu.ns, {"q0_2": 8 * tu.GHz}, {}) + traj1: FreqMapType = (20 * tu.ns, {cirq.q(0, 1): 5 * tu.GHz}, {}) + traj2: FreqMapType = (30 * tu.ns, {cirq.q(0, 2): 8 * tu.GHz}, {}) traj3: FreqMapType = (35 * tu.ns, {}, {}) traj4: FreqMapType = ( 40 * tu.ns, - {"q0_0": 8 * tu.GHz, "q0_1": None, "q0_2": None}, - {("q0_0", "q0_1"): 5 * tu.MHz, ("q0_1", "q0_2"): 8 * tu.MHz}, + {cirq.q(0, 0): 8 * tu.GHz, cirq.q(0, 1): None, cirq.q(0, 2): None}, + {(cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 8 * tu.MHz}, ) return [traj1, traj2, traj3, traj4] @@ -68,32 +73,32 @@ def test_full_traj(sparse_trajectory: list[FreqMapType]) -> None: assert len(analog_traj.full_trajectory) == 5 assert analog_traj.full_trajectory[0] == atu.FrequencyMap( 0 * tu.ns, - {"q0_0": None, "q0_1": None, "q0_2": None}, - {("q0_0", "q0_1"): 0 * tu.MHz, ("q0_1", "q0_2"): 0 * tu.MHz}, + {cirq.q(0, 0): None, cirq.q(0, 1): None, cirq.q(0, 2): None}, + {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, False, ) assert analog_traj.full_trajectory[1] == atu.FrequencyMap( 20 * tu.ns, - {"q0_0": None, "q0_1": 5 * tu.GHz, "q0_2": None}, - {("q0_0", "q0_1"): 0 * tu.MHz, ("q0_1", "q0_2"): 0 * tu.MHz}, + {cirq.q(0, 0): None, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): None}, + {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, False, ) assert analog_traj.full_trajectory[2] == atu.FrequencyMap( 30 * tu.ns, - {"q0_0": None, "q0_1": 5 * tu.GHz, "q0_2": 8 * tu.GHz}, - {("q0_0", "q0_1"): 0 * tu.MHz, ("q0_1", "q0_2"): 0 * tu.MHz}, + {cirq.q(0, 0): None, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): 8 * tu.GHz}, + {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, False, ) assert analog_traj.full_trajectory[3] == atu.FrequencyMap( 35 * tu.ns, - {"q0_0": None, "q0_1": 5 * tu.GHz, "q0_2": 8 * tu.GHz}, - {("q0_0", "q0_1"): 0 * tu.MHz, ("q0_1", "q0_2"): 0 * tu.MHz}, + {cirq.q(0, 0): None, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): 8 * tu.GHz}, + {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, True, ) assert analog_traj.full_trajectory[4] == atu.FrequencyMap( 40 * tu.ns, - {"q0_0": 8 * tu.GHz, "q0_1": None, "q0_2": None}, - {("q0_0", "q0_1"): 5 * tu.MHz, ("q0_1", "q0_2"): 8 * tu.MHz}, + {cirq.q(0, 0): 8 * tu.GHz, cirq.q(0, 1): None, cirq.q(0, 2): None}, + {(cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 8 * tu.MHz}, False, ) @@ -102,45 +107,45 @@ def test_get_full_trajectory_with_resolved_idles(sparse_trajectory: list[FreqMap analog_traj = atu.AnalogTrajectory.from_sparse_trajectory(sparse_trajectory) resolved_full_traj = analog_traj.get_full_trajectory_with_resolved_idles( - {"q0_0": 5 * tu.GHz, "q0_1": 6 * tu.GHz, "q0_2": 7 * tu.GHz} + {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 6 * tu.GHz, cirq.q(0, 2): 7 * tu.GHz} ) assert len(resolved_full_traj) == 5 assert resolved_full_traj[0] == atu.FrequencyMap( 0 * tu.ns, - {"q0_0": 5 * tu.GHz, "q0_1": 6 * tu.GHz, "q0_2": 7 * tu.GHz}, - {("q0_0", "q0_1"): 0 * tu.MHz, ("q0_1", "q0_2"): 0 * tu.MHz}, + {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 6 * tu.GHz, cirq.q(0, 2): 7 * tu.GHz}, + {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, False, ) assert resolved_full_traj[1] == atu.FrequencyMap( 20 * tu.ns, - {"q0_0": 5 * tu.GHz, "q0_1": 5 * tu.GHz, "q0_2": 7 * tu.GHz}, - {("q0_0", "q0_1"): 0 * tu.MHz, ("q0_1", "q0_2"): 0 * tu.MHz}, + {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): 7 * tu.GHz}, + {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, False, ) assert resolved_full_traj[2] == atu.FrequencyMap( 30 * tu.ns, - {"q0_0": 5 * tu.GHz, "q0_1": 5 * tu.GHz, "q0_2": 8 * tu.GHz}, - {("q0_0", "q0_1"): 0 * tu.MHz, ("q0_1", "q0_2"): 0 * tu.MHz}, + {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): 8 * tu.GHz}, + {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, False, ) assert resolved_full_traj[3] == atu.FrequencyMap( 35 * tu.ns, - {"q0_0": 5 * tu.GHz, "q0_1": 5 * tu.GHz, "q0_2": 8 * tu.GHz}, - {("q0_0", "q0_1"): 0 * tu.MHz, ("q0_1", "q0_2"): 0 * tu.MHz}, + {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): 8 * tu.GHz}, + {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, True, ) assert resolved_full_traj[4] == atu.FrequencyMap( 40 * tu.ns, - {"q0_0": 8 * tu.GHz, "q0_1": 6 * tu.GHz, "q0_2": 7 * tu.GHz}, - {("q0_0", "q0_1"): 5 * tu.MHz, ("q0_1", "q0_2"): 8 * tu.MHz}, + {cirq.q(0, 0): 8 * tu.GHz, cirq.q(0, 1): 6 * tu.GHz, cirq.q(0, 2): 7 * tu.GHz}, + {(cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 8 * tu.MHz}, False, ) def test_plot_with_unresolved_parameters() -> None: - traj1: FreqMapType = (20 * tu.ns, {"q0_1": sympy.Symbol("qf")}, {}) - traj2: FreqMapType = (sympy.Symbol("t"), {"q0_2": 8 * tu.GHz}, {}) + traj1: FreqMapType = (20 * tu.ns, {cirq.q(0, 1): sympy.Symbol("qf")}, {}) + traj2: FreqMapType = (sympy.Symbol("t"), {cirq.q(0, 2): 8 * tu.GHz}, {}) analog_traj = atu.AnalogTrajectory.from_sparse_trajectory([traj1, traj2]) with pytest.raises(ValueError): @@ -148,7 +153,11 @@ def test_plot_with_unresolved_parameters() -> None: def test_analog_traj_plot() -> None: - traj1: FreqMapType = (5 * tu.ns, {"q0_1": sympy.Symbol("qf")}, {("q0_0", "q0_1"): 2 * tu.MHz}) - traj2: FreqMapType = (sympy.Symbol("t"), {"q0_2": 8 * tu.GHz}, {}) + traj1: FreqMapType = ( + 5 * tu.ns, + {cirq.q(0, 1): sympy.Symbol("qf")}, + {(cirq.q(0, 0), cirq.q(0, 1)): 2 * tu.MHz}, + ) + traj2: FreqMapType = (sympy.Symbol("t"), {cirq.q(0, 2): 8 * tu.GHz}, {}) analog_traj = atu.AnalogTrajectory.from_sparse_trajectory([traj1, traj2]) analog_traj.plot(resolver={"t": 10 * tu.ns, "qf": 5 * tu.GHz}) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py index 1859d8cb788..7da37bb0308 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py @@ -22,10 +22,10 @@ def _get_neighbor_freqs( - qubit_pair: tuple[str, str], qubit_freq_dict: dict[str, su.ValueOrSymbol | None] + qubit_pair: tuple[cirq.Qid, cirq.Qid], qubit_freq_dict: dict[cirq.Qid, su.ValueOrSymbol | None] ) -> tuple[su.ValueOrSymbol | None, su.ValueOrSymbol | None]: """Get neighbor freqs from qubit_freq_dict given the pair.""" - sorted_pair = sorted(qubit_pair, key=_to_grid_qubit) + sorted_pair = sorted(qubit_pair) return (qubit_freq_dict[sorted_pair[0]], qubit_freq_dict[sorted_pair[1]]) @@ -43,14 +43,10 @@ def _coupler_name_from_qubit_pair(qubit_pair: tuple[str, str]) -> str: def _get_neighbor_coupler_freqs( - qubit_name: str, coupler_g_dict: dict[tuple[str, str], su.ValueOrSymbol] + qubit: cirq.Qid, coupler_g_dict: dict[tuple[cirq.Qid, cirq.Qid], su.ValueOrSymbol] ) -> dict[str, su.ValueOrSymbol]: """Get neighbor coupler coupling strength g given qubit name.""" - return { - _coupler_name_from_qubit_pair(pair): g - for pair, g in coupler_g_dict.items() - if qubit_name in pair - } + return {pair: g for pair, g in coupler_g_dict.items() if qubit in pair} class GenericAnalogCircuitBuilder: @@ -90,7 +86,7 @@ def make_circuit(self) -> cirq.Circuit: moments = [] for freq_map in self.trajectory.full_trajectory[1:]: if freq_map.is_wait_step: - targets = [_to_grid_qubit(q) for q in self.trajectory.qubits] + targets = self.trajectory.qubits wait_gate = wg.WaitGateWithUnit( freq_map.duration, qid_shape=cirq.qid_shape(targets) ) @@ -119,7 +115,7 @@ def make_one_moment( q, prev_freq_map.couplings ), linear_rise=self.linear_qubit_ramp, - ).on(_to_grid_qubit(q)) + ).on(q) ) coupler_gates = [] for p, g_max in freq_map.couplings.items(): @@ -138,7 +134,7 @@ def make_one_moment( neighbor_qubits_freq=_get_neighbor_freqs(p, freq_map.qubit_freqs), prev_neighbor_qubits_freq=_get_neighbor_freqs(p, prev_freq_map.qubit_freqs), interpolate_coupling_cal=self.interpolate_coupling_cal, - ).on(*sorted([_to_grid_qubit(p[0]), _to_grid_qubit(p[1])])) + ).on(*sorted([p[0], p[1]])) ) return cirq.Moment(qubit_gates + coupler_gates) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py index 3996c504a61..6c82159984d 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py @@ -25,8 +25,11 @@ def test_get_neighbor_freqs() -> None: - pair = ("q0_0", "q0_1") - qubit_freq_dict = {"q0_0": 5 * tu.GHz, "q0_1": sympy.Symbol("f_q"), "q0_2": 6 * tu.GHz} + q0 = cirq.GridQubit(0, 0) + q1 = cirq.GridQubit(0, 1) + q2 = cirq.GridQubit(0, 2) + pair = (q0, q1) + qubit_freq_dict = {q0: 5 * tu.GHz, q1: sympy.Symbol("f_q"), q2: 6 * tu.GHz} neighbor_freqs = gac._get_neighbor_freqs(pair, qubit_freq_dict) assert neighbor_freqs == (5 * tu.GHz, sympy.Symbol("f_q")) @@ -54,16 +57,21 @@ def test_coupler_name_from_qubit_pair() -> None: def test_make_one_moment_of_generic_analog_circuit() -> None: + q0 = cirq.GridQubit(0, 0) + q1 = cirq.GridQubit(0, 1) + q2 = cirq.GridQubit(0, 2) + pair1 = (q0, q1) + pair2 = (q1, q2) freq_map = atu.FrequencyMap( duration=3 * tu.ns, - qubit_freqs={"q0_0": 5 * tu.GHz, "q0_1": 6 * tu.GHz, "q0_2": sympy.Symbol("f_q0_2")}, - couplings={("q0_0", "q0_1"): 5 * tu.MHz, ("q0_1", "q0_2"): 6 * tu.MHz}, + qubit_freqs={q0: 5 * tu.GHz, q1: 6 * tu.GHz, q2: sympy.Symbol("f_q0_2")}, + couplings={pair1: 5 * tu.MHz, pair2: 6 * tu.MHz}, is_wait_step=False, ) prev_freq_map = atu.FrequencyMap( duration=9 * tu.ns, - qubit_freqs={"q0_0": 4 * tu.GHz, "q0_1": 6 * tu.GHz, "q0_2": sympy.Symbol("f_q0_2")}, - couplings={("q0_0", "q0_1"): 2 * tu.MHz, ("q0_1", "q0_2"): 3 * tu.MHz}, + qubit_freqs={q0: 4 * tu.GHz, q1: 6 * tu.GHz, q2: sympy.Symbol("f_q0_2")}, + couplings={pair1: 2 * tu.MHz, pair2: 3 * tu.MHz}, is_wait_step=False, ) @@ -78,8 +86,8 @@ def test_make_one_moment_of_generic_analog_circuit() -> None: w=3 * tu.ns, target_freq=5 * tu.GHz, prev_freq=4 * tu.GHz, - neighbor_coupler_g_dict={"c_q0_0_q0_1": 5 * tu.MHz}, - prev_neighbor_coupler_g_dict={"c_q0_0_q0_1": 2 * tu.MHz}, + neighbor_coupler_g_dict={pair1: 5 * tu.MHz}, + prev_neighbor_coupler_g_dict={pair1: 2 * tu.MHz}, linear_rise=True, ).on(cirq.GridQubit(0, 0)) assert moment.operations[1] == AnalogDetuneQubit( @@ -87,8 +95,8 @@ def test_make_one_moment_of_generic_analog_circuit() -> None: w=3 * tu.ns, target_freq=6 * tu.GHz, prev_freq=6 * tu.GHz, - neighbor_coupler_g_dict={"c_q0_0_q0_1": 5 * tu.MHz, "c_q0_1_q0_2": 6 * tu.MHz}, - prev_neighbor_coupler_g_dict={"c_q0_0_q0_1": 2 * tu.MHz, "c_q0_1_q0_2": 3 * tu.MHz}, + neighbor_coupler_g_dict={pair1: 5 * tu.MHz, pair2: 6 * tu.MHz}, + prev_neighbor_coupler_g_dict={pair1: 2 * tu.MHz, pair2: 3 * tu.MHz}, linear_rise=True, ).on(cirq.GridQubit(0, 1)) assert moment.operations[2] == AnalogDetuneQubit( @@ -96,8 +104,8 @@ def test_make_one_moment_of_generic_analog_circuit() -> None: w=3 * tu.ns, target_freq=sympy.Symbol("f_q0_2"), prev_freq=sympy.Symbol("f_q0_2"), - neighbor_coupler_g_dict={"c_q0_1_q0_2": 6 * tu.MHz}, - prev_neighbor_coupler_g_dict={"c_q0_1_q0_2": 3 * tu.MHz}, + neighbor_coupler_g_dict={pair2: 6 * tu.MHz}, + prev_neighbor_coupler_g_dict={pair2: 3 * tu.MHz}, linear_rise=True, ).on(cirq.GridQubit(0, 2)) @@ -125,17 +133,16 @@ def test_make_one_moment_of_generic_analog_circuit() -> None: def test_generic_analog_make_circuit() -> None: + q0 = cirq.GridQubit(0, 0) + q1 = cirq.GridQubit(0, 1) + trajectory = atu.AnalogTrajectory.from_sparse_trajectory( [ - (5 * tu.ns, {"q0_0": 5 * tu.GHz}, {}), + (5 * tu.ns, {q0: 5 * tu.GHz}, {}), (sympy.Symbol('t'), {}, {}), - ( - 10 * tu.ns, - {"q0_0": 8 * tu.GHz, "q0_1": sympy.Symbol('f')}, - {("q0_0", "q0_1"): -5 * tu.MHz}, - ), + (10 * tu.ns, {q0: 8 * tu.GHz, q1: sympy.Symbol('f')}, {(q0, q1): -5 * tu.MHz}), (3 * tu.ns, {}, {}), - (2 * tu.ns, {"q0_1": 4 * tu.GHz}, {}), + (2 * tu.ns, {q1: 4 * tu.GHz}, {}), ] ) builder = gac.GenericAnalogCircuitBuilder(trajectory) From 560b859576051d41bd9fb297ce9175b372d1c623 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Tue, 4 Nov 2025 22:26:08 +0000 Subject: [PATCH 02/13] fix the type issue --- .../analog_experiments/analog_trajectory_util.py | 8 ++++---- .../analog_experiments/generic_analog_circuit.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py index 420be40be40..024aa585db2 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py @@ -100,11 +100,11 @@ def from_sparse_trajectory( tuple[ tu.Value, dict[cirq.Qid, su.ValueOrSymbol | None], - dict[cirq.Coupler, su.ValueOrSymbol], + dict[tuple[cirq.Qid, cirq.Qid], su.ValueOrSymbol], ], ], qubits: list[cirq.Qid] | None = None, - pairs: list[cirq.Coupler | tuple[cirq.Qid, cirq.Qid]] | None = None, + pairs: list[tuple[cirq.Qid, cirq.Qid]] | None = None, ): """Construct AnalogTrajectory from sparse trajectory. @@ -150,7 +150,7 @@ def from_sparse_trajectory( return cls(full_trajectory=full_trajectory, qubits=qubits, pairs=pairs) def get_full_trajectory_with_resolved_idles( - self, idle_freq_map: dict[str, tu.Value] + self, idle_freq_map: dict[cirq.Qid, tu.Value] ) -> list[FrequencyMap]: """Insert idle frequencies instead of None in trajectory.""" @@ -164,7 +164,7 @@ def get_full_trajectory_with_resolved_idles( def plot( self, - idle_freq_map: dict[str, tu.Value] | None = None, + idle_freq_map: dict[cirq.Qid, tu.Value] | None = None, default_idle_freq: tu.Value = 6.5 * tu.GHz, resolver: cirq.ParamResolverOrSimilarType | None = None, axes: tuple[Axes, Axes] | None = None, diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py index 7da37bb0308..20d291dbfed 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py @@ -44,7 +44,7 @@ def _coupler_name_from_qubit_pair(qubit_pair: tuple[str, str]) -> str: def _get_neighbor_coupler_freqs( qubit: cirq.Qid, coupler_g_dict: dict[tuple[cirq.Qid, cirq.Qid], su.ValueOrSymbol] -) -> dict[str, su.ValueOrSymbol]: +) -> dict[cirq.Qid, su.ValueOrSymbol]: """Get neighbor coupler coupling strength g given qubit name.""" return {pair: g for pair, g in coupler_g_dict.items() if qubit in pair} From 7b39c072c930a57f7ee861405ddec1b2ccee4dd5 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Wed, 5 Nov 2025 00:13:24 +0000 Subject: [PATCH 03/13] allow mixed coupler and pair usage but always coupler inside --- .../analog_trajectory_util.py | 21 ++++++++----- .../analog_trajectory_util_test.py | 31 ++++++++++++------- .../generic_analog_circuit.py | 12 +++---- .../generic_analog_circuit_test.py | 12 +++---- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py index 024aa585db2..aafdcf2ec03 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py @@ -22,6 +22,7 @@ import tunits as tu import cirq +from cirq_google.ops import coupler as cgc from cirq_google.study import symbol_util as su if TYPE_CHECKING: @@ -41,7 +42,7 @@ class FrequencyMap: duration: su.ValueOrSymbol qubit_freqs: dict[cirq.Qid, su.ValueOrSymbol | None] - couplings: dict[tuple[cirq.Qid, cirq.Qid], su.ValueOrSymbol] + couplings: dict[cgc.Coupler, su.ValueOrSymbol] is_wait_step: bool def _is_parameterized_(self) -> bool: @@ -87,7 +88,7 @@ def __init__( *, full_trajectory: list[FrequencyMap], qubits: list[cirq.Qid], - pairs: list[tuple[cirq.Qid, cirq.Qid]], + pairs: list[cgc.Coupler], ): self.full_trajectory = full_trajectory self.qubits = qubits @@ -100,11 +101,11 @@ def from_sparse_trajectory( tuple[ tu.Value, dict[cirq.Qid, su.ValueOrSymbol | None], - dict[tuple[cirq.Qid, cirq.Qid], su.ValueOrSymbol], + dict[tuple[cirq.Qid, cirq.Qid] | cgc.Coupler, su.ValueOrSymbol], ], ], qubits: list[cirq.Qid] | None = None, - pairs: list[tuple[cirq.Qid, cirq.Qid]] | None = None, + pairs: list[tuple[cirq.Qid, cirq.Qid] | cgc.Coupler] | None = None, ): """Construct AnalogTrajectory from sparse trajectory. @@ -129,12 +130,18 @@ def from_sparse_trajectory( qubits = list(set(qubits_in_traj)) pairs = list(set(pairs_in_traj)) + def _to_coupler(pair: tuple[cirq.Qid, cirq.Qid] | cgc.Coupler) -> cgc.Coupler: + return pair if isinstance(pair, cgc.Coupler) else cgc.Coupler(*pair) + + pairs = [_to_coupler(pair) for pair in pairs] # Convert to coupler always. + full_trajectory: list[FrequencyMap] = [] init_qubit_freq_dict: dict[cirq.Qid, tu.Value | None] = {q: None for q in qubits} - init_g_dict: dict[tuple[cirq.Qid, cirq.Qid], tu.Value] = {p: 0 * tu.MHz for p in pairs} + init_g_dict: dict[cgc.Coupler, tu.Value] = {p: 0 * tu.MHz for p in pairs} full_trajectory.append(FrequencyMap(0 * tu.ns, init_qubit_freq_dict, init_g_dict, False)) for dt, qubit_freq_dict, g_dict in sparse_trajectory: + g_dict = {_to_coupler(p): g for p, g in g_dict.items()} # Convert to coupler always. # When both qubit_freq_dict and g_dict is empty, it is a wait step. is_wait_step = not (qubit_freq_dict or g_dict) # If no freq provided, set equal to previous @@ -142,8 +149,8 @@ def from_sparse_trajectory( q: qubit_freq_dict.get(q, full_trajectory[-1].qubit_freqs.get(q)) for q in qubits } # If no g provided, set equal to previous - new_g_dict: dict[tuple[cirq.Qid, cirq.Qid], tu.Value] = { - p: g_dict.get(p, full_trajectory[-1].couplings.get(p)) for p in pairs # type: ignore[misc] + new_g_dict: dict[cgc.Coupler, tu.Value] = { + _to_coupler(p): g_dict.get(p, full_trajectory[-1].couplings.get(p)) for p in pairs } full_trajectory.append(FrequencyMap(dt, new_qubit_freq_dict, new_g_dict, is_wait_step)) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py index 5efb2b655ad..6967dfffbe0 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py @@ -17,6 +17,7 @@ import tunits as tu import cirq +import cirq_google as cg from cirq_google.experimental.analog_experiments import analog_trajectory_util as atu @@ -63,42 +64,48 @@ def sparse_trajectory() -> list[FreqMapType]: traj4: FreqMapType = ( 40 * tu.ns, {cirq.q(0, 0): 8 * tu.GHz, cirq.q(0, 1): None, cirq.q(0, 2): None}, - {(cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 8 * tu.MHz}, + { + cg.Coupler(cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, + cg.Coupler(cirq.q(0, 1), cirq.q(0, 2)): 8 * tu.MHz, + }, ) return [traj1, traj2, traj3, traj4] def test_full_traj(sparse_trajectory: list[FreqMapType]) -> None: analog_traj = atu.AnalogTrajectory.from_sparse_trajectory(sparse_trajectory) + coupler1 = cg.Coupler(cirq.q(0, 0), cirq.q(0, 1)) + coupler2 = cg.Coupler(cirq.q(0, 1), cirq.q(0, 2)) + assert len(analog_traj.full_trajectory) == 5 assert analog_traj.full_trajectory[0] == atu.FrequencyMap( 0 * tu.ns, {cirq.q(0, 0): None, cirq.q(0, 1): None, cirq.q(0, 2): None}, - {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, + {coupler1: 0 * tu.MHz, coupler2: 0 * tu.MHz}, False, ) assert analog_traj.full_trajectory[1] == atu.FrequencyMap( 20 * tu.ns, {cirq.q(0, 0): None, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): None}, - {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, + {coupler1: 0 * tu.MHz, coupler2: 0 * tu.MHz}, False, ) assert analog_traj.full_trajectory[2] == atu.FrequencyMap( 30 * tu.ns, {cirq.q(0, 0): None, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): 8 * tu.GHz}, - {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, + {coupler1: 0 * tu.MHz, coupler2: 0 * tu.MHz}, False, ) assert analog_traj.full_trajectory[3] == atu.FrequencyMap( 35 * tu.ns, {cirq.q(0, 0): None, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): 8 * tu.GHz}, - {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, + {coupler1: 0 * tu.MHz, coupler2: 0 * tu.MHz}, True, ) assert analog_traj.full_trajectory[4] == atu.FrequencyMap( 40 * tu.ns, {cirq.q(0, 0): 8 * tu.GHz, cirq.q(0, 1): None, cirq.q(0, 2): None}, - {(cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 8 * tu.MHz}, + {coupler1: 5 * tu.MHz, coupler2: 8 * tu.MHz}, False, ) @@ -109,36 +116,38 @@ def test_get_full_trajectory_with_resolved_idles(sparse_trajectory: list[FreqMap resolved_full_traj = analog_traj.get_full_trajectory_with_resolved_idles( {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 6 * tu.GHz, cirq.q(0, 2): 7 * tu.GHz} ) + coupler1 = cg.Coupler(cirq.q(0, 0), cirq.q(0, 1)) + coupler2 = cg.Coupler(cirq.q(0, 1), cirq.q(0, 2)) assert len(resolved_full_traj) == 5 assert resolved_full_traj[0] == atu.FrequencyMap( 0 * tu.ns, {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 6 * tu.GHz, cirq.q(0, 2): 7 * tu.GHz}, - {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, + {coupler1: 0 * tu.MHz, coupler2: 0 * tu.MHz}, False, ) assert resolved_full_traj[1] == atu.FrequencyMap( 20 * tu.ns, {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): 7 * tu.GHz}, - {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, + {coupler1: 0 * tu.MHz, coupler2: 0 * tu.MHz}, False, ) assert resolved_full_traj[2] == atu.FrequencyMap( 30 * tu.ns, {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): 8 * tu.GHz}, - {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, + {coupler1: 0 * tu.MHz, coupler2: 0 * tu.MHz}, False, ) assert resolved_full_traj[3] == atu.FrequencyMap( 35 * tu.ns, {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 5 * tu.GHz, cirq.q(0, 2): 8 * tu.GHz}, - {(cirq.q(0, 0), cirq.q(0, 1)): 0 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 0 * tu.MHz}, + {coupler1: 0 * tu.MHz, coupler2: 0 * tu.MHz}, True, ) assert resolved_full_traj[4] == atu.FrequencyMap( 40 * tu.ns, {cirq.q(0, 0): 8 * tu.GHz, cirq.q(0, 1): 6 * tu.GHz, cirq.q(0, 2): 7 * tu.GHz}, - {(cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 8 * tu.MHz}, + {coupler1: 5 * tu.MHz, coupler2: 8 * tu.MHz}, False, ) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py index 20d291dbfed..4b3dd23a9f3 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py @@ -17,15 +17,15 @@ import cirq from cirq_google.experimental.analog_experiments import analog_trajectory_util as atu -from cirq_google.ops import analog_detune_gates as adg, wait_gate as wg +from cirq_google.ops import analog_detune_gates as adg, coupler as cgc, wait_gate as wg from cirq_google.study import symbol_util as su def _get_neighbor_freqs( - qubit_pair: tuple[cirq.Qid, cirq.Qid], qubit_freq_dict: dict[cirq.Qid, su.ValueOrSymbol | None] + coupler: cgc.Coupler, qubit_freq_dict: dict[cirq.Qid, su.ValueOrSymbol | None] ) -> tuple[su.ValueOrSymbol | None, su.ValueOrSymbol | None]: """Get neighbor freqs from qubit_freq_dict given the pair.""" - sorted_pair = sorted(qubit_pair) + sorted_pair = sorted(coupler.qubits) return (qubit_freq_dict[sorted_pair[0]], qubit_freq_dict[sorted_pair[1]]) @@ -43,10 +43,10 @@ def _coupler_name_from_qubit_pair(qubit_pair: tuple[str, str]) -> str: def _get_neighbor_coupler_freqs( - qubit: cirq.Qid, coupler_g_dict: dict[tuple[cirq.Qid, cirq.Qid], su.ValueOrSymbol] + qubit: cirq.Qid, coupler_g_dict: dict[cgc.Coupler, su.ValueOrSymbol] ) -> dict[cirq.Qid, su.ValueOrSymbol]: """Get neighbor coupler coupling strength g given qubit name.""" - return {pair: g for pair, g in coupler_g_dict.items() if qubit in pair} + return {coupler: g for coupler, g in coupler_g_dict.items() if qubit in coupler.qubits} class GenericAnalogCircuitBuilder: @@ -134,7 +134,7 @@ def make_one_moment( neighbor_qubits_freq=_get_neighbor_freqs(p, freq_map.qubit_freqs), prev_neighbor_qubits_freq=_get_neighbor_freqs(p, prev_freq_map.qubit_freqs), interpolate_coupling_cal=self.interpolate_coupling_cal, - ).on(*sorted([p[0], p[1]])) + ).on(p) ) return cirq.Moment(qubit_gates + coupler_gates) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py index 6c82159984d..68c3c9a57bb 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py @@ -17,6 +17,7 @@ import tunits as tu import cirq +import cirq_google as cg from cirq_google.experimental.analog_experiments import ( analog_trajectory_util as atu, generic_analog_circuit as gac, @@ -28,7 +29,7 @@ def test_get_neighbor_freqs() -> None: q0 = cirq.GridQubit(0, 0) q1 = cirq.GridQubit(0, 1) q2 = cirq.GridQubit(0, 2) - pair = (q0, q1) + pair = cg.Coupler(q0, q1) qubit_freq_dict = {q0: 5 * tu.GHz, q1: sympy.Symbol("f_q"), q2: 6 * tu.GHz} neighbor_freqs = gac._get_neighbor_freqs(pair, qubit_freq_dict) assert neighbor_freqs == (5 * tu.GHz, sympy.Symbol("f_q")) @@ -60,8 +61,8 @@ def test_make_one_moment_of_generic_analog_circuit() -> None: q0 = cirq.GridQubit(0, 0) q1 = cirq.GridQubit(0, 1) q2 = cirq.GridQubit(0, 2) - pair1 = (q0, q1) - pair2 = (q1, q2) + pair1 = cg.Coupler(q0, q1) + pair2 = cg.Coupler(q1, q2) freq_map = atu.FrequencyMap( duration=3 * tu.ns, qubit_freqs={q0: 5 * tu.GHz, q1: 6 * tu.GHz, q2: sympy.Symbol("f_q0_2")}, @@ -119,7 +120,7 @@ def test_make_one_moment_of_generic_analog_circuit() -> None: neighbor_qubits_freq=(5 * tu.GHz, 6 * tu.GHz), prev_neighbor_qubits_freq=(4 * tu.GHz, 6 * tu.GHz), interpolate_coupling_cal=False, - ).on(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)) + ).on(pair1) assert moment.operations[4] == AnalogDetuneCouplerOnly( length=3 * tu.ns, w=3 * tu.ns, @@ -129,7 +130,7 @@ def test_make_one_moment_of_generic_analog_circuit() -> None: neighbor_qubits_freq=(6 * tu.GHz, sympy.Symbol("f_q0_2")), prev_neighbor_qubits_freq=(6 * tu.GHz, sympy.Symbol("f_q0_2")), interpolate_coupling_cal=False, - ).on(cirq.GridQubit(0, 1), cirq.GridQubit(0, 2)) + ).on(pair2) def test_generic_analog_make_circuit() -> None: @@ -153,7 +154,6 @@ def test_generic_analog_make_circuit() -> None: assert isinstance(op.gate, AnalogDetuneQubit) for op in circuit[1].operations: assert isinstance(op.gate, cirq.WaitGate) - assert isinstance(circuit[2].operations[0].gate, AnalogDetuneQubit) assert isinstance(circuit[2].operations[1].gate, AnalogDetuneQubit) assert isinstance(circuit[2].operations[2].gate, AnalogDetuneCouplerOnly) From 6c04d43b6ea32e04a1b6fb2d21e79648f10cc54a Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Wed, 5 Nov 2025 00:48:43 +0000 Subject: [PATCH 04/13] Fix the pair usage --- .../analog_experiments/analog_trajectory_util.py | 10 +++++----- .../analog_experiments/generic_analog_circuit.py | 8 ++++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py index aafdcf2ec03..e1550985fb1 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py @@ -123,7 +123,7 @@ def from_sparse_trajectory( """ if qubits is None or pairs is None: qubits_in_traj: list[cirq.Qid] = [] - pairs_in_traj: list[tuple[cirq.Qid, cirq.Qid]] = [] + pairs_in_traj: list[tuple[cirq.Qid, cirq.Qid] | cgc.Coupler] = [] for _, q, p in sparse_trajectory: qubits_in_traj.extend(q.keys()) pairs_in_traj.extend(p.keys()) @@ -133,11 +133,11 @@ def from_sparse_trajectory( def _to_coupler(pair: tuple[cirq.Qid, cirq.Qid] | cgc.Coupler) -> cgc.Coupler: return pair if isinstance(pair, cgc.Coupler) else cgc.Coupler(*pair) - pairs = [_to_coupler(pair) for pair in pairs] # Convert to coupler always. + couplers = [_to_coupler(c) for c in pairs] # Convert to coupler always. full_trajectory: list[FrequencyMap] = [] init_qubit_freq_dict: dict[cirq.Qid, tu.Value | None] = {q: None for q in qubits} - init_g_dict: dict[cgc.Coupler, tu.Value] = {p: 0 * tu.MHz for p in pairs} + init_g_dict: dict[cgc.Coupler, tu.Value] = {c: 0 * tu.MHz for c in couplers} full_trajectory.append(FrequencyMap(0 * tu.ns, init_qubit_freq_dict, init_g_dict, False)) for dt, qubit_freq_dict, g_dict in sparse_trajectory: @@ -150,11 +150,11 @@ def _to_coupler(pair: tuple[cirq.Qid, cirq.Qid] | cgc.Coupler) -> cgc.Coupler: } # If no g provided, set equal to previous new_g_dict: dict[cgc.Coupler, tu.Value] = { - _to_coupler(p): g_dict.get(p, full_trajectory[-1].couplings.get(p)) for p in pairs + _to_coupler(p): g_dict.get(p, full_trajectory[-1].couplings.get(p)) for p in pairs # type: ignore[arg-type] } full_trajectory.append(FrequencyMap(dt, new_qubit_freq_dict, new_g_dict, is_wait_step)) - return cls(full_trajectory=full_trajectory, qubits=qubits, pairs=pairs) + return cls(full_trajectory=full_trajectory, qubits=qubits, pairs=couplers) def get_full_trajectory_with_resolved_idles( self, idle_freq_map: dict[cirq.Qid, tu.Value] diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py index 4b3dd23a9f3..827372f363a 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py @@ -44,9 +44,13 @@ def _coupler_name_from_qubit_pair(qubit_pair: tuple[str, str]) -> str: def _get_neighbor_coupler_freqs( qubit: cirq.Qid, coupler_g_dict: dict[cgc.Coupler, su.ValueOrSymbol] -) -> dict[cirq.Qid, su.ValueOrSymbol]: +) -> dict[str, su.ValueOrSymbol]: """Get neighbor coupler coupling strength g given qubit name.""" - return {coupler: g for coupler, g in coupler_g_dict.items() if qubit in coupler.qubits} + return { + _coupler_name_from_qubit_pair(coupler.qubits): g + for coupler, g in coupler_g_dict.items() + if qubit in coupler.qubits + } class GenericAnalogCircuitBuilder: From 3056980a1e974f1ea2064c496aac478e766c9fd3 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Wed, 5 Nov 2025 00:57:02 +0000 Subject: [PATCH 05/13] more fix --- .../analog_experiments/analog_trajectory_util.py | 2 +- .../analog_trajectory_util_test.py | 13 +++++++------ .../generic_analog_circuit_test.py | 12 ++++++------ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py index e1550985fb1..64dc19073ed 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py @@ -150,7 +150,7 @@ def _to_coupler(pair: tuple[cirq.Qid, cirq.Qid] | cgc.Coupler) -> cgc.Coupler: } # If no g provided, set equal to previous new_g_dict: dict[cgc.Coupler, tu.Value] = { - _to_coupler(p): g_dict.get(p, full_trajectory[-1].couplings.get(p)) for p in pairs # type: ignore[arg-type] + _to_coupler(p): g_dict.get(p, full_trajectory[-1].couplings.get(p)) for p in pairs # type: ignore[misc] } full_trajectory.append(FrequencyMap(dt, new_qubit_freq_dict, new_g_dict, is_wait_step)) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py index 6967dfffbe0..cf3471186d5 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py @@ -27,8 +27,8 @@ def freq_map() -> atu.FrequencyMap: 10 * tu.ns, {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 6 * tu.GHz, cirq.q(0, 2): sympy.Symbol("f_q0_2")}, { - (cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, - (cirq.q(0, 1), cirq.q(0, 2)): sympy.Symbol("g_q0_1_q0_2"), + cg.Coupler(cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, + cg.Coupler(cirq.q(0, 1), cirq.q(0, 2)): sympy.Symbol("g_q0_1_q0_2"), }, False, ) @@ -46,14 +46,15 @@ def test_freq_map_resolve(freq_map: atu.FrequencyMap) -> None: assert resolved_freq_map == atu.FrequencyMap( 10 * tu.ns, {cirq.q(0, 0): 5 * tu.GHz, cirq.q(0, 1): 6 * tu.GHz, cirq.q(0, 2): 6 * tu.GHz}, - {(cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, (cirq.q(0, 1), cirq.q(0, 2)): 7 * tu.MHz}, + { + cg.Coupler(cirq.q(0, 0), cirq.q(0, 1)): 5 * tu.MHz, + cg.Coupler(cirq.q(0, 1), cirq.q(0, 2)): 7 * tu.MHz, + }, False, ) -FreqMapType = tuple[ - tu.Value, dict[cirq.Qid, tu.Value | None], dict[tuple[cirq.Qid, cirq.Qid], tu.Value] -] +FreqMapType = tuple[tu.Value, dict[cirq.Qid, tu.Value | None], dict[cg.Coupler, tu.Value]] @pytest.fixture diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py index 68c3c9a57bb..f521463382d 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py @@ -87,8 +87,8 @@ def test_make_one_moment_of_generic_analog_circuit() -> None: w=3 * tu.ns, target_freq=5 * tu.GHz, prev_freq=4 * tu.GHz, - neighbor_coupler_g_dict={pair1: 5 * tu.MHz}, - prev_neighbor_coupler_g_dict={pair1: 2 * tu.MHz}, + neighbor_coupler_g_dict={"c_q0_0_q0_1": 5 * tu.MHz}, + prev_neighbor_coupler_g_dict={"c_q0_0_q0_1": 2 * tu.MHz}, linear_rise=True, ).on(cirq.GridQubit(0, 0)) assert moment.operations[1] == AnalogDetuneQubit( @@ -96,8 +96,8 @@ def test_make_one_moment_of_generic_analog_circuit() -> None: w=3 * tu.ns, target_freq=6 * tu.GHz, prev_freq=6 * tu.GHz, - neighbor_coupler_g_dict={pair1: 5 * tu.MHz, pair2: 6 * tu.MHz}, - prev_neighbor_coupler_g_dict={pair1: 2 * tu.MHz, pair2: 3 * tu.MHz}, + neighbor_coupler_g_dict={"c_q0_0_q0_1": 5 * tu.MHz, "c_q0_1_q0_2": 6 * tu.MHz}, + prev_neighbor_coupler_g_dict={"c_q0_0_q0_1": 2 * tu.MHz, "c_q0_1_q0_2": 3 * tu.MHz}, linear_rise=True, ).on(cirq.GridQubit(0, 1)) assert moment.operations[2] == AnalogDetuneQubit( @@ -105,8 +105,8 @@ def test_make_one_moment_of_generic_analog_circuit() -> None: w=3 * tu.ns, target_freq=sympy.Symbol("f_q0_2"), prev_freq=sympy.Symbol("f_q0_2"), - neighbor_coupler_g_dict={pair2: 6 * tu.MHz}, - prev_neighbor_coupler_g_dict={pair2: 3 * tu.MHz}, + neighbor_coupler_g_dict={"c_q0_1_q0_2": 6 * tu.MHz}, + prev_neighbor_coupler_g_dict={"c_q0_1_q0_2": 3 * tu.MHz}, linear_rise=True, ).on(cirq.GridQubit(0, 2)) From b7a588a3dac44281eeb5c5a5c4dcef486c314a70 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Wed, 5 Nov 2025 01:11:59 +0000 Subject: [PATCH 06/13] use coupler always --- .../analog_trajectory_util.py | 22 +++++++------------ .../analog_trajectory_util_test.py | 2 +- .../generic_analog_circuit.py | 8 +++---- .../generic_analog_circuit_test.py | 18 +++++++++------ 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py index 64dc19073ed..77b687ff9f7 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py @@ -101,11 +101,11 @@ def from_sparse_trajectory( tuple[ tu.Value, dict[cirq.Qid, su.ValueOrSymbol | None], - dict[tuple[cirq.Qid, cirq.Qid] | cgc.Coupler, su.ValueOrSymbol], + dict[cgc.Coupler, su.ValueOrSymbol], ], ], qubits: list[cirq.Qid] | None = None, - pairs: list[tuple[cirq.Qid, cirq.Qid] | cgc.Coupler] | None = None, + pairs: list[cgc.Coupler] | None = None, ): """Construct AnalogTrajectory from sparse trajectory. @@ -113,8 +113,8 @@ def from_sparse_trajectory( sparse_trajectory: A list of tuples, where each tuple defines a `FrequencyMap` and contains three elements: (duration, qubit_freqs, coupling_strengths). `duration` is a tunits value, `qubit_freqs` is a dictionary mapping qubit strings - to detuning frequencies, and `coupling_strengths` is a dictionary mapping qubit - pairs to their coupling strength. This format is considered "sparse" because each + to detuning frequencies, and `coupling_strengths` is a dictionary mapping + coupler to their coupling strength. This format is considered "sparse" because each tuple does not need to fully specify all qubits and coupling pairs; any missing detuning frequency or coupling strength will be set to the same value as the previous value in the list. @@ -123,25 +123,19 @@ def from_sparse_trajectory( """ if qubits is None or pairs is None: qubits_in_traj: list[cirq.Qid] = [] - pairs_in_traj: list[tuple[cirq.Qid, cirq.Qid] | cgc.Coupler] = [] + pairs_in_traj: list[cgc.Coupler] = [] for _, q, p in sparse_trajectory: qubits_in_traj.extend(q.keys()) pairs_in_traj.extend(p.keys()) qubits = list(set(qubits_in_traj)) pairs = list(set(pairs_in_traj)) - def _to_coupler(pair: tuple[cirq.Qid, cirq.Qid] | cgc.Coupler) -> cgc.Coupler: - return pair if isinstance(pair, cgc.Coupler) else cgc.Coupler(*pair) - - couplers = [_to_coupler(c) for c in pairs] # Convert to coupler always. - full_trajectory: list[FrequencyMap] = [] init_qubit_freq_dict: dict[cirq.Qid, tu.Value | None] = {q: None for q in qubits} - init_g_dict: dict[cgc.Coupler, tu.Value] = {c: 0 * tu.MHz for c in couplers} + init_g_dict: dict[cgc.Coupler, tu.Value] = {c: 0 * tu.MHz for c in pairs} full_trajectory.append(FrequencyMap(0 * tu.ns, init_qubit_freq_dict, init_g_dict, False)) for dt, qubit_freq_dict, g_dict in sparse_trajectory: - g_dict = {_to_coupler(p): g for p, g in g_dict.items()} # Convert to coupler always. # When both qubit_freq_dict and g_dict is empty, it is a wait step. is_wait_step = not (qubit_freq_dict or g_dict) # If no freq provided, set equal to previous @@ -150,11 +144,11 @@ def _to_coupler(pair: tuple[cirq.Qid, cirq.Qid] | cgc.Coupler) -> cgc.Coupler: } # If no g provided, set equal to previous new_g_dict: dict[cgc.Coupler, tu.Value] = { - _to_coupler(p): g_dict.get(p, full_trajectory[-1].couplings.get(p)) for p in pairs # type: ignore[misc] + c: g_dict.get(c, full_trajectory[-1].couplings.get(c)) for c in pairs # type: ignore[misc] } full_trajectory.append(FrequencyMap(dt, new_qubit_freq_dict, new_g_dict, is_wait_step)) - return cls(full_trajectory=full_trajectory, qubits=qubits, pairs=couplers) + return cls(full_trajectory=full_trajectory, qubits=qubits, pairs=pairs) def get_full_trajectory_with_resolved_idles( self, idle_freq_map: dict[cirq.Qid, tu.Value] diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py index cf3471186d5..b2ad5a418c6 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py @@ -166,7 +166,7 @@ def test_analog_traj_plot() -> None: traj1: FreqMapType = ( 5 * tu.ns, {cirq.q(0, 1): sympy.Symbol("qf")}, - {(cirq.q(0, 0), cirq.q(0, 1)): 2 * tu.MHz}, + {cg.Coupler(cirq.q(0, 0), cirq.q(0, 1)): 2 * tu.MHz}, ) traj2: FreqMapType = (sympy.Symbol("t"), {cirq.q(0, 2): 8 * tu.GHz}, {}) analog_traj = atu.AnalogTrajectory.from_sparse_trajectory([traj1, traj2]) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py index 827372f363a..99fb3d419b1 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py @@ -37,9 +37,9 @@ def _to_grid_qubit(qubit_name: str) -> cirq.GridQubit: return cirq.GridQubit(int(match[1]), int(match[2])) -def _coupler_name_from_qubit_pair(qubit_pair: tuple[str, str]) -> str: - sorted_pair = sorted(qubit_pair, key=_to_grid_qubit) - return f"c_{sorted_pair[0]}_{sorted_pair[1]}" +def _coupler_name(coupler: cgc.Coupler) -> str: + q1, q2 = sorted(coupler.qubits) + return f"c_q{q1.row}_{q1.col}_q{q2.row}_{q2.col}" def _get_neighbor_coupler_freqs( @@ -47,7 +47,7 @@ def _get_neighbor_coupler_freqs( ) -> dict[str, su.ValueOrSymbol]: """Get neighbor coupler coupling strength g given qubit name.""" return { - _coupler_name_from_qubit_pair(coupler.qubits): g + _coupler_name(coupler): g for coupler, g in coupler_g_dict.items() if qubit in coupler.qubits } diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py index f521463382d..77bbfff64f2 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py @@ -44,16 +44,16 @@ def test_to_grid_qubit() -> None: def test_coupler_name_from_qubit_pair() -> None: - pair = ("q0_0", "q0_1") - coupler_name = gac._coupler_name_from_qubit_pair(pair) + pair = cg.Coupler(cirq.q(0, 0), cirq.q(0, 1)) + coupler_name = gac._coupler_name(pair) assert coupler_name == "c_q0_0_q0_1" - pair = ("q9_0", "q10_0") - coupler_name = gac._coupler_name_from_qubit_pair(pair) + pair = cg.Coupler(cirq.q(9, 0), cirq.q(10, 0)) + coupler_name = gac._coupler_name(pair) assert coupler_name == "c_q9_0_q10_0" - pair = ("q7_8", "q7_7") - coupler_name = gac._coupler_name_from_qubit_pair(pair) + pair = cg.Coupler(cirq.q(7, 8), cirq.q(7, 7)) + coupler_name = gac._coupler_name(pair) assert coupler_name == "c_q7_7_q7_8" @@ -141,7 +141,11 @@ def test_generic_analog_make_circuit() -> None: [ (5 * tu.ns, {q0: 5 * tu.GHz}, {}), (sympy.Symbol('t'), {}, {}), - (10 * tu.ns, {q0: 8 * tu.GHz, q1: sympy.Symbol('f')}, {(q0, q1): -5 * tu.MHz}), + ( + 10 * tu.ns, + {q0: 8 * tu.GHz, q1: sympy.Symbol('f')}, + {cg.Coupler(q0, q1): -5 * tu.MHz}, + ), (3 * tu.ns, {}, {}), (2 * tu.ns, {q1: 4 * tu.GHz}, {}), ] From 7518a2f4bb309027177ef3c2eee5e4be842b734c Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Wed, 5 Nov 2025 01:25:57 +0000 Subject: [PATCH 07/13] fix type --- .../experimental/analog_experiments/analog_trajectory_util.py | 3 ++- .../experimental/analog_experiments/generic_analog_circuit.py | 2 +- .../analog_experiments/generic_analog_circuit_test.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py index 77b687ff9f7..6b200c73277 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py @@ -22,12 +22,13 @@ import tunits as tu import cirq -from cirq_google.ops import coupler as cgc from cirq_google.study import symbol_util as su if TYPE_CHECKING: from matplotlib.axes import Axes + from cirq_google.ops import coupler as cgc + @attrs.mutable class FrequencyMap: diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py index 99fb3d419b1..c0aeba0c6bf 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py @@ -39,7 +39,7 @@ def _to_grid_qubit(qubit_name: str) -> cirq.GridQubit: def _coupler_name(coupler: cgc.Coupler) -> str: q1, q2 = sorted(coupler.qubits) - return f"c_q{q1.row}_{q1.col}_q{q2.row}_{q2.col}" + return f"c_q{q1.row}_{q1.col}_q{q2.row}_{q2.col}" # type: ignore[return-value] def _get_neighbor_coupler_freqs( diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py index 77bbfff64f2..27f0ee3361e 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py @@ -31,7 +31,7 @@ def test_get_neighbor_freqs() -> None: q2 = cirq.GridQubit(0, 2) pair = cg.Coupler(q0, q1) qubit_freq_dict = {q0: 5 * tu.GHz, q1: sympy.Symbol("f_q"), q2: 6 * tu.GHz} - neighbor_freqs = gac._get_neighbor_freqs(pair, qubit_freq_dict) + neighbor_freqs = gac._get_neighbor_freqs(pair, qubit_freq_dict) # type: ignore[arg-type] assert neighbor_freqs == (5 * tu.GHz, sympy.Symbol("f_q")) From ebe8ae158f6216e52311e7afd2a9be3bfbc176e4 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Wed, 5 Nov 2025 02:21:45 +0000 Subject: [PATCH 08/13] fix --- .../experimental/analog_experiments/generic_analog_circuit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py index c0aeba0c6bf..cf22bdb3545 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py @@ -39,7 +39,7 @@ def _to_grid_qubit(qubit_name: str) -> cirq.GridQubit: def _coupler_name(coupler: cgc.Coupler) -> str: q1, q2 = sorted(coupler.qubits) - return f"c_q{q1.row}_{q1.col}_q{q2.row}_{q2.col}" # type: ignore[return-value] + return f"c_q{q1.row}_{q1.col}_q{q2.row}_{q2.col}" # type: ignore[attr-defined] def _get_neighbor_coupler_freqs( From 17e4e85e4393939f5d864f61b47e9d7a02b54387 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Thu, 6 Nov 2025 17:53:12 +0000 Subject: [PATCH 09/13] fix the traj plot --- .../analog_experiments/analog_trajectory_util.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py index 6b200c73277..eaa4f887e58 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py @@ -167,12 +167,18 @@ def get_full_trajectory_with_resolved_idles( def plot( self, idle_freq_map: dict[cirq.Qid, tu.Value] | None = None, - default_idle_freq: tu.Value = 6.5 * tu.GHz, resolver: cirq.ParamResolverOrSimilarType | None = None, axes: tuple[Axes, Axes] | None = None, ) -> tuple[Axes, Axes]: if idle_freq_map is None: - idle_freq_map = {q: default_idle_freq for q in self.qubits} + # Because we use relative frequencies and we do not expose the idle frequencies, + # we randomly assign idle frequencies for plotting purposes only. + idle_freq_map = {q: np.random.randn() * 50 * tu.MHz for q in self.qubits} + else: + for q in self.qubits: + if q not in idle_freq_map: # Fill in missing idle freqs + idle_freq_map[q] = np.random.randn() * 50 * tu.MHz + full_trajectory_resolved = cirq.resolve_parameters( self.get_full_trajectory_with_resolved_idles(idle_freq_map), resolver ) From 3a3a61389db08795fbf8b354de8655c8944c868e Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Fri, 7 Nov 2025 23:03:56 +0000 Subject: [PATCH 10/13] ignore cover --- .../experimental/analog_experiments/analog_trajectory_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py index eaa4f887e58..44d3cda4d47 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py @@ -174,7 +174,7 @@ def plot( # Because we use relative frequencies and we do not expose the idle frequencies, # we randomly assign idle frequencies for plotting purposes only. idle_freq_map = {q: np.random.randn() * 50 * tu.MHz for q in self.qubits} - else: + else: # pragma: no cover for q in self.qubits: if q not in idle_freq_map: # Fill in missing idle freqs idle_freq_map[q] = np.random.randn() * 50 * tu.MHz From bb21594d5c16dd12d62f3037b34032238f1bfebf Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Sat, 8 Nov 2025 18:28:15 +0000 Subject: [PATCH 11/13] Adrress the comment --- .../analog_trajectory_util.py | 38 +++++++++---------- .../generic_analog_circuit.py | 24 ++++++------ 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py index 44d3cda4d47..8ea613ed591 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py @@ -89,11 +89,11 @@ def __init__( *, full_trajectory: list[FrequencyMap], qubits: list[cirq.Qid], - pairs: list[cgc.Coupler], + couplers: list[cgc.Coupler], ): self.full_trajectory = full_trajectory self.qubits = qubits - self.pairs = pairs + self.couplers = couplers @classmethod def from_sparse_trajectory( @@ -106,34 +106,34 @@ def from_sparse_trajectory( ], ], qubits: list[cirq.Qid] | None = None, - pairs: list[cgc.Coupler] | None = None, + couplers: list[cgc.Coupler] | None = None, ): """Construct AnalogTrajectory from sparse trajectory. Args: sparse_trajectory: A list of tuples, where each tuple defines a `FrequencyMap` and contains three elements: (duration, qubit_freqs, coupling_strengths). - `duration` is a tunits value, `qubit_freqs` is a dictionary mapping qubit strings + `duration` is a tunits value, `qubit_freqs` is a dictionary mapping cirq qubits to detuning frequencies, and `coupling_strengths` is a dictionary mapping - coupler to their coupling strength. This format is considered "sparse" because each + couplers to their coupling strength. This format is considered "sparse" because each tuple does not need to fully specify all qubits and coupling pairs; any missing detuning frequency or coupling strength will be set to the same value as the previous value in the list. qubits: The qubits in interest. If not provided, automatically parsed from trajectory. - pairs: The pairs in interest. If not provided, automatically parsed from trajectory. + couplers: The couplers in interest. If not provided, automatically parsed from trajectory. """ - if qubits is None or pairs is None: + if qubits is None or couplers is None: qubits_in_traj: list[cirq.Qid] = [] - pairs_in_traj: list[cgc.Coupler] = [] + couplers_in_traj: list[cgc.Coupler] = [] for _, q, p in sparse_trajectory: qubits_in_traj.extend(q.keys()) - pairs_in_traj.extend(p.keys()) + couplers_in_traj.extend(p.keys()) qubits = list(set(qubits_in_traj)) - pairs = list(set(pairs_in_traj)) + couplers = list(set(couplers_in_traj)) full_trajectory: list[FrequencyMap] = [] init_qubit_freq_dict: dict[cirq.Qid, tu.Value | None] = {q: None for q in qubits} - init_g_dict: dict[cgc.Coupler, tu.Value] = {c: 0 * tu.MHz for c in pairs} + init_g_dict: dict[cgc.Coupler, tu.Value] = {c: 0 * tu.MHz for c in couplers} full_trajectory.append(FrequencyMap(0 * tu.ns, init_qubit_freq_dict, init_g_dict, False)) for dt, qubit_freq_dict, g_dict in sparse_trajectory: @@ -145,11 +145,11 @@ def from_sparse_trajectory( } # If no g provided, set equal to previous new_g_dict: dict[cgc.Coupler, tu.Value] = { - c: g_dict.get(c, full_trajectory[-1].couplings.get(c)) for c in pairs # type: ignore[misc] + c: g_dict.get(c, full_trajectory[-1].couplings.get(c)) for c in couplers # type: ignore[misc] } full_trajectory.append(FrequencyMap(dt, new_qubit_freq_dict, new_g_dict, is_wait_step)) - return cls(full_trajectory=full_trajectory, qubits=qubits, pairs=pairs) + return cls(full_trajectory=full_trajectory, qubits=qubits, couplers=couplers) def get_full_trajectory_with_resolved_idles( self, idle_freq_map: dict[cirq.Qid, tu.Value] @@ -193,17 +193,17 @@ def plot( if axes is None: _, axes = plt.subplots(1, 2, figsize=(10, 4)) - for qubit_agent in self.qubits: + for qubit in self.qubits: axes[0].plot( times, - [step.qubit_freqs[qubit_agent][tu.GHz] for step in full_trajectory_resolved], # type: ignore[index] - label=qubit_agent, + [step.qubit_freqs[qubit][tu.GHz] for step in full_trajectory_resolved], # type: ignore[index] + label=qubit, ) - for pair_agent in self.pairs: + for coupler in self.couplers: axes[1].plot( times, - [step.couplings[pair_agent][tu.MHz] for step in full_trajectory_resolved], - label=pair_agent, + [step.couplings[coupler][tu.MHz] for step in full_trajectory_resolved], + label=coupler, ) for ax, ylabel in zip(axes, ["Qubit freq. (GHz)", "Coupling (MHz)"]): diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py index cf22bdb3545..321371f38ac 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit.py @@ -24,7 +24,7 @@ def _get_neighbor_freqs( coupler: cgc.Coupler, qubit_freq_dict: dict[cirq.Qid, su.ValueOrSymbol | None] ) -> tuple[su.ValueOrSymbol | None, su.ValueOrSymbol | None]: - """Get neighbor freqs from qubit_freq_dict given the pair.""" + """Get neighbor freqs from qubit_freq_dict given the coupler.""" sorted_pair = sorted(coupler.qubits) return (qubit_freq_dict[sorted_pair[0]], qubit_freq_dict[sorted_pair[1]]) @@ -60,12 +60,10 @@ class GenericAnalogCircuitBuilder: and couplers, using tu.Values from analog calibration whenever available. Attributes: - trajectory: AnalogTrajectory object defining the circuit - g_ramp_shaping: coupling ramps are shaped according to ramp_shape_exp if True - qubits: list of qubits in the circuit - pairs: list of couplers in the circuit - ramp_shape_exp: exponent of g_ramp (g proportional to t^ramp_shape_exp) - interpolate_coupling_cal: interpolates between calibrated coupling tu.Values if True + trajectory: AnalogTrajectory object defining the circuit. + g_ramp_shaping: coupling ramps are shaped according to ramp_shape_exp if True. + ramp_shape_exp: exponent of g_ramp (g proportional to t^ramp_shape_exp). + interpolate_coupling_cal: interpolates between calibrated coupling tu.Values if True. linear_qubit_ramp: if True, the qubit ramp is linear. if false, a cosine shaped ramp is used. """ @@ -122,23 +120,23 @@ def make_one_moment( ).on(q) ) coupler_gates = [] - for p, g_max in freq_map.couplings.items(): + for c, g_max in freq_map.couplings.items(): # Currently skipping the step if these are the same. # However, change in neighbor qubit freq could potentially change coupler amp - if g_max == prev_freq_map.couplings[p]: + if g_max == prev_freq_map.couplings[c]: continue coupler_gates.append( adg.AnalogDetuneCouplerOnly( length=freq_map.duration, w=freq_map.duration, - g_0=prev_freq_map.couplings[p], + g_0=prev_freq_map.couplings[c], g_max=g_max, g_ramp_exponent=self.ramp_shape_exp, - neighbor_qubits_freq=_get_neighbor_freqs(p, freq_map.qubit_freqs), - prev_neighbor_qubits_freq=_get_neighbor_freqs(p, prev_freq_map.qubit_freqs), + neighbor_qubits_freq=_get_neighbor_freqs(c, freq_map.qubit_freqs), + prev_neighbor_qubits_freq=_get_neighbor_freqs(c, prev_freq_map.qubit_freqs), interpolate_coupling_cal=self.interpolate_coupling_cal, - ).on(p) + ).on(c) ) return cirq.Moment(qubit_gates + coupler_gates) From 6d7bf897f9ff413a48d7922199c03f24f3931646 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Sat, 8 Nov 2025 18:30:44 +0000 Subject: [PATCH 12/13] change the coupler name --- .../analog_experiments/generic_analog_circuit_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py index 27f0ee3361e..1e42960a1fc 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/generic_analog_circuit_test.py @@ -43,7 +43,7 @@ def test_to_grid_qubit() -> None: gac._to_grid_qubit("q1") -def test_coupler_name_from_qubit_pair() -> None: +def test_get_coupler_name() -> None: pair = cg.Coupler(cirq.q(0, 0), cirq.q(0, 1)) coupler_name = gac._coupler_name(pair) assert coupler_name == "c_q0_0_q0_1" From fb178ff59c9255995a3d7831e0b257e879a54378 Mon Sep 17 00:00:00 2001 From: Bicheng Ying Date: Sat, 8 Nov 2025 18:48:40 +0000 Subject: [PATCH 13/13] fix lint --- .../experimental/analog_experiments/analog_trajectory_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py index 8ea613ed591..40770cae2b6 100644 --- a/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py +++ b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util.py @@ -120,7 +120,7 @@ def from_sparse_trajectory( detuning frequency or coupling strength will be set to the same value as the previous value in the list. qubits: The qubits in interest. If not provided, automatically parsed from trajectory. - couplers: The couplers in interest. If not provided, automatically parsed from trajectory. + couplers: The couplers in interest. If not provided, auto. parsed from trajectory. """ if qubits is None or couplers is None: qubits_in_traj: list[cirq.Qid] = []