Skip to content

Commit 6c98693

Browse files
MichaelBroughtonrht
authored andcommitted
Deprecate ciruit.device everywhere. (quantumlib#4845)
Last item in step 1 of quantumlib#4744 .
1 parent 67561b0 commit 6c98693

9 files changed

+399
-93
lines changed

Diff for: cirq-core/cirq/circuits/circuit.py

+103-35
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@
2020
"""
2121

2222
import abc
23+
import contextlib
2324
import enum
2425
import html
2526
import itertools
2627
import math
28+
import re
29+
import warnings
2730
from collections import defaultdict
2831
from typing import (
2932
AbstractSet,
@@ -50,7 +53,7 @@
5053
import numpy as np
5154

5255
import cirq._version
53-
from cirq import devices, ops, protocols, qis
56+
from cirq import _compat, devices, ops, protocols, qis
5457
from cirq.circuits._bucket_priority_queue import BucketPriorityQueue
5558
from cirq.circuits.circuit_operation import CircuitOperation
5659
from cirq.circuits.insert_strategy import InsertStrategy
@@ -70,6 +73,17 @@
7073
_DEVICE_DEP_MESSAGE = 'Attaching devices to circuits will no longer be supported.'
7174

7275

76+
@contextlib.contextmanager
77+
def _block_overlapping_deprecation():
78+
with warnings.catch_warnings():
79+
warnings.filterwarnings(
80+
action='ignore',
81+
category=DeprecationWarning,
82+
message=f'(.|\n)*{re.escape(_DEVICE_DEP_MESSAGE)}(.|\n)*',
83+
)
84+
yield
85+
86+
7387
class Alignment(enum.Enum):
7488
# Stop when left ends are lined up.
7589
LEFT = 1
@@ -139,7 +153,10 @@ def freeze(self) -> 'cirq.FrozenCircuit':
139153

140154
if isinstance(self, FrozenCircuit):
141155
return self
142-
return FrozenCircuit(self, strategy=InsertStrategy.EARLIEST, device=self.device)
156+
157+
if self._device == cirq.UNCONSTRAINED_DEVICE:
158+
return FrozenCircuit(self, strategy=InsertStrategy.EARLIEST)
159+
return FrozenCircuit(self, strategy=InsertStrategy.EARLIEST, device=self._device)
143160

144161
def unfreeze(self, copy: bool = True) -> 'cirq.Circuit':
145162
"""Creates a Circuit from this circuit.
@@ -149,23 +166,26 @@ def unfreeze(self, copy: bool = True) -> 'cirq.Circuit':
149166
"""
150167
if isinstance(self, Circuit):
151168
return Circuit.copy(self) if copy else self
152-
return Circuit(self, strategy=InsertStrategy.EARLIEST, device=self.device)
169+
170+
if self._device == cirq.UNCONSTRAINED_DEVICE:
171+
return Circuit(self, strategy=InsertStrategy.EARLIEST)
172+
return Circuit(self, strategy=InsertStrategy.EARLIEST, device=self._device)
153173

154174
def __bool__(self):
155175
return bool(self.moments)
156176

157177
def __eq__(self, other):
158178
if not isinstance(other, AbstractCircuit):
159179
return NotImplemented
160-
return tuple(self.moments) == tuple(other.moments) and self.device == other.device
180+
return tuple(self.moments) == tuple(other.moments) and self._device == other._device
161181

162182
def _approx_eq_(self, other: Any, atol: Union[int, float]) -> bool:
163183
"""See `cirq.protocols.SupportsApproximateEquality`."""
164184
if not isinstance(other, AbstractCircuit):
165185
return NotImplemented
166186
return (
167187
cirq.protocols.approx_eq(tuple(self.moments), tuple(other.moments), atol=atol)
168-
and self.device == other.device
188+
and self._device == other._device
169189
)
170190

171191
def __ne__(self, other) -> bool:
@@ -241,7 +261,7 @@ def __repr__(self) -> str:
241261
args = []
242262
if self.moments:
243263
args.append(_list_repr_with_indented_item_lines(self.moments))
244-
if self.device != devices.UNCONSTRAINED_DEVICE:
264+
if self._device != devices.UNCONSTRAINED_DEVICE:
245265
args.append(f'device={self.device!r}')
246266
return f'cirq.{cls_name}({", ".join(args)})'
247267

@@ -1323,11 +1343,16 @@ def save_qasm(
13231343
self._to_qasm_output(header, precision, qubit_order).save(file_path)
13241344

13251345
def _json_dict_(self):
1326-
return protocols.obj_to_dict_helper(self, ['moments', 'device'])
1346+
ret = protocols.obj_to_dict_helper(self, ['moments', '_device'])
1347+
ret['device'] = ret['_device']
1348+
del ret['_device']
1349+
return ret
13271350

13281351
@classmethod
13291352
def _from_json_dict_(cls, moments, device, **kwargs):
1330-
return cls(moments, strategy=InsertStrategy.EARLIEST, device=device)
1353+
if device == cirq.UNCONSTRAINED_DEVICE:
1354+
return cls(moments, strategy=InsertStrategy.EARLIEST)
1355+
return cls(moments, device=device, strategy=InsertStrategy.EARLIEST)
13311356

13321357
def zip(
13331358
*circuits: 'cirq.AbstractCircuit', align: Union['cirq.Alignment', str] = Alignment.LEFT
@@ -1677,6 +1702,12 @@ class Circuit(AbstractCircuit):
16771702
independent 'factors' of the original Circuit.
16781703
"""
16791704

1705+
@_compat.deprecated_parameter(
1706+
deadline='v0.15',
1707+
fix=_DEVICE_DEP_MESSAGE,
1708+
parameter_desc='device',
1709+
match=lambda args, kwargs: 'device' in kwargs,
1710+
)
16801711
def __init__(
16811712
self,
16821713
*contents: 'cirq.OP_TREE',
@@ -1701,25 +1732,40 @@ def __init__(
17011732
self._device = device
17021733
self.append(contents, strategy=strategy)
17031734

1704-
@property
1705-
def device(self) -> 'cirq.Device':
1735+
@property # type: ignore
1736+
@_compat.deprecated(
1737+
deadline='v0.15',
1738+
fix=_DEVICE_DEP_MESSAGE,
1739+
)
1740+
def device(self) -> devices.Device:
17061741
return self._device
17071742

1708-
@device.setter
1743+
@device.setter # type: ignore
1744+
@_compat.deprecated(
1745+
deadline='v0.15',
1746+
fix=_DEVICE_DEP_MESSAGE,
1747+
)
17091748
def device(self, new_device: 'cirq.Device') -> None:
17101749
new_device.validate_circuit(self)
17111750
self._device = new_device
17121751

17131752
def __copy__(self) -> 'cirq.Circuit':
17141753
return self.copy()
17151754

1716-
def copy(self) -> 'cirq.Circuit':
1717-
copied_circuit = Circuit(device=self._device)
1755+
def copy(self) -> 'Circuit':
1756+
if self._device == cirq.UNCONSTRAINED_DEVICE:
1757+
copied_circuit = Circuit()
1758+
else:
1759+
copied_circuit = Circuit(device=self._device)
17181760
copied_circuit._moments = self._moments[:]
17191761
return copied_circuit
17201762

1721-
def _with_sliced_moments(self, moments: Iterable['cirq.Moment']) -> 'cirq.Circuit':
1722-
new_circuit = Circuit(device=self.device)
1763+
def _with_sliced_moments(self, moments: Iterable['cirq.Moment']) -> 'Circuit':
1764+
if self._device == cirq.UNCONSTRAINED_DEVICE:
1765+
new_circuit = Circuit()
1766+
else:
1767+
new_circuit = Circuit(device=self._device)
1768+
17231769
new_circuit._moments = list(moments)
17241770
return new_circuit
17251771

@@ -1759,8 +1805,8 @@ def __iadd__(self, other):
17591805
def __add__(self, other):
17601806
if isinstance(other, type(self)):
17611807
if (
1762-
devices.UNCONSTRAINED_DEVICE not in [self._device, other.device]
1763-
and self._device != other.device
1808+
devices.UNCONSTRAINED_DEVICE not in [self._device, other._device]
1809+
and self._device != other._device
17641810
):
17651811
raise ValueError("Can't add circuits with incompatible devices.")
17661812
elif not isinstance(other, (ops.Operation, Iterable)):
@@ -1791,6 +1837,8 @@ def __imul__(self, repetitions: INT_TYPE):
17911837
def __mul__(self, repetitions: INT_TYPE):
17921838
if not isinstance(repetitions, (int, np.integer)):
17931839
return NotImplemented
1840+
if self._device == cirq.UNCONSTRAINED_DEVICE:
1841+
return Circuit(self._moments * int(repetitions))
17941842
return Circuit(self._moments * int(repetitions), device=self._device)
17951843

17961844
def __rmul__(self, repetitions: INT_TYPE):
@@ -1816,10 +1864,17 @@ def __pow__(self, exponent: int) -> 'cirq.Circuit':
18161864
if inv_moment is NotImplemented:
18171865
return NotImplemented
18181866
inv_moments.append(inv_moment)
1867+
1868+
if self._device == cirq.UNCONSTRAINED_DEVICE:
1869+
return cirq.Circuit(inv_moments)
18191870
return cirq.Circuit(inv_moments, device=self._device)
18201871

18211872
__hash__ = None # type: ignore
18221873

1874+
@_compat.deprecated(
1875+
deadline='v0.15',
1876+
fix=_DEVICE_DEP_MESSAGE,
1877+
)
18231878
def with_device(
18241879
self,
18251880
new_device: 'cirq.Device',
@@ -1835,15 +1890,16 @@ def with_device(
18351890
Returns:
18361891
The translated circuit.
18371892
"""
1838-
return Circuit(
1839-
[
1840-
ops.Moment(
1841-
operation.transform_qubits(qubit_mapping) for operation in moment.operations
1842-
)
1843-
for moment in self._moments
1844-
],
1845-
device=new_device,
1846-
)
1893+
with _block_overlapping_deprecation():
1894+
return Circuit(
1895+
[
1896+
ops.Moment(
1897+
operation.transform_qubits(qubit_mapping) for operation in moment.operations
1898+
)
1899+
for moment in self._moments
1900+
],
1901+
device=new_device,
1902+
)
18471903

18481904
def tetris_concat(
18491905
*circuits: 'cirq.AbstractCircuit', align: Union['cirq.Alignment', str] = Alignment.LEFT
@@ -1859,6 +1915,12 @@ def zip(
18591915

18601916
zip.__doc__ = AbstractCircuit.zip.__doc__
18611917

1918+
@_compat.deprecated_parameter(
1919+
deadline='v0.15',
1920+
fix=_DEVICE_DEP_MESSAGE,
1921+
parameter_desc='new_device',
1922+
match=lambda args, kwargs: 'new_device' in kwargs,
1923+
)
18621924
def transform_qubits(
18631925
self,
18641926
qubit_map: Union[Dict['cirq.Qid', 'cirq.Qid'], Callable[['cirq.Qid'], 'cirq.Qid']],
@@ -1867,10 +1929,6 @@ def transform_qubits(
18671929
) -> 'cirq.Circuit':
18681930
"""Returns the same circuit, but with different qubits.
18691931
1870-
Note that this method does essentially the same thing as
1871-
`cirq.Circuit.with_device`. It is included regardless because there are
1872-
also `transform_qubits` methods on `cirq.Operation` and `cirq.Moment`.
1873-
18741932
Args:
18751933
qubit_map: A function or a dict mapping each current qubit into a desired
18761934
new qubit.
@@ -1891,9 +1949,17 @@ def transform_qubits(
18911949
transform = lambda q: qubit_map.get(q, q) # type: ignore
18921950
else:
18931951
raise TypeError('qubit_map must be a function or dict mapping qubits to qubits.')
1894-
return self.with_device(
1895-
new_device=self.device if new_device is None else new_device, qubit_mapping=transform
1896-
)
1952+
1953+
op_list = [
1954+
ops.Moment(operation.transform_qubits(transform) for operation in moment.operations)
1955+
for moment in self._moments
1956+
]
1957+
1958+
if new_device is None and self._device == devices.UNCONSTRAINED_DEVICE:
1959+
return Circuit(op_list)
1960+
1961+
with _block_overlapping_deprecation():
1962+
return Circuit(op_list, device=self._device if new_device is None else new_device)
18971963

18981964
def _prev_moment_available(self, op: 'cirq.Operation', end_moment_index: int) -> Optional[int]:
18991965
last_available = end_moment_index
@@ -2309,8 +2375,10 @@ def _resolve_parameters_(
23092375
resolved_operations = _resolve_operations(moment.operations, resolver, recursive)
23102376
new_moment = ops.Moment(resolved_operations)
23112377
resolved_moments.append(new_moment)
2312-
resolved_circuit = Circuit(resolved_moments, device=self.device)
2313-
return resolved_circuit
2378+
if self._device == devices.UNCONSTRAINED_DEVICE:
2379+
return Circuit(resolved_moments)
2380+
with _block_overlapping_deprecation():
2381+
return Circuit(resolved_moments, device=self._device)
23142382

23152383
@property
23162384
def moments(self):

Diff for: cirq-core/cirq/circuits/circuit_dag.py

+36-7
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import functools
1818
import networkx
1919

20-
from cirq import ops, devices
20+
from cirq import _compat, ops, devices
2121
from cirq.circuits import circuit
2222

2323
if TYPE_CHECKING:
@@ -70,6 +70,12 @@ class CircuitDag(networkx.DiGraph):
7070

7171
disjoint_qubits = staticmethod(_disjoint_qubits)
7272

73+
@_compat.deprecated_parameter(
74+
deadline='v0.15',
75+
fix=circuit._DEVICE_DEP_MESSAGE,
76+
parameter_desc='device',
77+
match=lambda args, kwargs: 'device' in kwargs or len(args) == 4,
78+
)
7379
def __init__(
7480
self,
7581
can_reorder: Callable[['cirq.Operation', 'cirq.Operation'], bool] = _disjoint_qubits,
@@ -92,28 +98,49 @@ def __init__(
9298
"""
9399
super().__init__(incoming_graph_data)
94100
self.can_reorder = can_reorder
95-
self.device = device
101+
self._device = device
102+
103+
@property # type: ignore
104+
@_compat.deprecated(
105+
deadline='v0.15',
106+
fix=circuit._DEVICE_DEP_MESSAGE,
107+
)
108+
def device(self) -> devices.Device:
109+
return self._device
96110

97111
@staticmethod
98112
def make_node(op: 'cirq.Operation') -> Unique:
99113
return Unique(op)
100114

101115
@staticmethod
102116
def from_circuit(
103-
circuit: 'cirq.Circuit',
117+
circuit: circuit.Circuit,
104118
can_reorder: Callable[['cirq.Operation', 'cirq.Operation'], bool] = _disjoint_qubits,
105119
) -> 'CircuitDag':
120+
if circuit._device == devices.UNCONSTRAINED_DEVICE:
121+
return CircuitDag.from_ops(circuit.all_operations(), can_reorder=can_reorder)
106122
return CircuitDag.from_ops(
107-
circuit.all_operations(), can_reorder=can_reorder, device=circuit.device
123+
circuit.all_operations(), can_reorder=can_reorder, device=circuit._device
108124
)
109125

110126
@staticmethod
127+
@_compat.deprecated_parameter(
128+
deadline='v0.15',
129+
fix=circuit._DEVICE_DEP_MESSAGE,
130+
parameter_desc='device',
131+
match=lambda args, kwargs: 'device' in kwargs,
132+
)
111133
def from_ops(
112134
*operations: 'cirq.OP_TREE',
113135
can_reorder: Callable[['cirq.Operation', 'cirq.Operation'], bool] = _disjoint_qubits,
114136
device: 'cirq.Device' = devices.UNCONSTRAINED_DEVICE,
115137
) -> 'CircuitDag':
116-
dag = CircuitDag(can_reorder=can_reorder, device=device)
138+
if device == devices.UNCONSTRAINED_DEVICE:
139+
dag = CircuitDag(can_reorder=can_reorder)
140+
else:
141+
with circuit._block_overlapping_deprecation():
142+
dag = CircuitDag(can_reorder=can_reorder, device=device)
143+
117144
for op in ops.flatten_op_tree(operations):
118145
dag.append(cast(ops.Operation, op))
119146
return dag
@@ -184,9 +211,11 @@ def all_operations(self) -> Iterator['cirq.Operation']:
184211
def all_qubits(self):
185212
return frozenset(q for node in self.nodes for q in node.val.qubits)
186213

187-
def to_circuit(self) -> 'cirq.Circuit':
214+
def to_circuit(self) -> circuit.Circuit:
215+
if self._device == devices.UNCONSTRAINED_DEVICE:
216+
return circuit.Circuit(self.all_operations(), strategy=circuit.InsertStrategy.EARLIEST)
188217
return circuit.Circuit(
189-
self.all_operations(), strategy=circuit.InsertStrategy.EARLIEST, device=self.device
218+
self.all_operations(), strategy=circuit.InsertStrategy.EARLIEST, device=self._device
190219
)
191220

192221
def findall_nodes_until_blocked(

0 commit comments

Comments
 (0)