Skip to content

Commit e1b03ef

Browse files
authored
Update AQT Backend (#6441)
Adjusted the AQT backend so that it works with the new AQT Arnica API. We also updated the gateset to reflect what we support. As we made an extension to the API, we were able to add a feature that lists the workspaces and resources that are available to a user. We also updated tests and documentation accordingly. Fixes #6379
1 parent 21986dd commit e1b03ef

10 files changed

+703
-214
lines changed

cirq-aqt/cirq_aqt/aqt_device.py

+34-15
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"""
2626

2727
import json
28+
from enum import Enum
2829
from typing import Any, cast, Dict, Iterable, List, Optional, Sequence, Set, Tuple, Union
2930

3031
import networkx as nx
@@ -36,11 +37,27 @@
3637
gate_dict = {'X': cirq.X, 'Y': cirq.Y, 'Z': cirq.Z, 'MS': cirq.XX, 'R': cirq.PhasedXPowGate}
3738

3839

40+
class OperationString(Enum):
41+
"""String representations of operations supported by AQT resources."""
42+
43+
MS = "MS"
44+
"""Cirq: XXPowGate, AQT: RXX gate."""
45+
46+
Z = "Z"
47+
"""Cirq: ZPowGate, AQT: RZ gate."""
48+
49+
R = "R"
50+
"""Cirq: PhasedXPowGate, AQT: R gate."""
51+
52+
MEASURE = "Meas"
53+
"""Measurement gate."""
54+
55+
3956
def get_op_string(op_obj: cirq.Operation) -> str:
4057
"""Find the string representation for a given gate or operation.
4158
4259
Args:
43-
op_obj: Gate or operation object. Gate must be one of: XXPowGate, XPowGate, YPowGate,
60+
op_obj: Gate or operation object. Gate must be one of: XXPowGate,
4461
ZPowGate, PhasedXPowGate, or MeasurementGate.
4562
4663
Returns:
@@ -50,20 +67,16 @@ def get_op_string(op_obj: cirq.Operation) -> str:
5067
ValueError: If the gate is not one of the supported gates.
5168
"""
5269
if isinstance(op_obj.gate, cirq.XXPowGate):
53-
op_str = 'MS'
54-
elif isinstance(op_obj.gate, cirq.XPowGate):
55-
op_str = 'X'
56-
elif isinstance(op_obj.gate, cirq.YPowGate):
57-
op_str = 'Y'
70+
op_str = OperationString.MS.value
5871
elif isinstance(op_obj.gate, cirq.ZPowGate):
59-
op_str = 'Z'
72+
op_str = OperationString.Z.value
6073
elif isinstance(op_obj.gate, cirq.PhasedXPowGate):
61-
op_str = 'R'
74+
op_str = OperationString.R.value
6275
elif isinstance(op_obj.gate, cirq.MeasurementGate):
63-
op_str = 'Meas'
76+
op_str = OperationString.MEASURE.value
6477
else:
6578
raise ValueError(f'Got unknown gate on operation: {op_obj}.')
66-
return op_str
79+
return str(op_str)
6780

6881

6982
class AQTNoiseModel(cirq.NoiseModel):
@@ -97,6 +110,7 @@ def noisy_moment(
97110
for qubit in op.qubits:
98111
noise_list.append(noise_op.on(qubit))
99112
noise_list += self.get_crosstalk_operation(op, system_qubits)
113+
100114
return list(moment) + noise_list
101115

102116
def get_crosstalk_operation(
@@ -122,16 +136,18 @@ def get_crosstalk_operation(
122136
for neigh_idx in neighbors:
123137
if neigh_idx >= 0 and neigh_idx < num_qubits:
124138
xtlk_arr[neigh_idx] = self.noise_op_dict['crosstalk']
139+
125140
for idx in idx_list:
126141
xtlk_arr[idx] = 0
127142
xtlk_op_list = []
128143
op_str = get_op_string(operation)
129144
gate = cast(cirq.EigenGate, gate_dict[op_str])
145+
130146
if len(operation.qubits) == 1:
131147
for idx in xtlk_arr.nonzero()[0]:
132148
exponent = operation.gate.exponent # type:ignore
133149
exponent = exponent * xtlk_arr[idx]
134-
xtlk_op = gate.on(system_qubits[idx]) ** exponent
150+
xtlk_op = operation.gate.on(system_qubits[idx]) ** exponent # type:ignore
135151
xtlk_op_list.append(xtlk_op)
136152
elif len(operation.qubits) == 2:
137153
for op_qubit in operation.qubits:
@@ -216,10 +232,14 @@ def simulate_samples(self, repetitions: int) -> cirq.Result:
216232
noise_model = cirq.NO_NOISE
217233
else:
218234
noise_model = AQTNoiseModel()
235+
219236
if self.circuit == cirq.Circuit():
220237
raise RuntimeError('Simulate called without a valid circuit.')
238+
221239
sim = cirq.DensityMatrixSimulator(noise=noise_model)
240+
222241
result = sim.run(self.circuit, repetitions=repetitions)
242+
223243
return result
224244

225245

@@ -342,10 +362,9 @@ def get_aqt_device(num_qubits: int) -> Tuple[AQTDevice, List[cirq.LineQubit]]:
342362
def get_default_noise_dict() -> Dict[str, Any]:
343363
"""Returns the current noise parameters"""
344364
default_noise_dict = {
345-
'X': cirq.depolarize(1e-3),
346-
'Y': cirq.depolarize(1e-3),
347-
'Z': cirq.depolarize(1e-3),
348-
'MS': cirq.depolarize(1e-2),
365+
OperationString.R.value: cirq.depolarize(1e-3),
366+
OperationString.Z.value: cirq.depolarize(0),
367+
OperationString.MS.value: cirq.depolarize(1e-2),
349368
'crosstalk': 0.03,
350369
}
351370
return default_noise_dict

cirq-aqt/cirq_aqt/aqt_device_metadata.py

-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ def __init__(
5353
self._gate_durations = {
5454
cirq.GateFamily(cirq.MeasurementGate): self._measurement_duration,
5555
cirq.GateFamily(cirq.XXPowGate): self._twoq_gates_duration,
56-
cirq.GateFamily(cirq.XPowGate): self._oneq_gates_duration,
57-
cirq.GateFamily(cirq.YPowGate): self._oneq_gates_duration,
5856
cirq.GateFamily(cirq.ZPowGate): self._oneq_gates_duration,
5957
cirq.GateFamily(cirq.PhasedXPowGate): self._oneq_gates_duration,
6058
}

cirq-aqt/cirq_aqt/aqt_device_metadata_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def test_aqtdevice_metadata(metadata, qubits):
4545
assert len(edges) == 10
4646
assert all(q0 != q1 for q0, q1 in edges)
4747
assert AQTTargetGateset() == metadata.gateset
48-
assert len(metadata.gate_durations) == 6
48+
assert len(metadata.gate_durations) == 4
4949

5050

5151
def test_aqtdevice_duration_of(metadata, qubits):

0 commit comments

Comments
 (0)