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

Add decomposition for CCZ gate and IonQTargetGateset when qubits are all-to-all connected #6095

Merged
merged 21 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
aa8077f
Add all-to-all decomposition for CCZ gate
yinghui-hu May 16, 2023
d5f8c98
Fix format check and type check
yinghui-hu May 16, 2023
9555f31
Revert type check change
yinghui-hu May 16, 2023
219c710
Ignore type check for `global_phase`
yinghui-hu May 16, 2023
e31bc96
Expect test_custom_value_not_implemented to pass
yinghui-hu May 16, 2023
1d85158
Sync test_custom_value_not_implemented
yinghui-hu May 16, 2023
a89bf4c
Merge branch 'quantumlib:master' into all_connectivity_decompose
yinghui-hu May 16, 2023
397b9a7
Merge branch 'quantumlib:master' into all_connectivity_decompose
yinghui-hu May 23, 2023
e12eda1
IonQTargetGateset._decompose_multi_qubit_operation
yinghui-hu May 23, 2023
79f9c3a
Fix format and type check
yinghui-hu May 23, 2023
cf3c640
Fix type for input `qubits`
yinghui-hu May 23, 2023
eea47ce
Merge branch 'quantumlib:master' into all_connectivity_decompose
yinghui-hu Jun 2, 2023
b4ca8d7
Add test for ValueError
yinghui-hu Jun 2, 2023
f3bf72d
Merge branch 'master' into all_connectivity_decompose
yinghui-hu Jul 19, 2023
8c5afe7
Resolve comments
yinghui-hu Jul 19, 2023
4d835d7
Add a new line after summary line and before description
yinghui-hu Jul 19, 2023
6a1f140
Fix format, type and lint
yinghui-hu Jul 19, 2023
02c49a0
Ignore type check
yinghui-hu Jul 19, 2023
d31fc77
Merge branch 'master' into all_connectivity_decompose
yinghui-hu Jul 21, 2023
210f720
Merge branch 'master' into all_connectivity_decompose
yinghui-hu Jul 27, 2023
ca5b113
Merge branch 'master' into all_connectivity_decompose
yinghui-hu Aug 6, 2023
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
2 changes: 1 addition & 1 deletion cirq-ionq/cirq_ionq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

from cirq_ionq.ionq_devices import IonQAPIDevice, decompose_to_device

from cirq_ionq.ionq_gateset import IonQTargetGateset
from cirq_ionq.ionq_gateset import IonQTargetGateset, decompose_all_to_all_connect_ccz_gate

from cirq_ionq.ionq_exceptions import (
IonQException,
Expand Down
64 changes: 62 additions & 2 deletions cirq-ionq/cirq_ionq/ionq_gateset.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from typing import Any
from typing import Dict
from typing import List
from typing import Tuple

import cirq

Expand Down Expand Up @@ -78,12 +79,21 @@ def _decompose_two_qubit_operation(self, op: cirq.Operation, _) -> cirq.OP_TREE:
temp, k=1, rewriter=lambda op: self._decompose_single_qubit_operation(op, -1)
).all_operations()

def _decompose_multi_qubit_operation(self, op: cirq.Operation, _) -> cirq.OP_TREE:
if isinstance(op.gate, cirq.CCZPowGate):
return decompose_all_to_all_connect_ccz_gate(op.gate, op.qubits)
return NotImplemented

@property
def preprocess_transformers(self) -> List['cirq.TRANSFORMER']:
"""List of transformers which should be run before decomposing individual operations."""
"""List of transformers which should be run before decomposing individual operations.

Decompose to three qubit gates because three qubit gates have different decomposition
for all-to-all connectivity between qubits.
"""
return [
cirq.create_transformer_with_kwargs(
cirq.expand_composite, no_decomp=lambda op: cirq.num_qubits(op) <= self.num_qubits
cirq.expand_composite, no_decomp=lambda op: cirq.num_qubits(op) <= 3
)
]

Expand All @@ -104,3 +114,53 @@ def _json_dict_(self) -> Dict[str, Any]:
@classmethod
def _from_json_dict_(cls, atol, **kwargs):
return cls(atol=atol)


def decompose_all_to_all_connect_ccz_gate(
ccz_gate: 'cirq.CCZPowGate', qubits: Tuple['cirq.Qid', ...]
) -> 'cirq.OP_TREE':
"""Decomposition of all-to-all connected qubits are different from line qubits or grid qubits.

For example, for qubits in the same ion trap, the decomposition of CCZ gate will be:

0: ──────────────@──────────────────@───@───p──────@───
│ │ │ │
1: ───@──────────┼───────@───p──────┼───X───p^-1───X───
│ │ │ │
2: ───X───p^-1───X───p───X───p^-1───X───p──────────────

where p = T**ccz_gate._exponent
"""
if len(qubits) != 3:
raise ValueError(f'Expect 3 qubits for CCZ gate, got {len(qubits)} qubits.')

a, b, c = qubits

p = cirq.T**ccz_gate._exponent
global_phase = 1j ** (2 * ccz_gate.global_shift * ccz_gate._exponent)
global_phase = (
complex(global_phase)
if cirq.is_parameterized(global_phase) and global_phase.is_complex # type: ignore
else global_phase
)
global_phase_operation = (
[cirq.global_phase_operation(global_phase)]
if cirq.is_parameterized(global_phase) or abs(global_phase - 1.0) > 0
else []
)

return global_phase_operation + [
cirq.CNOT(b, c),
p(c) ** -1,
cirq.CNOT(a, c),
p(c),
cirq.CNOT(b, c),
p(c) ** -1,
cirq.CNOT(a, c),
p(b),
p(c),
cirq.CNOT(a, b),
p(a),
p(b) ** -1,
cirq.CNOT(a, b),
]
43 changes: 43 additions & 0 deletions cirq-ionq/cirq_ionq/ionq_gateset_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,46 @@ def test_decompose_parameterized_operation():
atol=1e-6,
)
assert ionq_target_gateset.validate(decomposed_circuit)


def test_decomposition_all_to_all_connectivity():
"""This function only accepts 3 qubits as input"""
with pytest.raises(ValueError):
decompose_result = ionq.decompose_all_to_all_connect_ccz_gate(
cirq.CCZ, cirq.LineQubit.range(4)
)

decompose_result = ionq.decompose_all_to_all_connect_ccz_gate(cirq.CCZ, cirq.LineQubit.range(3))

cirq.testing.assert_has_diagram(
cirq.Circuit(decompose_result),
"""
0: ──────────────@──────────────────@───@───T──────@───
│ │ │ │
1: ───@──────────┼───────@───T──────┼───X───T^-1───X───
│ │ │ │
2: ───X───T^-1───X───T───X───T^-1───X───T──────────────
""",
)


def test_decompose_toffoli_gate():
"""Decompose result should reflect all-to-all connectivity"""
circuit = cirq.Circuit(cirq.TOFFOLI(*cirq.LineQubit.range(3)))
decomposed_circuit = cirq.optimize_for_target_gateset(
circuit, gateset=ionq_target_gateset, ignore_failures=False
)
cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
circuit, decomposed_circuit, atol=1e-8
)
assert ionq_target_gateset.validate(decomposed_circuit)
cirq.testing.assert_has_diagram(
decomposed_circuit,
"""
0: ──────────────────@──────────────────@───@───T──────@───
│ │ │ │
1: ───────@──────────┼───────@───T──────┼───X───T^-1───X───
│ │ │ │
2: ───H───X───T^-1───X───T───X───T^-1───X───T───H──────────
""",
)