Skip to content

Commit acbf204

Browse files
dstrain115rht
authored andcommitted
Remove deprecated netural_atoms classes (quantumlib#5695)
- Removes NeutralAtomDevice and ConvertToNeutralAtomGates
1 parent 689dc69 commit acbf204

File tree

7 files changed

+34
-752
lines changed

7 files changed

+34
-752
lines changed

cirq-core/cirq/__init__.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -654,12 +654,7 @@
654654
)
655655

656656
from cirq.ion import ConvertToIonGates, IonDevice
657-
from cirq.neutral_atoms import (
658-
ConvertToNeutralAtomGates,
659-
is_native_neutral_atom_gate,
660-
is_native_neutral_atom_op,
661-
NeutralAtomDevice,
662-
)
657+
from cirq.neutral_atoms import is_native_neutral_atom_gate, is_native_neutral_atom_op
663658

664659
from cirq.vis import (
665660
Heatmap,

cirq-core/cirq/neutral_atoms/__init__.py

-3
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@
1414

1515
"""Neutral atom devices and gates."""
1616

17-
from cirq.neutral_atoms.neutral_atom_devices import NeutralAtomDevice
18-
1917
from cirq.neutral_atoms.convert_to_neutral_atom_gates import (
20-
ConvertToNeutralAtomGates,
2118
is_native_neutral_atom_gate,
2219
is_native_neutral_atom_op,
2320
)

cirq-core/cirq/neutral_atoms/convert_to_neutral_atom_gates.py

+1-79
Original file line numberDiff line numberDiff line change
@@ -11,88 +11,10 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
from typing import List, Optional, TYPE_CHECKING
1514

16-
from cirq import ops, protocols, transformers
17-
from cirq._compat import deprecated_class
18-
from cirq.circuits.optimization_pass import PointOptimizationSummary, PointOptimizer
15+
from cirq import ops
1916
from cirq.neutral_atoms import neutral_atom_devices
2017

21-
if TYPE_CHECKING:
22-
import cirq
23-
24-
25-
@deprecated_class(
26-
deadline='v0.16',
27-
fix='Use cirq.optimize_for_target_gateset(circuit, gateset=cirq_pasqal.PasqalGateset()).',
28-
)
29-
class ConvertToNeutralAtomGates(PointOptimizer):
30-
"""Attempts to convert gates into native Atom gates.
31-
32-
First, checks if the given operation is already a native neutral atom
33-
operation.
34-
35-
Second, checks if the operation has a known unitary. If so, and the gate
36-
is a 1-qubit or 2-qubit gate, then performs circuit synthesis of the
37-
operation. The 2-qubit gates are decomposed using CZ gates because
38-
CZ gates are the highest fidelity 2-qubit gates for neutral atoms.
39-
40-
Third, attempts to `cirq.decompose` to the operation.
41-
42-
Fourth, if ignore_failures is set, gives up and returns the gate unchanged.
43-
Otherwise raises a TypeError.
44-
"""
45-
46-
def __init__(self, ignore_failures=False) -> None:
47-
"""Inits ConvertToNeutralAtomGates.
48-
49-
Args:
50-
ignore_failures: If set, gates that fail to convert are forwarded
51-
unchanged. If not set, conversion failures raise a TypeError.
52-
"""
53-
super().__init__()
54-
self.ignore_failures = ignore_failures
55-
self.gateset = neutral_atom_devices.neutral_atom_gateset()
56-
57-
def _convert_one(self, op: ops.Operation) -> ops.OP_TREE:
58-
# Known matrix?
59-
mat = protocols.unitary(op, None) if len(op.qubits) <= 2 else None
60-
if mat is not None and len(op.qubits) == 1:
61-
gates = transformers.single_qubit_matrix_to_phased_x_z(mat)
62-
return [g.on(op.qubits[0]) for g in gates]
63-
if mat is not None and len(op.qubits) == 2:
64-
return transformers.two_qubit_matrix_to_cz_operations(
65-
op.qubits[0], op.qubits[1], mat, allow_partial_czs=False, clean_operations=True
66-
)
67-
68-
return NotImplemented
69-
70-
def convert(self, op: ops.Operation) -> List[ops.Operation]:
71-
def on_stuck_raise(bad):
72-
return TypeError(
73-
"Don't know how to work with {!r}. "
74-
"It isn't a native atom operation, "
75-
"a 1 or 2 qubit gate with a known unitary, "
76-
"or composite.".format(bad)
77-
)
78-
79-
return protocols.decompose(
80-
op,
81-
keep=self.gateset._validate_operation,
82-
intercepting_decomposer=self._convert_one,
83-
on_stuck_raise=None if self.ignore_failures else on_stuck_raise,
84-
)
85-
86-
def optimization_at(
87-
self, circuit: 'cirq.Circuit', index: int, op: 'cirq.Operation'
88-
) -> Optional['cirq.PointOptimizationSummary']:
89-
converted = self.convert(op)
90-
if len(converted) == 1 and converted[0] is op:
91-
return None
92-
return PointOptimizationSummary(
93-
clear_span=1, new_operations=converted, clear_qubits=op.qubits
94-
)
95-
9618

9719
def is_native_neutral_atom_op(operation: ops.Operation) -> bool:
9820
"""Returns true if the operation is in the default neutral atom gateset."""

cirq-core/cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py

+31-73
Original file line numberDiff line numberDiff line change
@@ -12,81 +12,39 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import numpy as np
1615
import pytest
1716

1817
import cirq
1918

2019

21-
Q = cirq.LineQubit.range(3)
22-
23-
24-
def test_coverage():
25-
with cirq.testing.assert_deprecated(
26-
"Use cirq.optimize_for_target_gateset", deadline='v0.16', count=3
27-
):
28-
q = cirq.LineQubit.range(3)
29-
g = cirq.testing.ThreeQubitGate()
30-
31-
class FakeOperation(cirq.Operation):
32-
def __init__(self, gate, qubits):
33-
self._gate = gate
34-
self._qubits = qubits
35-
36-
@property
37-
def qubits(self):
38-
return self._qubits
39-
40-
def with_qubits(self, *new_qubits):
41-
return FakeOperation(self._gate, new_qubits)
42-
43-
op = FakeOperation(g, q).with_qubits(*q)
44-
circuit_ops = [cirq.Y(q[0]), cirq.ParallelGate(cirq.X, 3).on(*q)]
45-
c = cirq.Circuit(circuit_ops)
46-
cirq.neutral_atoms.ConvertToNeutralAtomGates().optimize_circuit(c)
47-
assert c == cirq.Circuit(circuit_ops)
48-
assert cirq.neutral_atoms.ConvertToNeutralAtomGates().convert(cirq.X.on(q[0])) == [
49-
cirq.X.on(q[0])
50-
]
51-
with pytest.raises(TypeError, match="Don't know how to work with"):
52-
cirq.neutral_atoms.ConvertToNeutralAtomGates().convert(op)
53-
assert not cirq.neutral_atoms.is_native_neutral_atom_op(op)
54-
assert not cirq.neutral_atoms.is_native_neutral_atom_gate(g)
55-
56-
57-
def test_avoids_decompose_fallback_when_matrix_available_single_qubit():
58-
class OtherX(cirq.testing.SingleQubitGate):
59-
def _unitary_(self) -> np.ndarray:
60-
return np.array([[0, 1], [1, 0]])
61-
62-
class OtherOtherX(cirq.testing.SingleQubitGate):
63-
def _decompose_(self, qubits):
64-
return OtherX().on(*qubits)
65-
66-
q = cirq.GridQubit(0, 0)
67-
c = cirq.Circuit(OtherX().on(q), OtherOtherX().on(q))
68-
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v0.16'):
69-
cirq.neutral_atoms.ConvertToNeutralAtomGates().optimize_circuit(c)
70-
cirq.testing.assert_has_diagram(c, '(0, 0): ───PhX(1)───PhX(1)───')
71-
72-
73-
def test_avoids_decompose_fallback_when_matrix_available_two_qubit():
74-
class OtherCZ(cirq.testing.TwoQubitGate):
75-
def _unitary_(self) -> np.ndarray:
76-
return np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]])
77-
78-
class OtherOtherCZ(cirq.testing.TwoQubitGate):
79-
def _decompose_(self, qubits):
80-
return OtherCZ().on(*qubits)
81-
82-
q00 = cirq.GridQubit(0, 0)
83-
q01 = cirq.GridQubit(0, 1)
84-
c = cirq.Circuit(OtherCZ().on(q00, q01), OtherOtherCZ().on(q00, q01))
85-
expected_diagram = """
86-
(0, 0): ───@───@───
87-
│ │
88-
(0, 1): ───@───@───
89-
"""
90-
with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v0.16'):
91-
cirq.neutral_atoms.ConvertToNeutralAtomGates().optimize_circuit(c)
92-
cirq.testing.assert_has_diagram(c, expected_diagram)
20+
Q, Q2, Q3 = cirq.LineQubit.range(3)
21+
22+
23+
@pytest.mark.parametrize(
24+
"op,expected",
25+
[
26+
(cirq.H(Q), False),
27+
(cirq.HPowGate(exponent=0.5)(Q), False),
28+
(cirq.PhasedXPowGate(exponent=0.25, phase_exponent=0.125)(Q), True),
29+
(cirq.XPowGate(exponent=0.5)(Q), True),
30+
(cirq.YPowGate(exponent=0.25)(Q), True),
31+
(cirq.ZPowGate(exponent=0.125)(Q), True),
32+
(cirq.CZPowGate(exponent=0.5)(Q, Q2), False),
33+
(cirq.CZ(Q, Q2), True),
34+
(cirq.CNOT(Q, Q2), True),
35+
(cirq.SWAP(Q, Q2), False),
36+
(cirq.ISWAP(Q, Q2), False),
37+
(cirq.CCNOT(Q, Q2, Q3), True),
38+
(cirq.CCZ(Q, Q2, Q3), True),
39+
(cirq.ParallelGate(cirq.X, num_copies=3)(Q, Q2, Q3), True),
40+
(cirq.ParallelGate(cirq.Y, num_copies=3)(Q, Q2, Q3), True),
41+
(cirq.ParallelGate(cirq.Z, num_copies=3)(Q, Q2, Q3), True),
42+
(cirq.X(Q).controlled_by(Q2, Q3), True),
43+
(cirq.Z(Q).controlled_by(Q2, Q3), True),
44+
(cirq.ZPowGate(exponent=0.5)(Q).controlled_by(Q2, Q3), False),
45+
],
46+
)
47+
def test_gateset(op: cirq.Operation, expected: bool):
48+
assert cirq.is_native_neutral_atom_op(op) == expected
49+
if op.gate is not None:
50+
assert cirq.is_native_neutral_atom_gate(op.gate) == expected

0 commit comments

Comments
 (0)