cirq-core 1.6.0.dev20250709210336__py3-none-any.whl → 1.6.0.dev20250710201614__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cirq-core might be problematic. Click here for more details.
- cirq/_version.py +1 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/circuit.py +103 -30
- cirq/circuits/circuit_test.py +49 -0
- cirq/circuits/frozen_circuit.py +8 -35
- cirq/circuits/frozen_circuit_test.py +23 -3
- {cirq_core-1.6.0.dev20250709210336.dist-info → cirq_core-1.6.0.dev20250710201614.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250709210336.dist-info → cirq_core-1.6.0.dev20250710201614.dist-info}/RECORD +11 -11
- {cirq_core-1.6.0.dev20250709210336.dist-info → cirq_core-1.6.0.dev20250710201614.dist-info}/WHEEL +0 -0
- {cirq_core-1.6.0.dev20250709210336.dist-info → cirq_core-1.6.0.dev20250710201614.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.6.0.dev20250709210336.dist-info → cirq_core-1.6.0.dev20250710201614.dist-info}/top_level.txt +0 -0
cirq/_version.py
CHANGED
cirq/_version_test.py
CHANGED
cirq/circuits/circuit.py
CHANGED
|
@@ -33,6 +33,7 @@ from typing import (
|
|
|
33
33
|
Any,
|
|
34
34
|
Callable,
|
|
35
35
|
cast,
|
|
36
|
+
Hashable,
|
|
36
37
|
Iterable,
|
|
37
38
|
Iterator,
|
|
38
39
|
Mapping,
|
|
@@ -141,7 +142,9 @@ class AbstractCircuit(abc.ABC):
|
|
|
141
142
|
"""
|
|
142
143
|
|
|
143
144
|
@classmethod
|
|
144
|
-
def from_moments(
|
|
145
|
+
def from_moments(
|
|
146
|
+
cls: type[CIRCUIT_TYPE], *moments: cirq.OP_TREE | None, tags: Sequence[Hashable] = ()
|
|
147
|
+
) -> CIRCUIT_TYPE:
|
|
145
148
|
"""Create a circuit from moment op trees.
|
|
146
149
|
|
|
147
150
|
Args:
|
|
@@ -155,8 +158,12 @@ class AbstractCircuit(abc.ABC):
|
|
|
155
158
|
which is then included in the new circuit. Note that in this
|
|
156
159
|
case we have the normal restriction that operations in a
|
|
157
160
|
moment must be applied to disjoint sets of qubits.
|
|
161
|
+
tags: A sequence of any type of object that is useful to attach metadata
|
|
162
|
+
to this circuit as long as the type is hashable. If you wish the
|
|
163
|
+
resulting circuit to be eventually serialized into JSON, you should
|
|
164
|
+
also restrict the tags to be JSON serializable.
|
|
158
165
|
"""
|
|
159
|
-
return cls._from_moments(cls._make_moments(moments))
|
|
166
|
+
return cls._from_moments(cls._make_moments(moments), tags=tags)
|
|
160
167
|
|
|
161
168
|
@staticmethod
|
|
162
169
|
def _make_moments(moments: Iterable[cirq.OP_TREE | None]) -> Iterator[cirq.Moment]:
|
|
@@ -170,7 +177,9 @@ class AbstractCircuit(abc.ABC):
|
|
|
170
177
|
|
|
171
178
|
@classmethod
|
|
172
179
|
@abc.abstractmethod
|
|
173
|
-
def _from_moments(
|
|
180
|
+
def _from_moments(
|
|
181
|
+
cls: type[CIRCUIT_TYPE], moments: Iterable[cirq.Moment], tags: Sequence[Hashable]
|
|
182
|
+
) -> CIRCUIT_TYPE:
|
|
174
183
|
"""Create a circuit from moments.
|
|
175
184
|
|
|
176
185
|
This must be implemented by subclasses. It provides a more efficient way
|
|
@@ -201,6 +210,20 @@ class AbstractCircuit(abc.ABC):
|
|
|
201
210
|
copy: If True and 'self' is a Circuit, returns a copy that circuit.
|
|
202
211
|
"""
|
|
203
212
|
|
|
213
|
+
@property
|
|
214
|
+
@abc.abstractmethod
|
|
215
|
+
def tags(self) -> tuple[Hashable, ...]:
|
|
216
|
+
"""Returns a tuple of the Circuit's tags."""
|
|
217
|
+
|
|
218
|
+
@abc.abstractmethod
|
|
219
|
+
def with_tags(self, *new_tags: Hashable) -> Self:
|
|
220
|
+
"""Creates a new tagged Circuit with `self.tags` and `new_tags` combined."""
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def untagged(self) -> Self:
|
|
224
|
+
"""Returns the underlying Circuit without any tags."""
|
|
225
|
+
return self._from_moments(self.moments, tags=()) if self.tags else self
|
|
226
|
+
|
|
204
227
|
def __bool__(self) -> bool:
|
|
205
228
|
return bool(self.moments)
|
|
206
229
|
|
|
@@ -210,14 +233,16 @@ class AbstractCircuit(abc.ABC):
|
|
|
210
233
|
return other is self or (
|
|
211
234
|
len(self.moments) == len(other.moments)
|
|
212
235
|
and all(m0 == m1 for m0, m1 in zip(self.moments, other.moments))
|
|
236
|
+
and self.tags == other.tags
|
|
213
237
|
)
|
|
214
238
|
|
|
215
239
|
def _approx_eq_(self, other: Any, atol: float) -> bool:
|
|
216
240
|
"""See `cirq.protocols.SupportsApproximateEquality`."""
|
|
217
241
|
if not isinstance(other, AbstractCircuit):
|
|
218
242
|
return NotImplemented
|
|
219
|
-
return other is self or
|
|
220
|
-
|
|
243
|
+
return other is self or (
|
|
244
|
+
self.tags == other.tags
|
|
245
|
+
and cirq.protocols.approx_eq(tuple(self.moments), tuple(other.moments), atol=atol)
|
|
221
246
|
)
|
|
222
247
|
|
|
223
248
|
def __ne__(self, other) -> bool:
|
|
@@ -259,7 +284,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
259
284
|
|
|
260
285
|
def __getitem__(self, key):
|
|
261
286
|
if isinstance(key, slice):
|
|
262
|
-
return self._from_moments(self.moments[key])
|
|
287
|
+
return self._from_moments(self.moments[key], tags=self.tags)
|
|
263
288
|
if hasattr(key, '__index__'):
|
|
264
289
|
return self.moments[key]
|
|
265
290
|
if isinstance(key, tuple):
|
|
@@ -272,7 +297,9 @@ class AbstractCircuit(abc.ABC):
|
|
|
272
297
|
return selected_moments[qubit_idx]
|
|
273
298
|
if isinstance(qubit_idx, ops.Qid):
|
|
274
299
|
qubit_idx = [qubit_idx]
|
|
275
|
-
return self._from_moments(
|
|
300
|
+
return self._from_moments(
|
|
301
|
+
(moment[qubit_idx] for moment in selected_moments), tags=self.tags
|
|
302
|
+
)
|
|
276
303
|
|
|
277
304
|
raise TypeError('__getitem__ called with key not of type slice, int, or tuple.')
|
|
278
305
|
|
|
@@ -283,7 +310,9 @@ class AbstractCircuit(abc.ABC):
|
|
|
283
310
|
args = []
|
|
284
311
|
if self.moments:
|
|
285
312
|
args.append(_list_repr_with_indented_item_lines(self.moments))
|
|
286
|
-
|
|
313
|
+
moments_repr = f'{", ".join(args)}'
|
|
314
|
+
tag_repr = ','.join(_compat.proper_repr(t) for t in self.tags)
|
|
315
|
+
return f'{moments_repr}, tags=[{tag_repr}]' if self.tags else moments_repr
|
|
287
316
|
|
|
288
317
|
def __repr__(self) -> str:
|
|
289
318
|
cls_name = self.__class__.__name__
|
|
@@ -942,7 +971,9 @@ class AbstractCircuit(abc.ABC):
|
|
|
942
971
|
"""Apply func to expand each op into a circuit, then zip up the circuits."""
|
|
943
972
|
return Circuit.zip(*[Circuit(func(op)) for op in moment])
|
|
944
973
|
|
|
945
|
-
return self._from_moments(
|
|
974
|
+
return self._from_moments(
|
|
975
|
+
(m for moment in self for m in map_moment(moment)), tags=self.tags
|
|
976
|
+
)
|
|
946
977
|
|
|
947
978
|
def qid_shape(
|
|
948
979
|
self, qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT
|
|
@@ -983,15 +1014,19 @@ class AbstractCircuit(abc.ABC):
|
|
|
983
1014
|
|
|
984
1015
|
def _with_measurement_key_mapping_(self, key_map: Mapping[str, str]):
|
|
985
1016
|
return self._from_moments(
|
|
986
|
-
protocols.with_measurement_key_mapping(moment, key_map) for moment in self.moments
|
|
1017
|
+
(protocols.with_measurement_key_mapping(moment, key_map) for moment in self.moments),
|
|
1018
|
+
tags=self.tags,
|
|
987
1019
|
)
|
|
988
1020
|
|
|
989
1021
|
def _with_key_path_(self, path: tuple[str, ...]):
|
|
990
|
-
return self._from_moments(
|
|
1022
|
+
return self._from_moments(
|
|
1023
|
+
(protocols.with_key_path(moment, path) for moment in self.moments), tags=self.tags
|
|
1024
|
+
)
|
|
991
1025
|
|
|
992
1026
|
def _with_key_path_prefix_(self, prefix: tuple[str, ...]):
|
|
993
1027
|
return self._from_moments(
|
|
994
|
-
protocols.with_key_path_prefix(moment, prefix) for moment in self.moments
|
|
1028
|
+
(protocols.with_key_path_prefix(moment, prefix) for moment in self.moments),
|
|
1029
|
+
tags=self.tags,
|
|
995
1030
|
)
|
|
996
1031
|
|
|
997
1032
|
def _with_rescoped_keys_(
|
|
@@ -1002,7 +1037,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
1002
1037
|
new_moment = protocols.with_rescoped_keys(moment, path, bindable_keys)
|
|
1003
1038
|
moments.append(new_moment)
|
|
1004
1039
|
bindable_keys |= protocols.measurement_key_objs(new_moment)
|
|
1005
|
-
return self._from_moments(moments)
|
|
1040
|
+
return self._from_moments(moments, tags=self.tags)
|
|
1006
1041
|
|
|
1007
1042
|
def _qid_shape_(self) -> tuple[int, ...]:
|
|
1008
1043
|
return self.qid_shape()
|
|
@@ -1300,22 +1335,33 @@ class AbstractCircuit(abc.ABC):
|
|
|
1300
1335
|
return diagram
|
|
1301
1336
|
|
|
1302
1337
|
def _is_parameterized_(self) -> bool:
|
|
1303
|
-
return any(protocols.is_parameterized(op) for op in self.all_operations())
|
|
1338
|
+
return any(protocols.is_parameterized(op) for op in self.all_operations()) or any(
|
|
1339
|
+
protocols.is_parameterized(tag) for tag in self.tags
|
|
1340
|
+
)
|
|
1304
1341
|
|
|
1305
1342
|
def _parameter_names_(self) -> AbstractSet[str]:
|
|
1306
|
-
|
|
1343
|
+
op_params = {name for op in self.all_operations() for name in protocols.parameter_names(op)}
|
|
1344
|
+
tag_params = {name for tag in self.tags for name in protocols.parameter_names(tag)}
|
|
1345
|
+
return op_params | tag_params
|
|
1307
1346
|
|
|
1308
1347
|
def _resolve_parameters_(self, resolver: cirq.ParamResolver, recursive: bool) -> Self:
|
|
1309
1348
|
changed = False
|
|
1310
1349
|
resolved_moments: list[cirq.Moment] = []
|
|
1350
|
+
resolved_tags: list[Hashable] = []
|
|
1311
1351
|
for moment in self:
|
|
1312
1352
|
resolved_moment = protocols.resolve_parameters(moment, resolver, recursive)
|
|
1313
1353
|
if resolved_moment is not moment:
|
|
1314
1354
|
changed = True
|
|
1315
1355
|
resolved_moments.append(resolved_moment)
|
|
1316
|
-
|
|
1356
|
+
for tag in self.tags:
|
|
1357
|
+
resolved_tag = protocols.resolve_parameters(tag, resolver, recursive)
|
|
1358
|
+
if resolved_tag is not tag:
|
|
1359
|
+
changed = True
|
|
1360
|
+
resolved_tags.append(resolved_tag)
|
|
1361
|
+
if changed:
|
|
1362
|
+
return self._from_moments(resolved_moments, tags=resolved_tags)
|
|
1363
|
+
else:
|
|
1317
1364
|
return self # pragma: no cover
|
|
1318
|
-
return self._from_moments(resolved_moments)
|
|
1319
1365
|
|
|
1320
1366
|
def _qasm_(self, args: cirq.QasmArgs | None = None) -> str:
|
|
1321
1367
|
if args is None:
|
|
@@ -1394,11 +1440,13 @@ class AbstractCircuit(abc.ABC):
|
|
|
1394
1440
|
self._to_qasm_output(header, precision, qubit_order).save(file_path)
|
|
1395
1441
|
|
|
1396
1442
|
def _json_dict_(self):
|
|
1397
|
-
|
|
1443
|
+
attribute_names = ['moments', 'tags'] if self.tags else ['moments']
|
|
1444
|
+
ret = protocols.obj_to_dict_helper(self, attribute_names)
|
|
1445
|
+
return ret
|
|
1398
1446
|
|
|
1399
1447
|
@classmethod
|
|
1400
|
-
def _from_json_dict_(cls, moments, **kwargs):
|
|
1401
|
-
return cls(moments, strategy=InsertStrategy.EARLIEST)
|
|
1448
|
+
def _from_json_dict_(cls, moments, tags=(), **kwargs):
|
|
1449
|
+
return cls(moments, tags=tags, strategy=InsertStrategy.EARLIEST)
|
|
1402
1450
|
|
|
1403
1451
|
def zip(
|
|
1404
1452
|
*circuits: cirq.AbstractCircuit, align: cirq.Alignment | str = Alignment.LEFT
|
|
@@ -1462,7 +1510,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
1462
1510
|
if isinstance(align, str):
|
|
1463
1511
|
align = Alignment[align.upper()]
|
|
1464
1512
|
|
|
1465
|
-
result = cirq.Circuit()
|
|
1513
|
+
result = cirq.Circuit(tags=circuits[0].tags if circuits else ())
|
|
1466
1514
|
for k in range(n):
|
|
1467
1515
|
try:
|
|
1468
1516
|
if align == Alignment.LEFT:
|
|
@@ -1531,7 +1579,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
1531
1579
|
for k in range(1, len(circuits)):
|
|
1532
1580
|
offset, n_acc = _concat_ragged_helper(offset, n_acc, buffer, circuits[k].moments, align)
|
|
1533
1581
|
|
|
1534
|
-
return cirq.Circuit(buffer[offset : offset + n_acc])
|
|
1582
|
+
return cirq.Circuit(buffer[offset : offset + n_acc], tags=circuits[0].tags)
|
|
1535
1583
|
|
|
1536
1584
|
def get_independent_qubit_sets(self) -> list[set[cirq.Qid]]:
|
|
1537
1585
|
"""Divide circuit's qubits into independent qubit sets.
|
|
@@ -1610,7 +1658,10 @@ class AbstractCircuit(abc.ABC):
|
|
|
1610
1658
|
# the qubits from one factor belong to a specific independent qubit set.
|
|
1611
1659
|
# This makes it possible to create independent circuits based on these
|
|
1612
1660
|
# moments.
|
|
1613
|
-
return (
|
|
1661
|
+
return (
|
|
1662
|
+
self._from_moments([m[qubits] for m in self.moments], tags=self.tags)
|
|
1663
|
+
for qubits in qubit_factors
|
|
1664
|
+
)
|
|
1614
1665
|
|
|
1615
1666
|
def _control_keys_(self) -> frozenset[cirq.MeasurementKey]:
|
|
1616
1667
|
controls = frozenset(k for op in self.all_operations() for k in protocols.control_keys(op))
|
|
@@ -1753,7 +1804,10 @@ class Circuit(AbstractCircuit):
|
|
|
1753
1804
|
"""
|
|
1754
1805
|
|
|
1755
1806
|
def __init__(
|
|
1756
|
-
self,
|
|
1807
|
+
self,
|
|
1808
|
+
*contents: cirq.OP_TREE,
|
|
1809
|
+
strategy: cirq.InsertStrategy = InsertStrategy.EARLIEST,
|
|
1810
|
+
tags: Sequence[Hashable] = (),
|
|
1757
1811
|
) -> None:
|
|
1758
1812
|
"""Initializes a circuit.
|
|
1759
1813
|
|
|
@@ -1767,9 +1821,14 @@ class Circuit(AbstractCircuit):
|
|
|
1767
1821
|
from `contents`, this determines how the operations are packed
|
|
1768
1822
|
together. This option does not affect later insertions into the
|
|
1769
1823
|
circuit.
|
|
1824
|
+
tags: A sequence of any type of object that is useful to attach metadata
|
|
1825
|
+
to this circuit as long as the type is hashable. If you wish the
|
|
1826
|
+
resulting circuit to be eventually serialized into JSON, you should
|
|
1827
|
+
also restrict the tags to be JSON serializable.
|
|
1770
1828
|
"""
|
|
1771
1829
|
self._placement_cache: _PlacementCache | None = _PlacementCache()
|
|
1772
1830
|
self._moments: list[cirq.Moment] = []
|
|
1831
|
+
self._tags = tuple(tags)
|
|
1773
1832
|
|
|
1774
1833
|
# Implementation note: the following cached properties are set lazily and then
|
|
1775
1834
|
# invalidated and reset to None in `self._mutated()`, which is called any time
|
|
@@ -1803,10 +1862,11 @@ class Circuit(AbstractCircuit):
|
|
|
1803
1862
|
self._placement_cache = None
|
|
1804
1863
|
|
|
1805
1864
|
@classmethod
|
|
1806
|
-
def _from_moments(cls, moments: Iterable[cirq.Moment]) -> Circuit:
|
|
1865
|
+
def _from_moments(cls, moments: Iterable[cirq.Moment], tags: Sequence[Hashable]) -> Circuit:
|
|
1807
1866
|
new_circuit = Circuit()
|
|
1808
1867
|
new_circuit._moments[:] = moments
|
|
1809
1868
|
new_circuit._placement_cache = None
|
|
1869
|
+
new_circuit._tags = tuple(tags)
|
|
1810
1870
|
return new_circuit
|
|
1811
1871
|
|
|
1812
1872
|
def _load_contents_with_earliest_strategy(self, contents: cirq.OP_TREE):
|
|
@@ -1865,7 +1925,7 @@ class Circuit(AbstractCircuit):
|
|
|
1865
1925
|
from cirq.circuits.frozen_circuit import FrozenCircuit
|
|
1866
1926
|
|
|
1867
1927
|
if self._frozen is None:
|
|
1868
|
-
self._frozen = FrozenCircuit._from_moments(self._moments)
|
|
1928
|
+
self._frozen = FrozenCircuit._from_moments(self._moments, tags=self.tags)
|
|
1869
1929
|
return self._frozen
|
|
1870
1930
|
|
|
1871
1931
|
def unfreeze(self, copy: bool = True) -> cirq.Circuit:
|
|
@@ -1894,8 +1954,9 @@ class Circuit(AbstractCircuit):
|
|
|
1894
1954
|
def copy(self) -> Circuit:
|
|
1895
1955
|
"""Return a copy of this circuit."""
|
|
1896
1956
|
copied_circuit = Circuit()
|
|
1897
|
-
copied_circuit._moments = self._moments
|
|
1957
|
+
copied_circuit._moments[:] = self._moments
|
|
1898
1958
|
copied_circuit._placement_cache = None
|
|
1959
|
+
copied_circuit._tags = self.tags
|
|
1899
1960
|
return copied_circuit
|
|
1900
1961
|
|
|
1901
1962
|
@overload
|
|
@@ -1955,7 +2016,7 @@ class Circuit(AbstractCircuit):
|
|
|
1955
2016
|
def __mul__(self, repetitions: _INT_TYPE):
|
|
1956
2017
|
if not isinstance(repetitions, (int, np.integer)):
|
|
1957
2018
|
return NotImplemented
|
|
1958
|
-
return Circuit(self._moments * int(repetitions))
|
|
2019
|
+
return Circuit(self._moments * int(repetitions), tags=self.tags)
|
|
1959
2020
|
|
|
1960
2021
|
def __rmul__(self, repetitions: _INT_TYPE):
|
|
1961
2022
|
if not isinstance(repetitions, (int, np.integer)):
|
|
@@ -1981,7 +2042,7 @@ class Circuit(AbstractCircuit):
|
|
|
1981
2042
|
return NotImplemented
|
|
1982
2043
|
inv_moments.append(inv_moment)
|
|
1983
2044
|
|
|
1984
|
-
return cirq.Circuit(inv_moments)
|
|
2045
|
+
return cirq.Circuit(inv_moments, tags=self.tags)
|
|
1985
2046
|
|
|
1986
2047
|
__hash__ = None # type: ignore
|
|
1987
2048
|
|
|
@@ -2466,6 +2527,18 @@ class Circuit(AbstractCircuit):
|
|
|
2466
2527
|
def moments(self) -> Sequence[cirq.Moment]:
|
|
2467
2528
|
return self._moments
|
|
2468
2529
|
|
|
2530
|
+
@property
|
|
2531
|
+
def tags(self) -> tuple[Hashable, ...]:
|
|
2532
|
+
return self._tags
|
|
2533
|
+
|
|
2534
|
+
def with_tags(self, *new_tags: Hashable) -> cirq.Circuit:
|
|
2535
|
+
"""Creates a new tagged `Circuit` with `self.tags` and `new_tags` combined."""
|
|
2536
|
+
if not new_tags:
|
|
2537
|
+
return self
|
|
2538
|
+
new_circuit = Circuit(tags=self.tags + new_tags)
|
|
2539
|
+
new_circuit._moments[:] = self._moments
|
|
2540
|
+
return new_circuit
|
|
2541
|
+
|
|
2469
2542
|
def with_noise(self, noise: cirq.NOISE_MODEL_LIKE) -> cirq.Circuit:
|
|
2470
2543
|
"""Make a noisy version of the circuit.
|
|
2471
2544
|
|
|
@@ -2480,7 +2553,7 @@ class Circuit(AbstractCircuit):
|
|
|
2480
2553
|
"""
|
|
2481
2554
|
noise_model = devices.NoiseModel.from_noise_model_like(noise)
|
|
2482
2555
|
qubits = sorted(self.all_qubits())
|
|
2483
|
-
c_noisy = Circuit()
|
|
2556
|
+
c_noisy = Circuit(tags=self.tags)
|
|
2484
2557
|
for op_tree in noise_model.noisy_moments(self, qubits):
|
|
2485
2558
|
# Keep moments aligned
|
|
2486
2559
|
c_noisy += Circuit(op_tree)
|
cirq/circuits/circuit_test.py
CHANGED
|
@@ -4919,3 +4919,52 @@ def test_append_speed() -> None:
|
|
|
4919
4919
|
duration = time.perf_counter() - t
|
|
4920
4920
|
assert len(c) == moments
|
|
4921
4921
|
assert duration < 5
|
|
4922
|
+
|
|
4923
|
+
|
|
4924
|
+
def test_tagged_circuits() -> None:
|
|
4925
|
+
q = cirq.LineQubit(0)
|
|
4926
|
+
ops = [cirq.X(q), cirq.H(q)]
|
|
4927
|
+
tags = (sympy.Symbol("a"), "b")
|
|
4928
|
+
circuit = cirq.Circuit(ops)
|
|
4929
|
+
tagged_circuit = cirq.Circuit(ops, tags=tags)
|
|
4930
|
+
# Test equality
|
|
4931
|
+
assert tagged_circuit.tags == tags
|
|
4932
|
+
assert circuit != tagged_circuit
|
|
4933
|
+
assert not cirq.approx_eq(circuit, tagged_circuit)
|
|
4934
|
+
# Test _repr_ and _json_ round trips.
|
|
4935
|
+
cirq.testing.assert_equivalent_repr(tagged_circuit)
|
|
4936
|
+
cirq.testing.assert_json_roundtrip_works(tagged_circuit)
|
|
4937
|
+
# Test utility methods and constructors
|
|
4938
|
+
assert tagged_circuit.with_tags() is tagged_circuit
|
|
4939
|
+
assert circuit.with_tags(*tags) == tagged_circuit
|
|
4940
|
+
assert tagged_circuit.with_tags("c") == cirq.Circuit(ops, tags=[*tags, "c"])
|
|
4941
|
+
assert tagged_circuit.untagged == circuit
|
|
4942
|
+
assert circuit.untagged is circuit
|
|
4943
|
+
assert tagged_circuit.freeze().tags == tags
|
|
4944
|
+
assert tagged_circuit.unfreeze(copy=True).tags == tags
|
|
4945
|
+
assert tagged_circuit.unfreeze(copy=False).tags == tags
|
|
4946
|
+
# Test parameterized protocols
|
|
4947
|
+
assert cirq.is_parameterized(circuit) is False
|
|
4948
|
+
assert cirq.is_parameterized(tagged_circuit) is True
|
|
4949
|
+
assert cirq.parameter_names(tagged_circuit) == {"a"}
|
|
4950
|
+
assert cirq.resolve_parameters(tagged_circuit, {"a": 1}).tags == (1, "b")
|
|
4951
|
+
# Tags are not propagated to diagrams yet.
|
|
4952
|
+
assert str(circuit) == str(tagged_circuit)
|
|
4953
|
+
# Test tags are preserved through operations
|
|
4954
|
+
assert (tagged_circuit + circuit).tags == tags
|
|
4955
|
+
assert (circuit + tagged_circuit).tags == () # We only preserve the tags for the first one
|
|
4956
|
+
assert (2 * tagged_circuit).tags == tags
|
|
4957
|
+
assert (tagged_circuit * 2).tags == tags
|
|
4958
|
+
assert (tagged_circuit**-1).tags == tags
|
|
4959
|
+
assert tagged_circuit.with_noise(cirq.X).tags == tags
|
|
4960
|
+
for c in tagged_circuit.factorize():
|
|
4961
|
+
assert tagged_circuit.tags == tags
|
|
4962
|
+
|
|
4963
|
+
q2 = cirq.LineQubit(1)
|
|
4964
|
+
circuit2 = cirq.Circuit(cirq.X(q2), cirq.H(q2))
|
|
4965
|
+
assert tagged_circuit.zip(circuit2).tags == tags
|
|
4966
|
+
assert circuit2.zip(tagged_circuit).tags == () # We only preserve the tags for the first one
|
|
4967
|
+
assert tagged_circuit.concat_ragged(circuit2).tags == tags
|
|
4968
|
+
assert (
|
|
4969
|
+
circuit2.concat_ragged(tagged_circuit).tags == ()
|
|
4970
|
+
) # We only preserve the tags for the first one
|
cirq/circuits/frozen_circuit.py
CHANGED
|
@@ -65,9 +65,12 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
|
|
|
65
65
|
self._tags = tuple(tags)
|
|
66
66
|
|
|
67
67
|
@classmethod
|
|
68
|
-
def _from_moments(
|
|
68
|
+
def _from_moments(
|
|
69
|
+
cls, moments: Iterable[cirq.Moment], tags: Sequence[Hashable]
|
|
70
|
+
) -> FrozenCircuit:
|
|
69
71
|
new_circuit = FrozenCircuit()
|
|
70
72
|
new_circuit._moments = tuple(moments)
|
|
73
|
+
new_circuit._tags = tuple(tags)
|
|
71
74
|
return new_circuit
|
|
72
75
|
|
|
73
76
|
@property
|
|
@@ -78,7 +81,7 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
|
|
|
78
81
|
return self
|
|
79
82
|
|
|
80
83
|
def unfreeze(self, copy: bool = True) -> cirq.Circuit:
|
|
81
|
-
return Circuit._from_moments(self._moments)
|
|
84
|
+
return Circuit._from_moments(self._moments, tags=self.tags)
|
|
82
85
|
|
|
83
86
|
@property
|
|
84
87
|
def tags(self) -> tuple[Hashable, ...]:
|
|
@@ -87,8 +90,7 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
|
|
|
87
90
|
|
|
88
91
|
@cached_property
|
|
89
92
|
def untagged(self) -> cirq.FrozenCircuit:
|
|
90
|
-
|
|
91
|
-
return self._from_moments(self._moments) if self.tags else self
|
|
93
|
+
return super().untagged
|
|
92
94
|
|
|
93
95
|
def with_tags(self, *new_tags: Hashable) -> cirq.FrozenCircuit:
|
|
94
96
|
"""Creates a new tagged `FrozenCircuit` with `self.tags` and `new_tags` combined."""
|
|
@@ -103,13 +105,6 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
|
|
|
103
105
|
# Explicitly cached for performance
|
|
104
106
|
return hash((self.moments, self.tags))
|
|
105
107
|
|
|
106
|
-
def __eq__(self, other):
|
|
107
|
-
super_eq = super().__eq__(other)
|
|
108
|
-
if super_eq is not True:
|
|
109
|
-
return super_eq
|
|
110
|
-
other_tags = other.tags if isinstance(other, FrozenCircuit) else ()
|
|
111
|
-
return self.tags == other_tags
|
|
112
|
-
|
|
113
108
|
def __getstate__(self):
|
|
114
109
|
# Don't save hash when pickling; see #3777.
|
|
115
110
|
state = self.__dict__
|
|
@@ -174,23 +169,11 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
|
|
|
174
169
|
|
|
175
170
|
@_compat.cached_method
|
|
176
171
|
def _is_parameterized_(self) -> bool:
|
|
177
|
-
return super()._is_parameterized_()
|
|
178
|
-
protocols.is_parameterized(tag) for tag in self.tags
|
|
179
|
-
)
|
|
172
|
+
return super()._is_parameterized_()
|
|
180
173
|
|
|
181
174
|
@_compat.cached_method
|
|
182
175
|
def _parameter_names_(self) -> AbstractSet[str]:
|
|
183
|
-
|
|
184
|
-
return super()._parameter_names_() | tag_params
|
|
185
|
-
|
|
186
|
-
def _resolve_parameters_(
|
|
187
|
-
self, resolver: cirq.ParamResolver, recursive: bool
|
|
188
|
-
) -> cirq.FrozenCircuit:
|
|
189
|
-
resolved_circuit = super()._resolve_parameters_(resolver, recursive)
|
|
190
|
-
resolved_tags = [
|
|
191
|
-
protocols.resolve_parameters(tag, resolver, recursive) for tag in self.tags
|
|
192
|
-
]
|
|
193
|
-
return resolved_circuit.with_tags(*resolved_tags)
|
|
176
|
+
return super()._parameter_names_()
|
|
194
177
|
|
|
195
178
|
def _measurement_key_names_(self) -> frozenset[str]:
|
|
196
179
|
return self.all_measurement_key_names()
|
|
@@ -217,16 +200,6 @@ class FrozenCircuit(AbstractCircuit, protocols.SerializableByKey):
|
|
|
217
200
|
except:
|
|
218
201
|
return NotImplemented
|
|
219
202
|
|
|
220
|
-
def _repr_args(self) -> str:
|
|
221
|
-
moments_repr = super()._repr_args()
|
|
222
|
-
tag_repr = ','.join(_compat.proper_repr(t) for t in self._tags)
|
|
223
|
-
return f'{moments_repr}, tags=[{tag_repr}]' if self.tags else moments_repr
|
|
224
|
-
|
|
225
|
-
def _json_dict_(self):
|
|
226
|
-
attribute_names = ['moments', 'tags'] if self.tags else ['moments']
|
|
227
|
-
ret = protocols.obj_to_dict_helper(self, attribute_names)
|
|
228
|
-
return ret
|
|
229
|
-
|
|
230
203
|
@classmethod
|
|
231
204
|
def _from_json_dict_(cls, moments, *, tags=(), **kwargs):
|
|
232
205
|
return cls(moments, strategy=InsertStrategy.EARLIEST, tags=tags)
|
|
@@ -96,15 +96,15 @@ def test_immutable() -> None:
|
|
|
96
96
|
def test_tagged_circuits() -> None:
|
|
97
97
|
q = cirq.LineQubit(0)
|
|
98
98
|
ops = [cirq.X(q), cirq.H(q)]
|
|
99
|
-
tags =
|
|
99
|
+
tags = (sympy.Symbol("a"), "b")
|
|
100
100
|
circuit = cirq.Circuit(ops)
|
|
101
101
|
frozen_circuit = cirq.FrozenCircuit(ops)
|
|
102
102
|
tagged_circuit = cirq.FrozenCircuit(ops, tags=tags)
|
|
103
103
|
# Test equality
|
|
104
|
-
assert tagged_circuit.tags ==
|
|
104
|
+
assert tagged_circuit.tags == tags
|
|
105
105
|
assert circuit == frozen_circuit != tagged_circuit
|
|
106
|
+
assert not cirq.approx_eq(frozen_circuit, tagged_circuit)
|
|
106
107
|
assert cirq.approx_eq(circuit, frozen_circuit)
|
|
107
|
-
assert cirq.approx_eq(frozen_circuit, tagged_circuit)
|
|
108
108
|
# Test hash
|
|
109
109
|
assert hash(frozen_circuit) != hash(tagged_circuit)
|
|
110
110
|
# Test _repr_ and _json_ round trips.
|
|
@@ -116,9 +116,29 @@ def test_tagged_circuits() -> None:
|
|
|
116
116
|
assert tagged_circuit.with_tags("c") == cirq.FrozenCircuit(ops, tags=[*tags, "c"])
|
|
117
117
|
assert tagged_circuit.untagged == frozen_circuit
|
|
118
118
|
assert frozen_circuit.untagged is frozen_circuit
|
|
119
|
+
assert tagged_circuit.unfreeze(copy=True).tags == tags
|
|
120
|
+
assert tagged_circuit.unfreeze(copy=False).tags == tags
|
|
119
121
|
# Test parameterized protocols
|
|
120
122
|
assert cirq.is_parameterized(frozen_circuit) is False
|
|
121
123
|
assert cirq.is_parameterized(tagged_circuit) is True
|
|
122
124
|
assert cirq.parameter_names(tagged_circuit) == {"a"}
|
|
125
|
+
assert cirq.resolve_parameters(tagged_circuit, {"a": 1}).tags == (1, "b")
|
|
123
126
|
# Tags are not propagated to diagrams yet.
|
|
124
127
|
assert str(frozen_circuit) == str(tagged_circuit)
|
|
128
|
+
# Test tags are preserved through operations
|
|
129
|
+
assert (tagged_circuit + circuit).tags == tags
|
|
130
|
+
assert (circuit + tagged_circuit).tags == () # We only preserve the tags for the first one
|
|
131
|
+
assert (2 * tagged_circuit).tags == tags
|
|
132
|
+
assert (tagged_circuit * 2).tags == tags
|
|
133
|
+
assert (tagged_circuit**-1).tags == tags
|
|
134
|
+
for c in tagged_circuit.factorize():
|
|
135
|
+
assert tagged_circuit.tags == tags
|
|
136
|
+
|
|
137
|
+
q2 = cirq.LineQubit(1)
|
|
138
|
+
circuit2 = cirq.Circuit(cirq.X(q2), cirq.H(q2))
|
|
139
|
+
assert tagged_circuit.zip(circuit2).tags == tags
|
|
140
|
+
assert circuit2.zip(tagged_circuit).tags == () # We only preserve the tags for the first one
|
|
141
|
+
assert tagged_circuit.concat_ragged(circuit2).tags == tags
|
|
142
|
+
assert (
|
|
143
|
+
circuit2.concat_ragged(tagged_circuit).tags == ()
|
|
144
|
+
) # We only preserve the tags for the first one
|
{cirq_core-1.6.0.dev20250709210336.dist-info → cirq_core-1.6.0.dev20250710201614.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cirq-core
|
|
3
|
-
Version: 1.6.0.
|
|
3
|
+
Version: 1.6.0.dev20250710201614
|
|
4
4
|
Summary: A framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits.
|
|
5
5
|
Home-page: http://github.com/quantumlib/cirq
|
|
6
6
|
Author: The Cirq Developers
|
{cirq_core-1.6.0.dev20250709210336.dist-info → cirq_core-1.6.0.dev20250710201614.dist-info}/RECORD
RENAMED
|
@@ -4,8 +4,8 @@ cirq/_compat_test.py,sha256=emXpdD5ZvwLRlFAoQB8YatmZyU3b4e9jg6FppMTUhkU,33900
|
|
|
4
4
|
cirq/_doc.py,sha256=BrnoABo1hk5RgB3Cgww4zLHUfiyFny0F1V-tOMCbdaU,2909
|
|
5
5
|
cirq/_import.py,sha256=ixBu4EyGl46Ram2cP3p5eZVEFDW5L2DS-VyTjz4N9iw,8429
|
|
6
6
|
cirq/_import_test.py,sha256=oF4izzOVZLc7NZ0aZHFcGv-r01eiFFt_JORx_x7_D4s,1089
|
|
7
|
-
cirq/_version.py,sha256=
|
|
8
|
-
cirq/_version_test.py,sha256=
|
|
7
|
+
cirq/_version.py,sha256=m4hvsoxwoTZW7nkIKNqyHusG5pkALz-3Xdvl2rSL-1A,1278
|
|
8
|
+
cirq/_version_test.py,sha256=M_J_DJkVg3XLVn4B7SC8WbPAqgWw3TF6OpKiEmr774U,155
|
|
9
9
|
cirq/conftest.py,sha256=wSDKNdIQRDfLnXvOCWD3erheOw8JHRhdfQ53EyTUIXg,1239
|
|
10
10
|
cirq/json_resolver_cache.py,sha256=hYyG53VJeV61X0oukK5ndZYega8lkL2FyaL1m0j6h5M,13556
|
|
11
11
|
cirq/py.typed,sha256=VFSlmh_lNwnaXzwY-ZuW-C2Ws5PkuDoVgBdNCs0jXJE,63
|
|
@@ -16,12 +16,12 @@ cirq/circuits/_box_drawing_character_data.py,sha256=hExbMJHm9LGORhlhNiUvPiHquv4p
|
|
|
16
16
|
cirq/circuits/_box_drawing_character_data_test.py,sha256=GyiNQDtiu_drzEe_y8DOXCFRYDKr2k8KetXN5RVDp18,1668
|
|
17
17
|
cirq/circuits/_bucket_priority_queue.py,sha256=U564r2mou4aZsOlpVYiZCgirqS6mVznG3ESyawBt4gE,6749
|
|
18
18
|
cirq/circuits/_bucket_priority_queue_test.py,sha256=MOby-UKYZQMe2n4KhqkfDCPrz-T_3eBbWDEa0_nadJQ,5627
|
|
19
|
-
cirq/circuits/circuit.py,sha256=
|
|
19
|
+
cirq/circuits/circuit.py,sha256=pdRVuMGfCAjoBn5bh01IBR6EoiB8oOtChX_HvI6vBqk,122669
|
|
20
20
|
cirq/circuits/circuit_operation.py,sha256=Bkmf3rY0QYwS8UC1c1rJpvfbSrQcYVkvSX45Hv059uQ,36302
|
|
21
21
|
cirq/circuits/circuit_operation_test.py,sha256=JqRjSqt--Weceog4CAl4iZW8CNy0qJ_2svUyeAR6D-s,49411
|
|
22
|
-
cirq/circuits/circuit_test.py,sha256=
|
|
23
|
-
cirq/circuits/frozen_circuit.py,sha256=
|
|
24
|
-
cirq/circuits/frozen_circuit_test.py,sha256=
|
|
22
|
+
cirq/circuits/circuit_test.py,sha256=Q1ywfvVp6ThmtkAKTk-5bq0cVKctncL0d1qoWxTL_r4,166579
|
|
23
|
+
cirq/circuits/frozen_circuit.py,sha256=UXwABQqBSnSKqSWmRluQPD09xZU0orSW3b3IHvDqxUw,7903
|
|
24
|
+
cirq/circuits/frozen_circuit_test.py,sha256=1Uk3g9St_nJFmu3IJ5hAcXWJjLfWFUXTCKQU1b0JJrE,5321
|
|
25
25
|
cirq/circuits/insert_strategy.py,sha256=3995vK4U6O9RV4BXMoFl9Tf3ekxIiqxv71IuX80JtYo,3237
|
|
26
26
|
cirq/circuits/insert_strategy_test.py,sha256=pBFgsylgRG1CS1h4JyzZQFP-xvh6fSbgpiZgxXfbpr4,1237
|
|
27
27
|
cirq/circuits/moment.py,sha256=MK8H9YUQ44ofLdM1E_zOrJ4Sh5Ayh4ezDtwZkx1O-1E,28363
|
|
@@ -1220,8 +1220,8 @@ cirq/work/sampler.py,sha256=rxbMWvrhu3gfNSBjZKozw28lLKVvBAS_1EGyPdYe8Xg,19041
|
|
|
1220
1220
|
cirq/work/sampler_test.py,sha256=SsMrRvLDYELyOAWLKISjkdEfrBwLYWRsT6D8WrsLM3Q,13533
|
|
1221
1221
|
cirq/work/zeros_sampler.py,sha256=Fs2JWwq0n9zv7_G5Rm-9vPeHUag7uctcMOHg0JTkZpc,2371
|
|
1222
1222
|
cirq/work/zeros_sampler_test.py,sha256=lQLgQDGBLtfImryys2HzQ2jOSGxHgc7-koVBUhv8qYk,3345
|
|
1223
|
-
cirq_core-1.6.0.
|
|
1224
|
-
cirq_core-1.6.0.
|
|
1225
|
-
cirq_core-1.6.0.
|
|
1226
|
-
cirq_core-1.6.0.
|
|
1227
|
-
cirq_core-1.6.0.
|
|
1223
|
+
cirq_core-1.6.0.dev20250710201614.dist-info/licenses/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
|
1224
|
+
cirq_core-1.6.0.dev20250710201614.dist-info/METADATA,sha256=dH62aYT8Qf5VpA7jOWI5gAcL9yT-duDKmBy5905yxUg,4857
|
|
1225
|
+
cirq_core-1.6.0.dev20250710201614.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
1226
|
+
cirq_core-1.6.0.dev20250710201614.dist-info/top_level.txt,sha256=Sz9iOxHU0IEMLSFGwiwOCaN2e9K-jFbBbtpPN1hB73g,5
|
|
1227
|
+
cirq_core-1.6.0.dev20250710201614.dist-info/RECORD,,
|
{cirq_core-1.6.0.dev20250709210336.dist-info → cirq_core-1.6.0.dev20250710201614.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|