Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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.

Expand All @@ -121,17 +121,17 @@ 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())
qubits = list(set(qubits_in_traj))
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:
Expand All @@ -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]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)

Expand All @@ -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]

Expand All @@ -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,
)

Expand All @@ -102,53 +107,57 @@ 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):
analog_traj.plot()


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})
Original file line number Diff line number Diff line change
Expand Up @@ -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]])


Expand All @@ -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:
Expand Down Expand Up @@ -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)
)
Expand Down Expand Up @@ -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():
Expand All @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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"))

Expand Down Expand Up @@ -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,
)

Expand All @@ -78,26 +86,26 @@ 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(
length=3 * tu.ns,
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(
length=3 * tu.ns,
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))

Expand Down Expand Up @@ -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)
Expand Down
Loading