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..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 @@ -27,6 +27,8 @@ if TYPE_CHECKING: from matplotlib.axes import Axes + from cirq_google.ops import coupler as cgc + @attrs.mutable class FrequencyMap: @@ -40,8 +42,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[cgc.Coupler, su.ValueOrSymbol] is_wait_step: bool def _is_parameterized_(self) -> bool: @@ -86,12 +88,12 @@ def __init__( self, *, full_trajectory: list[FrequencyMap], - qubits: list[str], - pairs: list[tuple[str, str]], + qubits: list[cirq.Qid], + couplers: list[cgc.Coupler], ): self.full_trajectory = full_trajectory self.qubits = qubits - self.pairs = pairs + self.couplers = couplers @classmethod def from_sparse_trajectory( @@ -99,39 +101,39 @@ 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[cgc.Coupler, su.ValueOrSymbol], ], ], - qubits: list[str] | None = None, - pairs: list[tuple[str, str]] | None = None, + qubits: list[cirq.Qid] | 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 - to detuning frequencies, and `coupling_strengths` is a dictionary mapping qubit - pairs to their coupling strength. This format is considered "sparse" because each + `duration` is a tunits value, `qubit_freqs` is a dictionary mapping cirq qubits + to detuning frequencies, and `coupling_strengths` is a dictionary mapping + 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, auto. parsed from trajectory. """ - if qubits is None or pairs is None: - qubits_in_traj: list[str] = [] - pairs_in_traj: list[tuple[str, str]] = [] + if qubits is None or couplers is None: + qubits_in_traj: list[cirq.Qid] = [] + 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[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[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: @@ -142,15 +144,15 @@ 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] = { - 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] = { + 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[str, tu.Value] + self, idle_freq_map: dict[cirq.Qid, tu.Value] ) -> list[FrequencyMap]: """Insert idle frequencies instead of None in trajectory.""" @@ -164,13 +166,19 @@ def get_full_trajectory_with_resolved_idles( def plot( self, - idle_freq_map: dict[str, tu.Value] | None = None, - default_idle_freq: tu.Value = 6.5 * tu.GHz, + idle_freq_map: dict[cirq.Qid, tu.Value] | None = None, 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: # 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 + full_trajectory_resolved = cirq.resolve_parameters( self.get_full_trajectory_with_resolved_idles(idle_freq_map), resolver ) @@ -185,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/analog_trajectory_util_test.py b/cirq-google/cirq_google/experimental/analog_experiments/analog_trajectory_util_test.py index d55afd19de0..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 @@ -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 @@ -24,8 +25,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")}, + { + 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, ) @@ -41,59 +45,68 @@ 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}, + { + 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[str, tu.Value | None], dict[tuple[str, str], tu.Value]] +FreqMapType = tuple[tu.Value, dict[cirq.Qid, tu.Value | None], dict[cg.Coupler, 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}, + { + 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, - {"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}, + {coupler1: 0 * tu.MHz, coupler2: 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}, + {coupler1: 0 * tu.MHz, coupler2: 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}, + {coupler1: 0 * tu.MHz, coupler2: 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}, + {coupler1: 0 * tu.MHz, coupler2: 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}, + {coupler1: 5 * tu.MHz, coupler2: 8 * tu.MHz}, False, ) @@ -102,45 +115,47 @@ 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} ) + 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, - {"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}, + {coupler1: 0 * tu.MHz, coupler2: 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}, + {coupler1: 0 * tu.MHz, coupler2: 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}, + {coupler1: 0 * tu.MHz, coupler2: 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}, + {coupler1: 0 * tu.MHz, coupler2: 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}, + {coupler1: 5 * tu.MHz, coupler2: 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 +163,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")}, + {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]) 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..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 @@ -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[str, str], qubit_freq_dict: dict[str, 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, key=_to_grid_qubit) + """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]]) @@ -37,19 +37,19 @@ 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}" # type: ignore[attr-defined] def _get_neighbor_coupler_freqs( - qubit_name: str, coupler_g_dict: dict[tuple[str, str], su.ValueOrSymbol] + qubit: cirq.Qid, coupler_g_dict: dict[cgc.Coupler, 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 + _coupler_name(coupler): g + for coupler, g in coupler_g_dict.items() + if qubit in coupler.qubits } @@ -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. """ @@ -90,7 +88,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,26 +117,26 @@ 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(): + 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(*sorted([_to_grid_qubit(p[0]), _to_grid_qubit(p[1])])) + ).on(c) ) 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..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 @@ -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, @@ -25,9 +26,12 @@ 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} - neighbor_freqs = gac._get_neighbor_freqs(pair, qubit_freq_dict) + q0 = cirq.GridQubit(0, 0) + q1 = cirq.GridQubit(0, 1) + 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) # type: ignore[arg-type] assert neighbor_freqs == (5 * tu.GHz, sympy.Symbol("f_q")) @@ -39,31 +43,36 @@ def test_to_grid_qubit() -> None: gac._to_grid_qubit("q1") -def test_coupler_name_from_qubit_pair() -> None: - pair = ("q0_0", "q0_1") - coupler_name = gac._coupler_name_from_qubit_pair(pair) +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" - 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" 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 = cg.Coupler(q0, q1) + pair2 = cg.Coupler(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, ) @@ -111,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, @@ -121,21 +130,24 @@ 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: + 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}, + {q0: 8 * tu.GHz, q1: sympy.Symbol('f')}, + {cg.Coupler(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) @@ -146,7 +158,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)