Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding custom gates for EeroQ hardware #1003

Merged
merged 23 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cirq-superstaq/cirq_superstaq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
CR,
CZ3,
CZ3_INV,
DD,
SWAP3,
ZX,
AceCR,
AceCRMinusPlus,
AceCRPlusMinus,
Barrier,
BSwapPowGate,
DDPowGate,
ParallelGates,
ParallelRGate,
QubitSubspaceGate,
Expand Down Expand Up @@ -74,6 +76,8 @@
"CR",
"CZ3",
"CZ3_INV",
"DD",
"DDPowGate",
"Job",
"measured_qubit_indices",
"ParallelGates",
Expand Down
4 changes: 4 additions & 0 deletions cirq-superstaq/cirq_superstaq/ops/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
AQTICCX,
AQTITOFFOLI,
CR,
DD,
ZX,
AceCR,
AceCRMinusPlus,
AceCRPlusMinus,
Barrier,
DDPowGate,
ParallelGates,
ParallelRGate,
RGate,
Expand Down Expand Up @@ -51,6 +53,8 @@
"CR",
"CZ3",
"CZ3_INV",
"DD",
"DDPowGate",
"ParallelGates",
"ParallelRGate",
"QubitSubspaceGate",
Expand Down
61 changes: 61 additions & 0 deletions cirq-superstaq/cirq_superstaq/ops/qubit_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,66 @@ def _json_dict_(self) -> dict[str, Any]:
return cirq.obj_to_dict_helper(self, ["rz_rads"])


class DDPowGate(cirq.EigenGate):
r"""The Dipole-Dipole gate for EeroQ hardware"""

def _eigen_components(self) -> list[tuple[float, npt.NDArray[np.float_]]]:
return [
(
-0.5,
np.array([[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]),
),
(
1.0,
np.array([[0, 0, 0, 0], [0, 0.5, 0.5, 0], [0, 0.5, 0.5, 0], [0, 0, 0, 0]]),
),
(
0.0,
np.array([[0, 0, 0, 0], [0, 0.5, -0.5, 0], [0, -0.5, 0.5, 0], [0, 0, 0, 0]]),
),
]

def _num_qubits_(self) -> int:
return 2

def _decompose_(self, qubits: tuple[cirq.LineQubit, cirq.LineQubit]) -> list[cirq.Operation]:
return [
cirq.ZZPowGate(exponent=self.exponent, global_shift=self.global_shift - 0.5).on(
*qubits
),
cirq.ISwapPowGate(exponent=self.exponent).on(*qubits),
]

def _has_stabilizer_effect_(self) -> bool | None:
if cirq.is_parameterized(self):
return None

return (2 * self.exponent) % 1 == 0

def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo:
return cirq.CircuitDiagramInfo(
wire_symbols=("DD", "DD"), exponent=self._diagram_exponent(args)
)

def __str__(self) -> str:
if self.exponent == 1:
return "DD"
return f"DD**{self._exponent!r}"
pgoiporia marked this conversation as resolved.
Show resolved Hide resolved

def __repr__(self) -> str:
if self._global_shift == 0:
if self._exponent == 1:
return "css.DD"
return f"(css.DD**{cirq._compat.proper_repr(self._exponent)})"
return (
f"css.DDPowGate(exponent={cirq._compat.proper_repr(self._exponent)},"
f" global_shift={self._global_shift!r})"
)


DD = DDPowGate()


def custom_resolver(cirq_type: str) -> type[cirq.Gate] | None:
"""Tells `cirq.read_json` how to deserialize `cirq-superstaq`'s custom gates.

Expand All @@ -1003,5 +1063,6 @@ def custom_resolver(cirq_type: str) -> type[cirq.Gate] | None:
"IXGate": IXGate,
"ParallelRGate": ParallelRGate,
"StrippedCZGate": StrippedCZGate,
"DDPowGate": DDPowGate,
}
return type_to_gate_map.get(cirq_type)
56 changes: 56 additions & 0 deletions cirq-superstaq/cirq_superstaq/ops/qubit_gates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1102,6 +1102,61 @@ def test_itoffoli() -> None:
)


def test_dd_protocols() -> None:
with mock.patch("cirq.testing.consistent_protocols.assert_qasm_is_consistent_with_unitary"):
cirq.testing.assert_eigengate_implements_consistent_protocols(
css.DDPowGate,
setup_code="import cirq_superstaq as css; import sympy",
ignoring_global_phase=True,
)
pgoiporia marked this conversation as resolved.
Show resolved Hide resolved

assert cirq.has_stabilizer_effect(css.DD)
assert cirq.has_stabilizer_effect(css.DD**1.5)
assert not cirq.has_stabilizer_effect(css.DD**1.3)
assert not cirq.has_stabilizer_effect(css.DD ** sympy.var("x"))


def test_dd_matrix() -> None:
np.testing.assert_allclose(
cirq.unitary(css.DD),
np.array([[-1j, 0, 0, 0], [0, 0, -1, 0], [0, -1, 0, 0], [0, 0, 0, -1j]]),
)


def test_dd_str() -> None:
assert str(css.DD) == "DD"
assert str(css.DD**0.5) == "DD**0.5"
assert str(css.DDPowGate(global_shift=0.1)) == "DD"


def test_dd_repr() -> None:
assert repr(css.DD) == "css.DD"
assert repr(css.DDPowGate(exponent=0.5)) == "(css.DD**0.5)"
assert (
repr(css.DDPowGate(exponent=0.5, global_shift=0.123))
== "css.DDPowGate(exponent=0.5, global_shift=0.123)"
)

cirq.testing.assert_equivalent_repr(css.DDPowGate(), setup_code="import cirq_superstaq as css")


def test_dd_circuit() -> None:
a, b = cirq.LineQubit.range(2)

op = css.DDPowGate()(a, b)

cirq.testing.assert_has_diagram(
cirq.Circuit(op),
textwrap.dedent(
"""
0: ───DD───
1: ───DD───
"""
),
)


def test_custom_resolver() -> None:
circuit = cirq.Circuit()
qubits = cirq.LineQubit.range(4)
Expand All @@ -1121,6 +1176,7 @@ def test_custom_resolver() -> None:
circuit += css.ops.qubit_gates.ICCX(qubits[0], qubits[1], qubits[2])
circuit += css.ops.qubit_gates.IX(qubits[0])
circuit += css.StrippedCZGate(0.123).on(qubits[0], qubits[1])
circuit += css.DDPowGate().on(qubits[0], qubits[1])

json_text = cirq.to_json(circuit)
resolvers = [*css.SUPERSTAQ_RESOLVERS, *cirq.DEFAULT_RESOLVERS]
Expand Down