19
19
AbstractSet ,
20
20
Any ,
21
21
Callable ,
22
+ cast ,
22
23
Dict ,
23
24
FrozenSet ,
24
25
Iterable ,
@@ -80,17 +81,26 @@ class Moment:
80
81
are no such operations, returns an empty Moment.
81
82
"""
82
83
83
- def __init__ (self , * contents : 'cirq.OP_TREE' ) -> None :
84
+ def __init__ (self , * contents : 'cirq.OP_TREE' , _flatten_contents : bool = True ) -> None :
84
85
"""Constructs a moment with the given operations.
85
86
86
87
Args:
87
88
contents: The operations applied within the moment.
88
89
Will be flattened and frozen into a tuple before storing.
90
+ _flatten_contents: If True, use flatten_to_ops to convert
91
+ the OP_TREE of contents into a tuple of Operation. If False,
92
+ we skip flattening and assume that contents already consists
93
+ of individual operations. This is used internally by helper
94
+ methods to avoid unnecessary validation.
89
95
90
96
Raises:
91
97
ValueError: A qubit appears more than once.
92
98
"""
93
- self ._operations = tuple (op_tree .flatten_to_ops (contents ))
99
+ self ._operations = (
100
+ tuple (op_tree .flatten_to_ops (contents ))
101
+ if _flatten_contents
102
+ else cast (Tuple ['cirq.Operation' ], contents )
103
+ )
94
104
self ._sorted_operations : Optional [Tuple ['cirq.Operation' , ...]] = None
95
105
96
106
# An internal dictionary to support efficient operation access by qubit.
@@ -106,6 +116,20 @@ def __init__(self, *contents: 'cirq.OP_TREE') -> None:
106
116
self ._measurement_key_objs : Optional [FrozenSet ['cirq.MeasurementKey' ]] = None
107
117
self ._control_keys : Optional [FrozenSet ['cirq.MeasurementKey' ]] = None
108
118
119
+ @classmethod
120
+ def from_ops (cls , * ops : 'cirq.Operation' ) -> 'cirq.Moment' :
121
+ """Construct a Moment from the given operations.
122
+
123
+ This avoids calling `flatten_to_ops` in the moment constructor, which
124
+ results in better performance in cases where the contents of the moment
125
+ are already in the form of a sequence of operations rather than an
126
+ arbitrary OP_TREE.
127
+
128
+ Args:
129
+ *ops: Operations to include in the Moment.
130
+ """
131
+ return cls (* ops , _flatten_contents = False )
132
+
109
133
@property
110
134
def operations (self ) -> Tuple ['cirq.Operation' , ...]:
111
135
return self ._operations
@@ -164,7 +188,7 @@ def with_operation(self, operation: 'cirq.Operation') -> 'cirq.Moment':
164
188
raise ValueError (f'Overlapping operations: { operation } ' )
165
189
166
190
# Use private variables to facilitate a quick copy.
167
- m = Moment ()
191
+ m = Moment (_flatten_contents = False )
168
192
m ._operations = self ._operations + (operation ,)
169
193
m ._sorted_operations = None
170
194
m ._qubits = self ._qubits .union (operation .qubits )
@@ -194,7 +218,7 @@ def with_operations(self, *contents: 'cirq.OP_TREE') -> 'cirq.Moment':
194
218
if not flattened_contents :
195
219
return self
196
220
197
- m = Moment ()
221
+ m = Moment (_flatten_contents = False )
198
222
# Use private variables to facilitate a quick copy.
199
223
m ._qubit_to_op = self ._qubit_to_op .copy ()
200
224
qubits = set (self ._qubits )
@@ -483,7 +507,7 @@ def _json_dict_(self) -> Dict[str, Any]:
483
507
484
508
@classmethod
485
509
def _from_json_dict_ (cls , operations , ** kwargs ):
486
- return Moment ( operations )
510
+ return cls . from_ops ( * operations )
487
511
488
512
def __add__ (self , other : 'cirq.OP_TREE' ) -> 'cirq.Moment' :
489
513
0 commit comments