@@ -173,28 +173,20 @@ def _from_moments(cls: Type[CIRCUIT_TYPE], moments: Iterable['cirq.Moment']) ->
173
173
def moments (self ) -> Sequence ['cirq.Moment' ]:
174
174
pass
175
175
176
+ @abc .abstractmethod
176
177
def freeze (self ) -> 'cirq.FrozenCircuit' :
177
178
"""Creates a FrozenCircuit from this circuit.
178
179
179
180
If 'self' is a FrozenCircuit, the original object is returned.
180
181
"""
181
- from cirq .circuits import FrozenCircuit
182
-
183
- if isinstance (self , FrozenCircuit ):
184
- return self
185
-
186
- return FrozenCircuit (self , strategy = InsertStrategy .EARLIEST )
187
182
183
+ @abc .abstractmethod
188
184
def unfreeze (self , copy : bool = True ) -> 'cirq.Circuit' :
189
185
"""Creates a Circuit from this circuit.
190
186
191
187
Args:
192
188
copy: If True and 'self' is a Circuit, returns a copy that circuit.
193
189
"""
194
- if isinstance (self , Circuit ):
195
- return Circuit .copy (self ) if copy else self
196
-
197
- return Circuit (self , strategy = InsertStrategy .EARLIEST )
198
190
199
191
def __bool__ (self ):
200
192
return bool (self .moments )
@@ -1743,7 +1735,10 @@ def __init__(
1743
1735
together. This option does not affect later insertions into the
1744
1736
circuit.
1745
1737
"""
1738
+ # Implementation note: we set self._frozen = None any time self._moments
1739
+ # is mutated, to "invalidate" the frozen instance.
1746
1740
self ._moments : List ['cirq.Moment' ] = []
1741
+ self ._frozen : Optional ['cirq.FrozenCircuit' ] = None
1747
1742
flattened_contents = tuple (ops .flatten_to_ops_or_moments (contents ))
1748
1743
if all (isinstance (c , Moment ) for c in flattened_contents ):
1749
1744
self ._moments [:] = cast (Iterable [Moment ], flattened_contents )
@@ -1810,12 +1805,29 @@ def _load_contents_with_earliest_strategy(self, contents: 'cirq.OP_TREE'):
1810
1805
for i in range (length ):
1811
1806
if i in moments_by_index :
1812
1807
self ._moments .append (moments_by_index [i ].with_operations (op_lists_by_index [i ]))
1808
+ self ._frozen = None
1813
1809
else :
1814
1810
self ._moments .append (Moment (op_lists_by_index [i ]))
1811
+ self ._frozen = None
1815
1812
1816
1813
def __copy__ (self ) -> 'cirq.Circuit' :
1817
1814
return self .copy ()
1818
1815
1816
+ def freeze (self ) -> 'cirq.FrozenCircuit' :
1817
+ """Gets a frozen version of this circuit.
1818
+
1819
+ Repeated calls to `.freeze()` will return the same FrozenCircuit
1820
+ instance as long as this circuit is not mutated.
1821
+ """
1822
+ from cirq .circuits import FrozenCircuit
1823
+
1824
+ if self ._frozen is None :
1825
+ self ._frozen = FrozenCircuit .from_moments (* self ._moments )
1826
+ return self ._frozen
1827
+
1828
+ def unfreeze (self , copy : bool = True ) -> 'cirq.Circuit' :
1829
+ return self .copy () if copy else self
1830
+
1819
1831
def copy (self ) -> 'Circuit' :
1820
1832
"""Return a copy of this circuit."""
1821
1833
copied_circuit = Circuit ()
@@ -1841,11 +1853,13 @@ def __setitem__(self, key, value):
1841
1853
raise TypeError ('Can only assign Moments into Circuits.' )
1842
1854
1843
1855
self ._moments [key ] = value
1856
+ self ._frozen = None
1844
1857
1845
1858
# pylint: enable=function-redefined
1846
1859
1847
1860
def __delitem__ (self , key : Union [int , slice ]):
1848
1861
del self ._moments [key ]
1862
+ self ._frozen = None
1849
1863
1850
1864
def __iadd__ (self , other ):
1851
1865
self .append (other )
@@ -1874,6 +1888,7 @@ def __imul__(self, repetitions: _INT_TYPE):
1874
1888
if not isinstance (repetitions , (int , np .integer )):
1875
1889
return NotImplemented
1876
1890
self ._moments *= int (repetitions )
1891
+ self ._frozen = None
1877
1892
return self
1878
1893
1879
1894
def __mul__ (self , repetitions : _INT_TYPE ):
@@ -2017,6 +2032,7 @@ def _pick_or_create_inserted_op_moment_index(
2017
2032
2018
2033
if strategy is InsertStrategy .NEW or strategy is InsertStrategy .NEW_THEN_INLINE :
2019
2034
self ._moments .insert (splitter_index , Moment ())
2035
+ self ._frozen = None
2020
2036
return splitter_index
2021
2037
2022
2038
if strategy is InsertStrategy .INLINE :
@@ -2074,13 +2090,16 @@ def insert(
2074
2090
for moment_or_op in list (ops .flatten_to_ops_or_moments (moment_or_operation_tree )):
2075
2091
if isinstance (moment_or_op , Moment ):
2076
2092
self ._moments .insert (k , moment_or_op )
2093
+ self ._frozen = None
2077
2094
k += 1
2078
2095
else :
2079
2096
op = moment_or_op
2080
2097
p = self ._pick_or_create_inserted_op_moment_index (k , op , strategy )
2081
2098
while p >= len (self ._moments ):
2082
2099
self ._moments .append (Moment ())
2100
+ self ._frozen = None
2083
2101
self ._moments [p ] = self ._moments [p ].with_operation (op )
2102
+ self ._frozen = None
2084
2103
k = max (k , p + 1 )
2085
2104
if strategy is InsertStrategy .NEW_THEN_INLINE :
2086
2105
strategy = InsertStrategy .INLINE
@@ -2119,6 +2138,7 @@ def insert_into_range(self, operations: 'cirq.OP_TREE', start: int, end: int) ->
2119
2138
break
2120
2139
2121
2140
self ._moments [i ] = self ._moments [i ].with_operation (op )
2141
+ self ._frozen = None
2122
2142
op_index += 1
2123
2143
2124
2144
if op_index >= len (flat_ops ):
@@ -2165,6 +2185,7 @@ def _push_frontier(
2165
2185
if n_new_moments > 0 :
2166
2186
insert_index = min (late_frontier .values ())
2167
2187
self ._moments [insert_index :insert_index ] = [Moment ()] * n_new_moments
2188
+ self ._frozen = None
2168
2189
for q in update_qubits :
2169
2190
if early_frontier .get (q , 0 ) > insert_index :
2170
2191
early_frontier [q ] += n_new_moments
@@ -2191,13 +2212,13 @@ def _insert_operations(
2191
2212
if len (operations ) != len (insertion_indices ):
2192
2213
raise ValueError ('operations and insertion_indices must have the same length.' )
2193
2214
self ._moments += [Moment () for _ in range (1 + max (insertion_indices ) - len (self ))]
2215
+ self ._frozen = None
2194
2216
moment_to_ops : Dict [int , List ['cirq.Operation' ]] = defaultdict (list )
2195
2217
for op_index , moment_index in enumerate (insertion_indices ):
2196
2218
moment_to_ops [moment_index ].append (operations [op_index ])
2197
2219
for moment_index , new_ops in moment_to_ops .items ():
2198
- self ._moments [moment_index ] = Moment (
2199
- self ._moments [moment_index ].operations + tuple (new_ops )
2200
- )
2220
+ self ._moments [moment_index ] = self ._moments [moment_index ].with_operations (* new_ops )
2221
+ self ._frozen = None
2201
2222
2202
2223
def insert_at_frontier (
2203
2224
self ,
@@ -2259,6 +2280,7 @@ def batch_remove(self, removals: Iterable[Tuple[int, 'cirq.Operation']]) -> None
2259
2280
old_op for old_op in copy ._moments [i ].operations if op != old_op
2260
2281
)
2261
2282
self ._moments = copy ._moments
2283
+ self ._frozen = None
2262
2284
2263
2285
def batch_replace (
2264
2286
self , replacements : Iterable [Tuple [int , 'cirq.Operation' , 'cirq.Operation' ]]
@@ -2283,6 +2305,7 @@ def batch_replace(
2283
2305
old_op if old_op != op else new_op for old_op in copy ._moments [i ].operations
2284
2306
)
2285
2307
self ._moments = copy ._moments
2308
+ self ._frozen = None
2286
2309
2287
2310
def batch_insert_into (self , insert_intos : Iterable [Tuple [int , 'cirq.OP_TREE' ]]) -> None :
2288
2311
"""Inserts operations into empty spaces in existing moments.
@@ -2303,6 +2326,7 @@ def batch_insert_into(self, insert_intos: Iterable[Tuple[int, 'cirq.OP_TREE']])
2303
2326
for i , insertions in insert_intos :
2304
2327
copy ._moments [i ] = copy ._moments [i ].with_operations (insertions )
2305
2328
self ._moments = copy ._moments
2329
+ self ._frozen = None
2306
2330
2307
2331
def batch_insert (self , insertions : Iterable [Tuple [int , 'cirq.OP_TREE' ]]) -> None :
2308
2332
"""Applies a batched insert operation to the circuit.
@@ -2337,6 +2361,7 @@ def batch_insert(self, insertions: Iterable[Tuple[int, 'cirq.OP_TREE']]) -> None
2337
2361
if next_index > insert_index :
2338
2362
shift += next_index - insert_index
2339
2363
self ._moments = copy ._moments
2364
+ self ._frozen = None
2340
2365
2341
2366
def append (
2342
2367
self ,
@@ -2367,6 +2392,7 @@ def clear_operations_touching(
2367
2392
for k in moment_indices :
2368
2393
if 0 <= k < len (self ._moments ):
2369
2394
self ._moments [k ] = self ._moments [k ].without_operations_touching (qubits )
2395
+ self ._frozen = None
2370
2396
2371
2397
@property
2372
2398
def moments (self ) -> Sequence ['cirq.Moment' ]:
0 commit comments