15
15
"""A simplified time-slice of operations within a sequenced circuit."""
16
16
17
17
import itertools
18
+ from functools import cached_property
18
19
from types import NotImplementedType
19
20
from typing import (
20
21
AbstractSet ,
@@ -113,7 +114,6 @@ def __init__(self, *contents: 'cirq.OP_TREE', _flatten_contents: bool = True) ->
113
114
raise ValueError (f'Overlapping operations: { self .operations } ' )
114
115
self ._qubit_to_op [q ] = op
115
116
116
- self ._qubits = frozenset (self ._qubit_to_op .keys ())
117
117
self ._measurement_key_objs : Optional [FrozenSet ['cirq.MeasurementKey' ]] = None
118
118
self ._control_keys : Optional [FrozenSet ['cirq.MeasurementKey' ]] = None
119
119
@@ -135,9 +135,9 @@ def from_ops(cls, *ops: 'cirq.Operation') -> 'cirq.Moment':
135
135
def operations (self ) -> Tuple ['cirq.Operation' , ...]:
136
136
return self ._operations
137
137
138
- @property
138
+ @cached_property
139
139
def qubits (self ) -> FrozenSet ['cirq.Qid' ]:
140
- return self ._qubits
140
+ return frozenset ( self ._qubit_to_op )
141
141
142
142
def operates_on_single_qubit (self , qubit : 'cirq.Qid' ) -> bool :
143
143
"""Determines if the moment has operations touching the given qubit.
@@ -157,7 +157,7 @@ def operates_on(self, qubits: Iterable['cirq.Qid']) -> bool:
157
157
Returns:
158
158
Whether this moment has operations involving the qubits.
159
159
"""
160
- return not self ._qubits .isdisjoint (qubits )
160
+ return not self ._qubit_to_op . keys () .isdisjoint (qubits )
161
161
162
162
def operation_at (self , qubit : raw_types .Qid ) -> Optional ['cirq.Operation' ]:
163
163
"""Returns the operation on a certain qubit for the moment.
@@ -185,14 +185,13 @@ def with_operation(self, operation: 'cirq.Operation') -> 'cirq.Moment':
185
185
Raises:
186
186
ValueError: If the operation given overlaps a current operation in the moment.
187
187
"""
188
- if any (q in self ._qubits for q in operation .qubits ):
188
+ if any (q in self ._qubit_to_op for q in operation .qubits ):
189
189
raise ValueError (f'Overlapping operations: { operation } ' )
190
190
191
191
# Use private variables to facilitate a quick copy.
192
192
m = Moment (_flatten_contents = False )
193
193
m ._operations = self ._operations + (operation ,)
194
194
m ._sorted_operations = None
195
- m ._qubits = self ._qubits .union (operation .qubits )
196
195
m ._qubit_to_op = {** self ._qubit_to_op , ** {q : operation for q in operation .qubits }}
197
196
198
197
m ._measurement_key_objs = self ._measurement_key_objs_ ().union (
@@ -222,14 +221,11 @@ def with_operations(self, *contents: 'cirq.OP_TREE') -> 'cirq.Moment':
222
221
m = Moment (_flatten_contents = False )
223
222
# Use private variables to facilitate a quick copy.
224
223
m ._qubit_to_op = self ._qubit_to_op .copy ()
225
- qubits = set (self ._qubits )
226
224
for op in flattened_contents :
227
- if any (q in qubits for q in op .qubits ):
225
+ if any (q in m . _qubit_to_op for q in op .qubits ):
228
226
raise ValueError (f'Overlapping operations: { op } ' )
229
- qubits .update (op .qubits )
230
227
for q in op .qubits :
231
228
m ._qubit_to_op [q ] = op
232
- m ._qubits = frozenset (qubits )
233
229
234
230
m ._operations = self ._operations + flattened_contents
235
231
m ._sorted_operations = None
@@ -450,7 +446,9 @@ def expand_to(self, qubits: Iterable['cirq.Qid']) -> 'cirq.Moment':
450
446
@_compat .cached_method ()
451
447
def _has_kraus_ (self ) -> bool :
452
448
"""Returns True if self has a Kraus representation and self uses <= 10 qubits."""
453
- return all (protocols .has_kraus (op ) for op in self .operations ) and len (self .qubits ) <= 10
449
+ return (
450
+ all (protocols .has_kraus (op ) for op in self .operations ) and len (self ._qubit_to_op ) <= 10
451
+ )
454
452
455
453
def _kraus_ (self ) -> Sequence [np .ndarray ]:
456
454
r"""Returns Kraus representation of self.
@@ -475,7 +473,7 @@ def _kraus_(self) -> Sequence[np.ndarray]:
475
473
if not self ._has_kraus_ ():
476
474
return NotImplemented
477
475
478
- qubits = sorted (self .qubits )
476
+ qubits = sorted (self ._qubit_to_op )
479
477
n = len (qubits )
480
478
if n < 1 :
481
479
return (np .array ([[1 + 0j ]]),)
@@ -602,7 +600,7 @@ def to_text_diagram(
602
600
"""
603
601
604
602
# Figure out where to place everything.
605
- qs = set ( self .qubits ) | set (extra_qubits )
603
+ qs = self ._qubit_to_op . keys ( ) | set (extra_qubits )
606
604
points = {xy_breakdown_func (q ) for q in qs }
607
605
x_keys = sorted ({pt [0 ] for pt in points }, key = _SortByValFallbackToType )
608
606
y_keys = sorted ({pt [1 ] for pt in points }, key = _SortByValFallbackToType )
0 commit comments