Skip to content

Commit

Permalink
Update AQT Backend (#6441)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jbrixon authored Apr 19, 2024
1 parent 21986dd commit e1b03ef
Show file tree
Hide file tree
Showing 10 changed files with 703 additions and 214 deletions.
49 changes: 34 additions & 15 deletions cirq-aqt/cirq_aqt/aqt_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"""

import json
from enum import Enum
from typing import Any, cast, Dict, Iterable, List, Optional, Sequence, Set, Tuple, Union

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


class OperationString(Enum):
"""String representations of operations supported by AQT resources."""

MS = "MS"
"""Cirq: XXPowGate, AQT: RXX gate."""

Z = "Z"
"""Cirq: ZPowGate, AQT: RZ gate."""

R = "R"
"""Cirq: PhasedXPowGate, AQT: R gate."""

MEASURE = "Meas"
"""Measurement gate."""


def get_op_string(op_obj: cirq.Operation) -> str:
"""Find the string representation for a given gate or operation.
Args:
op_obj: Gate or operation object. Gate must be one of: XXPowGate, XPowGate, YPowGate,
op_obj: Gate or operation object. Gate must be one of: XXPowGate,
ZPowGate, PhasedXPowGate, or MeasurementGate.
Returns:
Expand All @@ -50,20 +67,16 @@ def get_op_string(op_obj: cirq.Operation) -> str:
ValueError: If the gate is not one of the supported gates.
"""
if isinstance(op_obj.gate, cirq.XXPowGate):
op_str = 'MS'
elif isinstance(op_obj.gate, cirq.XPowGate):
op_str = 'X'
elif isinstance(op_obj.gate, cirq.YPowGate):
op_str = 'Y'
op_str = OperationString.MS.value
elif isinstance(op_obj.gate, cirq.ZPowGate):
op_str = 'Z'
op_str = OperationString.Z.value
elif isinstance(op_obj.gate, cirq.PhasedXPowGate):
op_str = 'R'
op_str = OperationString.R.value
elif isinstance(op_obj.gate, cirq.MeasurementGate):
op_str = 'Meas'
op_str = OperationString.MEASURE.value
else:
raise ValueError(f'Got unknown gate on operation: {op_obj}.')
return op_str
return str(op_str)


class AQTNoiseModel(cirq.NoiseModel):
Expand Down Expand Up @@ -97,6 +110,7 @@ def noisy_moment(
for qubit in op.qubits:
noise_list.append(noise_op.on(qubit))
noise_list += self.get_crosstalk_operation(op, system_qubits)

return list(moment) + noise_list

def get_crosstalk_operation(
Expand All @@ -122,16 +136,18 @@ def get_crosstalk_operation(
for neigh_idx in neighbors:
if neigh_idx >= 0 and neigh_idx < num_qubits:
xtlk_arr[neigh_idx] = self.noise_op_dict['crosstalk']

for idx in idx_list:
xtlk_arr[idx] = 0
xtlk_op_list = []
op_str = get_op_string(operation)
gate = cast(cirq.EigenGate, gate_dict[op_str])

if len(operation.qubits) == 1:
for idx in xtlk_arr.nonzero()[0]:
exponent = operation.gate.exponent # type:ignore
exponent = exponent * xtlk_arr[idx]
xtlk_op = gate.on(system_qubits[idx]) ** exponent
xtlk_op = operation.gate.on(system_qubits[idx]) ** exponent # type:ignore
xtlk_op_list.append(xtlk_op)
elif len(operation.qubits) == 2:
for op_qubit in operation.qubits:
Expand Down Expand Up @@ -216,10 +232,14 @@ def simulate_samples(self, repetitions: int) -> cirq.Result:
noise_model = cirq.NO_NOISE
else:
noise_model = AQTNoiseModel()

if self.circuit == cirq.Circuit():
raise RuntimeError('Simulate called without a valid circuit.')

sim = cirq.DensityMatrixSimulator(noise=noise_model)

result = sim.run(self.circuit, repetitions=repetitions)

return result


Expand Down Expand Up @@ -342,10 +362,9 @@ def get_aqt_device(num_qubits: int) -> Tuple[AQTDevice, List[cirq.LineQubit]]:
def get_default_noise_dict() -> Dict[str, Any]:
"""Returns the current noise parameters"""
default_noise_dict = {
'X': cirq.depolarize(1e-3),
'Y': cirq.depolarize(1e-3),
'Z': cirq.depolarize(1e-3),
'MS': cirq.depolarize(1e-2),
OperationString.R.value: cirq.depolarize(1e-3),
OperationString.Z.value: cirq.depolarize(0),
OperationString.MS.value: cirq.depolarize(1e-2),
'crosstalk': 0.03,
}
return default_noise_dict
Expand Down
2 changes: 0 additions & 2 deletions cirq-aqt/cirq_aqt/aqt_device_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ def __init__(
self._gate_durations = {
cirq.GateFamily(cirq.MeasurementGate): self._measurement_duration,
cirq.GateFamily(cirq.XXPowGate): self._twoq_gates_duration,
cirq.GateFamily(cirq.XPowGate): self._oneq_gates_duration,
cirq.GateFamily(cirq.YPowGate): self._oneq_gates_duration,
cirq.GateFamily(cirq.ZPowGate): self._oneq_gates_duration,
cirq.GateFamily(cirq.PhasedXPowGate): self._oneq_gates_duration,
}
Expand Down
2 changes: 1 addition & 1 deletion cirq-aqt/cirq_aqt/aqt_device_metadata_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def test_aqtdevice_metadata(metadata, qubits):
assert len(edges) == 10
assert all(q0 != q1 for q0, q1 in edges)
assert AQTTargetGateset() == metadata.gateset
assert len(metadata.gate_durations) == 6
assert len(metadata.gate_durations) == 4


def test_aqtdevice_duration_of(metadata, qubits):
Expand Down
Loading

0 comments on commit e1b03ef

Please sign in to comment.