Skip to content

Commit 2faba7a

Browse files
CynocracytanujkhattarCirqBot
authored
Update Cirq decomposition to use RZ, RX, CNOT only (#4824)
* Update Cirq decomposition to use RZ, RX, CNOT only * Validate that decomposed gates match expected gateset Co-authored-by: Tanuj Khattar <[email protected]> Co-authored-by: Cirq Bot <[email protected]>
1 parent 497cd3d commit 2faba7a

File tree

2 files changed

+20
-17
lines changed

2 files changed

+20
-17
lines changed

cirq-ionq/cirq_ionq/ionq_devices.py

+15-17
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515

1616
from typing import AbstractSet, Sequence, Union
1717

18-
import numpy as np
19-
2018
import cirq
2119

2220

@@ -103,19 +101,19 @@ def _decompose_single_qubit(self, operation: cirq.Operation) -> cirq.OP_TREE:
103101
yield gate(qubit)
104102

105103
def _decompose_two_qubit(self, operation: cirq.Operation) -> cirq.OP_TREE:
106-
"""Decomposes a two qubit gate into XXPow, YYPow, and ZZPow plus single qubit gates."""
104+
"""Decomposes a two qubit unitary operation into ZPOW, XPOW, and CNOT."""
107105
mat = cirq.unitary(operation)
108-
kak = cirq.kak_decomposition(mat, check_preconditions=False)
109-
110-
for qubit, mat in zip(operation.qubits, kak.single_qubit_operations_before):
111-
gates = cirq.single_qubit_matrix_to_gates(mat, self.atol)
112-
for gate in gates:
113-
yield gate(qubit)
114-
115-
two_qubit_gates = [cirq.XX, cirq.YY, cirq.ZZ]
116-
for two_qubit_gate, coefficient in zip(two_qubit_gates, kak.interaction_coefficients):
117-
yield (two_qubit_gate ** (-coefficient * 2 / np.pi))(*operation.qubits)
118-
119-
for qubit, mat in zip(operation.qubits, kak.single_qubit_operations_after):
120-
for gate in cirq.single_qubit_matrix_to_gates(mat, self.atol):
121-
yield gate(qubit)
106+
q0, q1 = operation.qubits
107+
naive = cirq.two_qubit_matrix_to_operations(q0, q1, mat, allow_partial_czs=False)
108+
temp = cirq.map_operations_and_unroll(
109+
cirq.Circuit(naive),
110+
lambda op, _: [cirq.H(op.qubits[1]), cirq.CNOT(*op.qubits), cirq.H(op.qubits[1])]
111+
if type(op.gate) == cirq.CZPowGate
112+
else op,
113+
)
114+
cirq.merge_single_qubit_gates_into_phased_x_z(temp)
115+
# A final pass breaks up PhasedXPow into Rz, Rx.
116+
yield cirq.map_operations_and_unroll(
117+
temp,
118+
lambda op, _: cirq.decompose_once(op) if type(op.gate) == cirq.PhasedXPowGate else op,
119+
).all_operations()

cirq-ionq/cirq_ionq/ionq_devices_test.py

+5
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ def test_decompose_leaves_supported_alone(gate):
129129
assert device.decompose_operation(operation) == operation
130130

131131

132+
VALID_DECOMPOSED_GATES = cirq.Gateset(cirq.XPowGate, cirq.ZPowGate, cirq.CNOT)
133+
134+
132135
def test_decompose_single_qubit_matrix_gate():
133136
q = cirq.LineQubit(0)
134137
device = ionq.IonQAPIDevice(qubits=[q])
@@ -139,6 +142,7 @@ def test_decompose_single_qubit_matrix_gate():
139142
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
140143
circuit, decomposed_circuit, atol=1e-8
141144
)
145+
assert VALID_DECOMPOSED_GATES.validate(decomposed_circuit)
142146

143147

144148
def test_decompose_two_qubit_matrix_gate():
@@ -151,6 +155,7 @@ def test_decompose_two_qubit_matrix_gate():
151155
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
152156
circuit, decomposed_circuit, atol=1e-8
153157
)
158+
assert VALID_DECOMPOSED_GATES.validate(decomposed_circuit)
154159

155160

156161
def test_decompose_unsupported_gate():

0 commit comments

Comments
 (0)