cirq-core 1.1.0.dev20221219200817__py3-none-any.whl → 1.2.0__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.
Files changed (229) hide show
  1. cirq/__init__.py +8 -0
  2. cirq/_compat.py +29 -4
  3. cirq/_compat_test.py +24 -26
  4. cirq/_version.py +32 -1
  5. cirq/_version_test.py +1 -1
  6. cirq/circuits/_block_diagram_drawer_test.py +4 -3
  7. cirq/circuits/circuit.py +109 -63
  8. cirq/circuits/circuit_operation.py +2 -3
  9. cirq/circuits/circuit_operation_test.py +4 -4
  10. cirq/circuits/circuit_test.py +11 -0
  11. cirq/circuits/frozen_circuit.py +13 -1
  12. cirq/circuits/frozen_circuit_test.py +5 -1
  13. cirq/circuits/moment.py +39 -14
  14. cirq/circuits/moment_test.py +7 -0
  15. cirq/circuits/text_diagram_drawer.py +1 -1
  16. cirq/circuits/text_diagram_drawer_test.py +3 -7
  17. cirq/conftest.py +8 -0
  18. cirq/contrib/acquaintance/bipartite.py +1 -1
  19. cirq/contrib/acquaintance/devices.py +2 -2
  20. cirq/contrib/acquaintance/executor.py +5 -2
  21. cirq/contrib/acquaintance/gates.py +3 -2
  22. cirq/contrib/acquaintance/permutation.py +13 -2
  23. cirq/contrib/acquaintance/testing.py +3 -5
  24. cirq/contrib/paulistring/recombine.py +3 -6
  25. cirq/contrib/qasm_import/_parser.py +17 -21
  26. cirq/contrib/qasm_import/_parser_test.py +30 -45
  27. cirq/contrib/qcircuit/qcircuit_test.py +3 -7
  28. cirq/contrib/quantum_volume/quantum_volume.py +3 -3
  29. cirq/contrib/quimb/mps_simulator.py +1 -1
  30. cirq/contrib/quimb/state_vector.py +2 -0
  31. cirq/contrib/quirk/quirk_gate.py +1 -0
  32. cirq/contrib/svg/svg.py +4 -7
  33. cirq/contrib/svg/svg_test.py +29 -1
  34. cirq/devices/grid_qubit.py +26 -28
  35. cirq/devices/grid_qubit_test.py +21 -5
  36. cirq/devices/line_qubit.py +10 -12
  37. cirq/devices/line_qubit_test.py +9 -2
  38. cirq/devices/named_topologies.py +1 -1
  39. cirq/devices/noise_model.py +4 -1
  40. cirq/devices/superconducting_qubits_noise_properties.py +1 -3
  41. cirq/experiments/n_qubit_tomography.py +1 -1
  42. cirq/experiments/qubit_characterizations.py +2 -2
  43. cirq/experiments/single_qubit_readout_calibration.py +1 -1
  44. cirq/experiments/t2_decay_experiment.py +1 -1
  45. cirq/experiments/xeb_simulation_test.py +2 -2
  46. cirq/interop/quirk/cells/testing.py +1 -1
  47. cirq/json_resolver_cache.py +1 -0
  48. cirq/linalg/__init__.py +2 -0
  49. cirq/linalg/decompositions_test.py +4 -4
  50. cirq/linalg/diagonalize_test.py +5 -6
  51. cirq/linalg/transformations.py +72 -9
  52. cirq/linalg/transformations_test.py +23 -7
  53. cirq/ops/__init__.py +4 -0
  54. cirq/ops/arithmetic_operation.py +4 -6
  55. cirq/ops/classically_controlled_operation.py +10 -3
  56. cirq/ops/clifford_gate.py +1 -7
  57. cirq/ops/common_channels.py +21 -15
  58. cirq/ops/common_gate_families.py +2 -3
  59. cirq/ops/common_gates.py +48 -11
  60. cirq/ops/common_gates_test.py +4 -0
  61. cirq/ops/controlled_gate.py +44 -18
  62. cirq/ops/controlled_operation.py +13 -5
  63. cirq/ops/dense_pauli_string.py +14 -19
  64. cirq/ops/diagonal_gate.py +3 -4
  65. cirq/ops/eigen_gate.py +8 -10
  66. cirq/ops/eigen_gate_test.py +6 -0
  67. cirq/ops/gate_operation.py +11 -6
  68. cirq/ops/gate_operation_test.py +11 -2
  69. cirq/ops/gateset.py +2 -1
  70. cirq/ops/gateset_test.py +38 -5
  71. cirq/ops/global_phase_op.py +28 -2
  72. cirq/ops/global_phase_op_test.py +21 -0
  73. cirq/ops/identity.py +1 -1
  74. cirq/ops/kraus_channel_test.py +2 -2
  75. cirq/ops/linear_combinations.py +7 -6
  76. cirq/ops/linear_combinations_test.py +26 -10
  77. cirq/ops/matrix_gates.py +8 -4
  78. cirq/ops/matrix_gates_test.py +25 -3
  79. cirq/ops/measure_util.py +13 -5
  80. cirq/ops/measure_util_test.py +8 -2
  81. cirq/ops/measurement_gate.py +1 -1
  82. cirq/ops/measurement_gate_test.py +9 -4
  83. cirq/ops/mixed_unitary_channel_test.py +4 -4
  84. cirq/ops/named_qubit.py +2 -4
  85. cirq/ops/parity_gates.py +5 -1
  86. cirq/ops/parity_gates_test.py +6 -0
  87. cirq/ops/pauli_gates.py +9 -9
  88. cirq/ops/pauli_string.py +4 -2
  89. cirq/ops/pauli_string_raw_types.py +4 -11
  90. cirq/ops/pauli_string_test.py +13 -13
  91. cirq/ops/pauli_sum_exponential.py +6 -1
  92. cirq/ops/qubit_manager.py +97 -0
  93. cirq/ops/qubit_manager_test.py +66 -0
  94. cirq/ops/raw_types.py +75 -33
  95. cirq/ops/raw_types_test.py +34 -0
  96. cirq/ops/three_qubit_gates.py +16 -10
  97. cirq/ops/three_qubit_gates_test.py +4 -2
  98. cirq/ops/two_qubit_diagonal_gate.py +3 -3
  99. cirq/ops/wait_gate.py +1 -1
  100. cirq/protocols/__init__.py +1 -0
  101. cirq/protocols/act_on_protocol.py +3 -3
  102. cirq/protocols/act_on_protocol_test.py +5 -5
  103. cirq/protocols/apply_channel_protocol.py +9 -8
  104. cirq/protocols/apply_mixture_protocol.py +8 -8
  105. cirq/protocols/apply_mixture_protocol_test.py +1 -1
  106. cirq/protocols/apply_unitary_protocol.py +66 -19
  107. cirq/protocols/apply_unitary_protocol_test.py +50 -0
  108. cirq/protocols/circuit_diagram_info_protocol.py +7 -9
  109. cirq/protocols/decompose_protocol.py +167 -125
  110. cirq/protocols/decompose_protocol_test.py +132 -2
  111. cirq/protocols/has_stabilizer_effect_protocol.py +2 -1
  112. cirq/protocols/inverse_protocol.py +2 -2
  113. cirq/protocols/json_serialization_test.py +3 -3
  114. cirq/protocols/json_test_data/Linspace.json +20 -7
  115. cirq/protocols/json_test_data/Linspace.repr +4 -1
  116. cirq/protocols/json_test_data/Points.json +19 -8
  117. cirq/protocols/json_test_data/Points.repr +4 -1
  118. cirq/protocols/json_test_data/Result.repr_inward +1 -1
  119. cirq/protocols/json_test_data/ResultDict.repr +1 -1
  120. cirq/protocols/json_test_data/ResultDict.repr_inward +1 -1
  121. cirq/protocols/json_test_data/TrialResult.repr_inward +1 -1
  122. cirq/protocols/json_test_data/XPowGate.json +13 -5
  123. cirq/protocols/json_test_data/XPowGate.repr +1 -1
  124. cirq/protocols/json_test_data/ZPowGate.json +13 -5
  125. cirq/protocols/json_test_data/ZPowGate.repr +1 -1
  126. cirq/protocols/json_test_data/ZipLongest.json +19 -0
  127. cirq/protocols/json_test_data/ZipLongest.repr +1 -0
  128. cirq/protocols/json_test_data/spec.py +1 -0
  129. cirq/protocols/kraus_protocol.py +3 -4
  130. cirq/protocols/measurement_key_protocol.py +3 -1
  131. cirq/protocols/mixture_protocol.py +3 -2
  132. cirq/protocols/phase_protocol.py +3 -3
  133. cirq/protocols/pow_protocol.py +1 -2
  134. cirq/protocols/qasm.py +4 -4
  135. cirq/protocols/qid_shape_protocol.py +8 -8
  136. cirq/protocols/resolve_parameters.py +8 -3
  137. cirq/protocols/resolve_parameters_test.py +3 -3
  138. cirq/protocols/unitary_protocol.py +19 -11
  139. cirq/protocols/unitary_protocol_test.py +37 -0
  140. cirq/qis/channels.py +1 -1
  141. cirq/qis/clifford_tableau.py +4 -5
  142. cirq/qis/quantum_state_representation.py +7 -9
  143. cirq/qis/states.py +21 -13
  144. cirq/qis/states_test.py +7 -0
  145. cirq/sim/clifford/clifford_simulator.py +3 -3
  146. cirq/sim/density_matrix_simulation_state.py +2 -1
  147. cirq/sim/density_matrix_simulator.py +1 -1
  148. cirq/sim/density_matrix_simulator_test.py +9 -5
  149. cirq/sim/density_matrix_utils.py +7 -32
  150. cirq/sim/mux.py +2 -2
  151. cirq/sim/simulation_state.py +58 -18
  152. cirq/sim/simulation_state_base.py +5 -2
  153. cirq/sim/simulation_state_test.py +121 -9
  154. cirq/sim/simulation_utils.py +59 -0
  155. cirq/sim/simulation_utils_test.py +32 -0
  156. cirq/sim/simulator.py +2 -1
  157. cirq/sim/simulator_base_test.py +3 -3
  158. cirq/sim/sparse_simulator.py +1 -1
  159. cirq/sim/sparse_simulator_test.py +5 -5
  160. cirq/sim/state_vector.py +7 -36
  161. cirq/sim/state_vector_simulation_state.py +18 -1
  162. cirq/sim/state_vector_simulator.py +3 -2
  163. cirq/sim/state_vector_simulator_test.py +24 -2
  164. cirq/sim/state_vector_test.py +46 -15
  165. cirq/study/__init__.py +1 -0
  166. cirq/study/flatten_expressions.py +2 -2
  167. cirq/study/resolver.py +2 -0
  168. cirq/study/resolver_test.py +1 -1
  169. cirq/study/result.py +1 -1
  170. cirq/study/sweeps.py +103 -9
  171. cirq/study/sweeps_test.py +64 -0
  172. cirq/testing/__init__.py +4 -0
  173. cirq/testing/circuit_compare.py +15 -18
  174. cirq/testing/consistent_act_on.py +4 -4
  175. cirq/testing/consistent_controlled_gate_op_test.py +1 -1
  176. cirq/testing/consistent_decomposition.py +11 -2
  177. cirq/testing/consistent_decomposition_test.py +8 -1
  178. cirq/testing/consistent_protocols.py +2 -0
  179. cirq/testing/consistent_protocols_test.py +8 -4
  180. cirq/testing/consistent_qasm.py +8 -15
  181. cirq/testing/consistent_specified_has_unitary.py +1 -1
  182. cirq/testing/consistent_unitary.py +85 -0
  183. cirq/testing/consistent_unitary_test.py +96 -0
  184. cirq/testing/equivalent_repr_eval.py +10 -10
  185. cirq/testing/json.py +3 -3
  186. cirq/testing/logs.py +1 -1
  187. cirq/testing/order_tester.py +4 -5
  188. cirq/testing/random_circuit.py +3 -5
  189. cirq/testing/sample_gates.py +79 -0
  190. cirq/testing/sample_gates_test.py +59 -0
  191. cirq/transformers/__init__.py +2 -0
  192. cirq/transformers/analytical_decompositions/__init__.py +8 -0
  193. cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +130 -0
  194. cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +58 -0
  195. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +230 -0
  196. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +112 -0
  197. cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +1 -3
  198. cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +1 -1
  199. cirq/transformers/expand_composite.py +1 -1
  200. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +4 -4
  201. cirq/transformers/measurement_transformers.py +4 -4
  202. cirq/transformers/merge_single_qubit_gates.py +17 -4
  203. cirq/transformers/routing/route_circuit_cqc.py +2 -2
  204. cirq/transformers/stratify.py +125 -62
  205. cirq/transformers/stratify_test.py +20 -16
  206. cirq/transformers/transformer_api.py +1 -1
  207. cirq/transformers/transformer_primitives.py +3 -2
  208. cirq/transformers/transformer_primitives_test.py +11 -0
  209. cirq/value/abc_alt.py +3 -2
  210. cirq/value/abc_alt_test.py +1 -0
  211. cirq/value/classical_data.py +10 -10
  212. cirq/value/digits.py +2 -2
  213. cirq/value/linear_dict.py +18 -19
  214. cirq/value/product_state.py +7 -6
  215. cirq/value/value_equality_attr.py +2 -2
  216. cirq/vis/heatmap.py +1 -1
  217. cirq/vis/heatmap_test.py +2 -2
  218. cirq/work/collector.py +2 -2
  219. cirq/work/observable_measurement_data.py +5 -5
  220. cirq/work/observable_readout_calibration.py +3 -1
  221. cirq/work/observable_settings.py +1 -1
  222. cirq/work/pauli_sum_collector.py +9 -8
  223. cirq/work/sampler.py +2 -0
  224. cirq/work/zeros_sampler.py +2 -2
  225. {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/METADATA +7 -15
  226. {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/RECORD +229 -215
  227. {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/WHEEL +1 -1
  228. {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/LICENSE +0 -0
  229. {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/top_level.txt +0 -0
cirq/__init__.py CHANGED
@@ -16,6 +16,8 @@
16
16
 
17
17
  from cirq import _import
18
18
 
19
+ from cirq._compat import __cirq_debug__, with_debug
20
+
19
21
  # A module can only depend on modules imported earlier in this list of modules
20
22
  # at import time. Pytest will fail otherwise (enforced by
21
23
  # dev_tools/import_test.py).
@@ -236,6 +238,7 @@ from cirq.ops import (
236
238
  LinearCombinationOfOperations,
237
239
  MatrixGate,
238
240
  MixedUnitaryChannel,
241
+ M,
239
242
  measure,
240
243
  measure_each,
241
244
  measure_paulistring_terms,
@@ -281,9 +284,11 @@ from cirq.ops import (
281
284
  qft,
282
285
  Qid,
283
286
  QuantumFourierTransformGate,
287
+ QubitManager,
284
288
  QubitOrder,
285
289
  QubitOrderOrList,
286
290
  QubitPermutationGate,
291
+ R,
287
292
  reset,
288
293
  reset_each,
289
294
  ResetChannel,
@@ -366,6 +371,7 @@ from cirq.transformers import (
366
371
  parameterized_2q_op_to_sqrt_iswap_operations,
367
372
  prepare_two_qubit_state_using_cz,
368
373
  prepare_two_qubit_state_using_sqrt_iswap,
374
+ quantum_shannon_decomposition,
369
375
  RouteCQC,
370
376
  routed_circuit_with_mapping,
371
377
  SqrtIswapTargetGateset,
@@ -498,6 +504,7 @@ from cirq.study import (
498
504
  Result,
499
505
  UnitSweep,
500
506
  Zip,
507
+ ZipLongest,
501
508
  )
502
509
 
503
510
  from cirq.value import (
@@ -561,6 +568,7 @@ from cirq.protocols import (
561
568
  decompose,
562
569
  decompose_once,
563
570
  decompose_once_with_qubits,
571
+ DecompositionContext,
564
572
  DEFAULT_RESOLVERS,
565
573
  definitely_commutes,
566
574
  equal_up_to_global_phase,
cirq/_compat.py CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  """Workarounds for compatibility issues between versions and libraries."""
16
16
  import contextlib
17
+ import contextvars
17
18
  import dataclasses
18
19
  import functools
19
20
  import importlib
@@ -24,15 +25,41 @@ import sys
24
25
  import traceback
25
26
  import warnings
26
27
  from types import ModuleType
27
- from typing import Any, Callable, Dict, Optional, overload, Set, Tuple, Type, TypeVar
28
+ from typing import Any, Callable, Dict, Iterator, Optional, overload, Set, Tuple, Type, TypeVar
28
29
 
29
30
  import numpy as np
30
31
  import pandas as pd
31
32
  import sympy
32
33
  import sympy.printing.repr
33
34
 
35
+ from cirq._doc import document
36
+
34
37
  ALLOW_DEPRECATION_IN_TEST = 'ALLOW_DEPRECATION_IN_TEST'
35
38
 
39
+ __cirq_debug__ = contextvars.ContextVar('__cirq_debug__', default=__debug__)
40
+ document(
41
+ __cirq_debug__,
42
+ "A cirq specific flag which can be used to conditionally turn off all validations across Cirq "
43
+ "to boost performance in production mode. Defaults to python's built-in constant __debug__. "
44
+ "The flag is implemented as a `ContextVar` and is thread safe.",
45
+ )
46
+
47
+
48
+ @contextlib.contextmanager
49
+ def with_debug(value: bool) -> Iterator[None]:
50
+ """Sets the value of global constant `cirq.__cirq_debug__` within the context.
51
+
52
+ If `__cirq_debug__` is set to False, all validations in Cirq are disabled to optimize
53
+ performance. Users should use the `cirq.with_debug` context manager instead of manually
54
+ mutating the value of `__cirq_debug__` flag. On exit, the context manager resets the
55
+ value of `__cirq_debug__` flag to what it was before entering the context manager.
56
+ """
57
+ token = __cirq_debug__.set(value)
58
+ try:
59
+ yield
60
+ finally:
61
+ __cirq_debug__.reset(token)
62
+
36
63
 
37
64
  try:
38
65
  from functools import cached_property # pylint: disable=unused-import
@@ -138,9 +165,7 @@ def proper_repr(value: Any) -> str:
138
165
  return Printer().doprint(value)
139
166
 
140
167
  if isinstance(value, np.ndarray):
141
- if np.issubdtype(value.dtype, np.datetime64):
142
- return f'np.array({value.tolist()!r}, dtype=np.{value.dtype!r})'
143
- return f'np.array({value.tolist()!r}, dtype=np.{value.dtype})'
168
+ return f'np.array({value.tolist()!r}, dtype=np.{value.dtype!r})'
144
169
 
145
170
  if isinstance(value, pd.MultiIndex):
146
171
  return f'pd.MultiIndex.from_tuples({repr(list(value))}, names={repr(list(value.names))})'
cirq/_compat_test.py CHANGED
@@ -13,7 +13,7 @@
13
13
  # limitations under the License.
14
14
  import collections
15
15
  import dataclasses
16
- import importlib
16
+ import importlib.metadata
17
17
  import logging
18
18
  import multiprocessing
19
19
  import os
@@ -51,6 +51,16 @@ from cirq._compat import (
51
51
  )
52
52
 
53
53
 
54
+ def test_with_debug():
55
+ assert cirq.__cirq_debug__.get()
56
+ with cirq.with_debug(False):
57
+ assert not cirq.__cirq_debug__.get()
58
+ with cirq.with_debug(True):
59
+ assert cirq.__cirq_debug__.get()
60
+ assert not cirq.__cirq_debug__.get()
61
+ assert cirq.__cirq_debug__.get()
62
+
63
+
54
64
  def test_proper_repr():
55
65
  v = sympy.Symbol('t') * 3
56
66
  v2 = eval(proper_repr(v))
@@ -88,7 +98,7 @@ def test_proper_repr_data_frame():
88
98
  pd.testing.assert_frame_equal(df2, df)
89
99
 
90
100
 
91
- def test_dataclass_repr_simple():
101
+ def test_dataclass_repr_simple() -> None:
92
102
  @dataclasses.dataclass
93
103
  class TestClass1:
94
104
  x: int
@@ -101,7 +111,7 @@ def test_dataclass_repr_simple():
101
111
  assert repr(TestClass1(5, 'hi')) == "cirq.TestClass1(x=5, y='hi')"
102
112
 
103
113
 
104
- def test_dataclass_repr_numpy():
114
+ def test_dataclass_repr_numpy() -> None:
105
115
  @dataclasses.dataclass
106
116
  class TestClass2:
107
117
  x: np.ndarray
@@ -110,7 +120,10 @@ def test_dataclass_repr_numpy():
110
120
  return dataclass_repr(self, namespace='cirq.testing')
111
121
 
112
122
  tc = TestClass2(np.ones(3))
113
- assert repr(tc) == "cirq.testing.TestClass2(x=np.array([1.0, 1.0, 1.0], dtype=np.float64))"
123
+ assert (
124
+ repr(tc)
125
+ == "cirq.testing.TestClass2(x=np.array([1.0, 1.0, 1.0], dtype=np.dtype('float64')))"
126
+ )
114
127
 
115
128
 
116
129
  def test_proper_eq():
@@ -187,9 +200,8 @@ def test_deprecated():
187
200
 
188
201
  with pytest.raises(AssertionError, match='deadline should match vX.Y'):
189
202
  # pylint: disable=unused-variable
190
- # coverage: ignore
191
203
  @deprecated(deadline='invalid', fix='Roll some dice.')
192
- def badly_deprecated_func(*args, **kwargs):
204
+ def badly_deprecated_func(*args, **kwargs): # pragma: no cover
193
205
  return new_func(*args, **kwargs)
194
206
 
195
207
  # pylint: enable=unused-variable
@@ -245,8 +257,7 @@ def test_deprecated_parameter():
245
257
  rewrite=lambda args, kwargs: (args, {'new_count': kwargs['double_count'] * 2}),
246
258
  )
247
259
  # pylint: disable=unused-variable
248
- # coverage: ignore
249
- def f_with_badly_deprecated_param(new_count):
260
+ def f_with_badly_deprecated_param(new_count): # pragma: no cover
250
261
  return new_count
251
262
 
252
263
  # pylint: enable=unused-variable
@@ -358,9 +369,8 @@ def test_deprecated_class():
358
369
 
359
370
  with pytest.raises(AssertionError, match='deadline should match vX.Y'):
360
371
  # pylint: disable=unused-variable
361
- # coverage: ignore
362
372
  @deprecated_class(deadline='invalid', fix='theFix', name='foo')
363
- class BadlyDeprecatedClass(NewClass):
373
+ class BadlyDeprecatedClass(NewClass): # pragma: no cover
364
374
  ...
365
375
 
366
376
  # pylint: enable=unused-variable
@@ -606,8 +616,6 @@ def subprocess_context(test_func):
606
616
  "it to this method?"
607
617
  )
608
618
 
609
- import os
610
-
611
619
  ctx = multiprocessing.get_context('spawn' if os.name == 'nt' else 'fork')
612
620
 
613
621
  exception = ctx.Queue()
@@ -619,8 +627,7 @@ def subprocess_context(test_func):
619
627
  p.start()
620
628
  p.join()
621
629
  result = exception.get()
622
- if result:
623
- # coverage: ignore
630
+ if result: # pragma: no cover
624
631
  ex_type, msg, ex_trace = result
625
632
  if ex_type == "Skipped":
626
633
  warnings.warn(f"Skipping: {ex_type}: {msg}\n{ex_trace}")
@@ -709,21 +716,12 @@ def test_metadata_search_path():
709
716
  subprocess_context(_test_metadata_search_path_inner)()
710
717
 
711
718
 
712
- def _test_metadata_search_path_inner():
719
+ def _test_metadata_search_path_inner(): # pragma: no cover
713
720
  # initialize the DeprecatedModuleFinders
714
721
  # pylint: disable=unused-import
715
722
  import cirq.testing._compat_test_data.module_a
716
723
 
717
- try:
718
- # importlib.metadata for python 3.8+
719
- # coverage: ignore
720
- import importlib.metadata as m
721
- except: # coverage: ignore
722
- # coverage: ignore
723
- # importlib_metadata for python <3.8
724
- m = pytest.importorskip("importlib_metadata")
725
-
726
- assert m.metadata('flynt')
724
+ assert importlib.metadata.metadata('numpy')
727
725
 
728
726
 
729
727
  def test_metadata_distributions_after_deprecated_submodule():
@@ -990,7 +988,7 @@ def test_cached_property():
990
988
 
991
989
 
992
990
  class Bar:
993
- def __init__(self):
991
+ def __init__(self) -> None:
994
992
  self.foo_calls: Dict[int, int] = collections.Counter()
995
993
  self.bar_calls: Dict[int, int] = collections.Counter()
996
994
 
cirq/_version.py CHANGED
@@ -1 +1,32 @@
1
- __version__ = "1.1.0.dev20221219200817"
1
+ # Copyright 2018 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Define version number here, read it from setup.py automatically,
16
+ and warn users that the latest version of cirq uses python 3.9+"""
17
+
18
+ import sys
19
+
20
+ if sys.version_info < (3, 9, 0):
21
+ # coverage: ignore
22
+ raise SystemError(
23
+ "You installed the latest version of cirq but aren't on python 3.9+.\n"
24
+ 'To fix this error, you need to either:\n'
25
+ '\n'
26
+ 'A) Update to python 3.9 or later.\n'
27
+ '- OR -\n'
28
+ 'B) Explicitly install an older deprecated-but-compatible version '
29
+ 'of cirq (e.g. "python -m pip install cirq==1.1.*")'
30
+ )
31
+
32
+ __version__ = "1.2.0"
cirq/_version_test.py CHANGED
@@ -3,4 +3,4 @@ import cirq
3
3
 
4
4
 
5
5
  def test_version():
6
- assert cirq.__version__ == "1.1.0.dev"
6
+ assert cirq.__version__ == "1.2.0.dev"
@@ -11,6 +11,7 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+
14
15
  import itertools
15
16
 
16
17
  import pytest
@@ -31,13 +32,13 @@ def _assert_same_diagram(actual: str, expected: str):
31
32
  "Diagram differs from the desired diagram.\n"
32
33
  '\n'
33
34
  'Actual diagram:\n'
34
- '{}\n'
35
+ f'{actual}\n'
35
36
  '\n'
36
37
  'Desired diagram:\n'
37
- '{}\n'
38
+ f'{expected}\n'
38
39
  '\n'
39
40
  'Highlighted differences:\n'
40
- '{}\n'.format(actual, expected, cirq.testing.highlight_text_differences(actual, expected))
41
+ f'{cirq.testing.highlight_text_differences(actual, expected)}\n'
41
42
  )
42
43
 
43
44
 
cirq/circuits/circuit.py CHANGED
@@ -47,6 +47,7 @@ from typing import (
47
47
  TypeVar,
48
48
  Union,
49
49
  )
50
+ from typing_extensions import Self
50
51
 
51
52
  import networkx
52
53
  import numpy as np
@@ -236,15 +237,15 @@ class AbstractCircuit(abc.ABC):
236
237
  pass
237
238
 
238
239
  @overload
239
- def __getitem__(self: CIRCUIT_TYPE, key: slice) -> CIRCUIT_TYPE:
240
+ def __getitem__(self, key: slice) -> Self:
240
241
  pass
241
242
 
242
243
  @overload
243
- def __getitem__(self: CIRCUIT_TYPE, key: Tuple[slice, 'cirq.Qid']) -> CIRCUIT_TYPE:
244
+ def __getitem__(self, key: Tuple[slice, 'cirq.Qid']) -> Self:
244
245
  pass
245
246
 
246
247
  @overload
247
- def __getitem__(self: CIRCUIT_TYPE, key: Tuple[slice, Iterable['cirq.Qid']]) -> CIRCUIT_TYPE:
248
+ def __getitem__(self, key: Tuple[slice, Iterable['cirq.Qid']]) -> Self:
248
249
  pass
249
250
 
250
251
  def __getitem__(self, key):
@@ -305,7 +306,10 @@ class AbstractCircuit(abc.ABC):
305
306
  return None
306
307
 
307
308
  def next_moment_operating_on(
308
- self, qubits: Iterable['cirq.Qid'], start_moment_index: int = 0, max_distance: int = None
309
+ self,
310
+ qubits: Iterable['cirq.Qid'],
311
+ start_moment_index: int = 0,
312
+ max_distance: Optional[int] = None,
309
313
  ) -> Optional[int]:
310
314
  """Finds the index of the next moment that touches the given qubits.
311
315
 
@@ -910,9 +914,7 @@ class AbstractCircuit(abc.ABC):
910
914
  """
911
915
  return (op for moment in self for op in moment.operations)
912
916
 
913
- def map_operations(
914
- self: CIRCUIT_TYPE, func: Callable[['cirq.Operation'], 'cirq.OP_TREE']
915
- ) -> CIRCUIT_TYPE:
917
+ def map_operations(self, func: Callable[['cirq.Operation'], 'cirq.OP_TREE']) -> Self:
916
918
  """Applies the given function to all operations in this circuit.
917
919
 
918
920
  Args:
@@ -1284,9 +1286,7 @@ class AbstractCircuit(abc.ABC):
1284
1286
  def _parameter_names_(self) -> AbstractSet[str]:
1285
1287
  return {name for op in self.all_operations() for name in protocols.parameter_names(op)}
1286
1288
 
1287
- def _resolve_parameters_(
1288
- self: CIRCUIT_TYPE, resolver: 'cirq.ParamResolver', recursive: bool
1289
- ) -> CIRCUIT_TYPE:
1289
+ def _resolve_parameters_(self, resolver: 'cirq.ParamResolver', recursive: bool) -> Self:
1290
1290
  changed = False
1291
1291
  resolved_moments: List['cirq.Moment'] = []
1292
1292
  for moment in self:
@@ -1458,7 +1458,7 @@ class AbstractCircuit(abc.ABC):
1458
1458
  are placed one after the other and then moved inward until just before
1459
1459
  their operations would collide. If any of the circuits do not share
1460
1460
  qubits and so would not collide, the starts or ends of the circuits will
1461
- be aligned, acording to the given align parameter.
1461
+ be aligned, according to the given align parameter.
1462
1462
 
1463
1463
  Beware that this method is *not* associative. For example:
1464
1464
 
@@ -1537,7 +1537,7 @@ class AbstractCircuit(abc.ABC):
1537
1537
  uf.union(*op.qubits)
1538
1538
  return sorted([qs for qs in uf.to_sets()], key=min)
1539
1539
 
1540
- def factorize(self: CIRCUIT_TYPE) -> Iterable[CIRCUIT_TYPE]:
1540
+ def factorize(self) -> Iterable[Self]:
1541
1541
  """Factorize circuit into a sequence of independent circuits (factors).
1542
1542
 
1543
1543
  Factorization is possible when the circuit's qubits can be divided
@@ -1776,12 +1776,10 @@ class Circuit(AbstractCircuit):
1776
1776
  Non-moment entries will be inserted according to the EARLIEST
1777
1777
  insertion strategy.
1778
1778
  """
1779
- # These are dicts from the qubit/key to the greatest moment index that has it. It is safe
1780
- # to default to `-1`, as that is interpreted as meaning the zeroth index onward does not
1781
- # have this value.
1782
- qubit_indexes: Dict['cirq.Qid', int] = defaultdict(lambda: -1)
1783
- mkey_indexes: Dict['cirq.MeasurementKey', int] = defaultdict(lambda: -1)
1784
- ckey_indexes: Dict['cirq.MeasurementKey', int] = defaultdict(lambda: -1)
1779
+ # These are dicts from the qubit/key to the greatest moment index that has it.
1780
+ qubit_indices: Dict['cirq.Qid', int] = {}
1781
+ mkey_indices: Dict['cirq.MeasurementKey', int] = {}
1782
+ ckey_indices: Dict['cirq.MeasurementKey', int] = {}
1785
1783
 
1786
1784
  # We also maintain the dict from moment index to moments/ops that go into it, for use when
1787
1785
  # building the actual moments at the end.
@@ -1793,46 +1791,17 @@ class Circuit(AbstractCircuit):
1793
1791
 
1794
1792
  # "mop" means current moment-or-operation
1795
1793
  for mop in ops.flatten_to_ops_or_moments(contents):
1796
- mop_qubits = mop.qubits
1797
- mop_mkeys = protocols.measurement_key_objs(mop)
1798
- mop_ckeys = protocols.control_keys(mop)
1799
1794
 
1800
- # Both branches define `i`, the moment index at which to place the mop.
1795
+ # Identify the index of the moment to place this `mop` into.
1796
+ placement_index = get_earliest_accommodating_moment_index(
1797
+ mop, qubit_indices, mkey_indices, ckey_indices, length
1798
+ )
1799
+ length = max(length, placement_index + 1) # update the length of the circuit thus far
1800
+
1801
1801
  if isinstance(mop, Moment):
1802
- # We always append moment to the end, to be consistent with `self.append`
1803
- i = length
1804
- moments_by_index[i] = mop
1802
+ moments_by_index[placement_index] = mop
1805
1803
  else:
1806
- # Initially we define `i` as the greatest moment index that has a conflict. `-1` is
1807
- # the initial conflict, and we search for larger ones. Once we get the largest one,
1808
- # we increment i by 1 to set the placement index.
1809
- i = -1
1810
-
1811
- # Look for the maximum conflict; i.e. a moment that has a qubit the same as one of
1812
- # this op's qubits, that has a measurement or control key the same as one of this
1813
- # op's measurement keys, or that has a measurement key the same as one of this op's
1814
- # control keys. (Control keys alone can commute past each other). The `ifs` are
1815
- # logically unnecessary but seem to make this slightly faster.
1816
- if mop_qubits:
1817
- i = max(i, *[qubit_indexes[q] for q in mop_qubits])
1818
- if mop_mkeys:
1819
- i = max(i, *[mkey_indexes[k] for k in mop_mkeys])
1820
- i = max(i, *[ckey_indexes[k] for k in mop_mkeys])
1821
- if mop_ckeys:
1822
- i = max(i, *[mkey_indexes[k] for k in mop_ckeys])
1823
- i += 1
1824
- op_lists_by_index[i].append(mop)
1825
-
1826
- # Update our dicts with data from the latest mop placement. Note `i` will always be
1827
- # greater than the existing value for all of these, by construction, so there is no
1828
- # need to do a `max(i, existing)`.
1829
- for q in mop_qubits:
1830
- qubit_indexes[q] = i
1831
- for k in mop_mkeys:
1832
- mkey_indexes[k] = i
1833
- for k in mop_ckeys:
1834
- ckey_indexes[k] = i
1835
- length = max(length, i + 1)
1804
+ op_lists_by_index[placement_index].append(mop)
1836
1805
 
1837
1806
  # Finally, once everything is placed, we can construct and append the actual moments for
1838
1807
  # each index.
@@ -1861,9 +1830,8 @@ class Circuit(AbstractCircuit):
1861
1830
  pass
1862
1831
 
1863
1832
  def __setitem__(self, key, value):
1864
- if isinstance(key, int):
1865
- if not isinstance(value, Moment):
1866
- raise TypeError('Can only assign Moments into Circuits.')
1833
+ if isinstance(key, int) and not isinstance(value, Moment):
1834
+ raise TypeError('Can only assign Moments into Circuits.')
1867
1835
 
1868
1836
  if isinstance(key, slice):
1869
1837
  value = list(value)
@@ -2160,7 +2128,7 @@ class Circuit(AbstractCircuit):
2160
2128
  self,
2161
2129
  early_frontier: Dict['cirq.Qid', int],
2162
2130
  late_frontier: Dict['cirq.Qid', int],
2163
- update_qubits: Iterable['cirq.Qid'] = None,
2131
+ update_qubits: Optional[Iterable['cirq.Qid']] = None,
2164
2132
  ) -> Tuple[int, int]:
2165
2133
  """Inserts moments to separate two frontiers.
2166
2134
 
@@ -2230,7 +2198,10 @@ class Circuit(AbstractCircuit):
2230
2198
  )
2231
2199
 
2232
2200
  def insert_at_frontier(
2233
- self, operations: 'cirq.OP_TREE', start: int, frontier: Dict['cirq.Qid', int] = None
2201
+ self,
2202
+ operations: 'cirq.OP_TREE',
2203
+ start: int,
2204
+ frontier: Optional[Dict['cirq.Qid', int]] = None,
2234
2205
  ) -> Dict['cirq.Qid', int]:
2235
2206
  """Inserts operations inline at frontier.
2236
2207
 
@@ -2421,7 +2392,9 @@ class Circuit(AbstractCircuit):
2421
2392
 
2422
2393
 
2423
2394
  def _pick_inserted_ops_moment_indices(
2424
- operations: Sequence['cirq.Operation'], start: int = 0, frontier: Dict['cirq.Qid', int] = None
2395
+ operations: Sequence['cirq.Operation'],
2396
+ start: int = 0,
2397
+ frontier: Optional[Dict['cirq.Qid', int]] = None,
2425
2398
  ) -> Tuple[Sequence[int], Dict['cirq.Qid', int]]:
2426
2399
  """Greedily assigns operations to moments.
2427
2400
 
@@ -2595,8 +2568,7 @@ def _get_global_phase_and_tags_for_op(op: 'cirq.Operation') -> Tuple[Optional[co
2595
2568
  elif isinstance(op.untagged, CircuitOperation):
2596
2569
  op_phase, op_tags = _get_global_phase_and_tags_for_ops(op.untagged.circuit.all_operations())
2597
2570
  return op_phase, list(op.tags) + op_tags
2598
- else:
2599
- return None, []
2571
+ return None, []
2600
2572
 
2601
2573
 
2602
2574
  def _get_global_phase_and_tags_for_ops(op_list: Any) -> Tuple[Optional[complex], List[Any]]:
@@ -2755,3 +2727,77 @@ def _group_until_different(items: Iterable[_TIn], key: Callable[[_TIn], _TKey],
2755
2727
  Tuples containing the group key and item values.
2756
2728
  """
2757
2729
  return ((k, [val(i) for i in v]) for (k, v) in itertools.groupby(items, key))
2730
+
2731
+
2732
+ def get_earliest_accommodating_moment_index(
2733
+ moment_or_operation: Union['cirq.Moment', 'cirq.Operation'],
2734
+ qubit_indices: Dict['cirq.Qid', int],
2735
+ mkey_indices: Dict['cirq.MeasurementKey', int],
2736
+ ckey_indices: Dict['cirq.MeasurementKey', int],
2737
+ length: Optional[int] = None,
2738
+ ) -> int:
2739
+ """Get the index of the earliest moment that can accommodate the given moment or operation.
2740
+
2741
+ Updates the dictionaries keeping track of the last moment index addressing a given qubit,
2742
+ measurement key, and control key.
2743
+
2744
+ Args:
2745
+ moment_or_operation: The moment operation in question.
2746
+ qubit_indices: A dictionary mapping qubits to the latest moments that address them.
2747
+ mkey_indices: A dictionary mapping measureent keys to the latest moments that address them.
2748
+ ckey_indices: A dictionary mapping control keys to the latest moments that address them.
2749
+ length: The length of the circuit that we are trying to insert a moment or operation into.
2750
+ Should probably be equal to the maximum of the values in `qubit_indices`,
2751
+ `mkey_indices`, and `ckey_indices`.
2752
+
2753
+ Returns:
2754
+ The integer index of the earliest moment that can accommodate the given moment or operation.
2755
+ """
2756
+ mop_qubits = moment_or_operation.qubits
2757
+ mop_mkeys = protocols.measurement_key_objs(moment_or_operation)
2758
+ mop_ckeys = protocols.control_keys(moment_or_operation)
2759
+
2760
+ if isinstance(moment_or_operation, Moment):
2761
+ # For consistency with `Circuit.append`, moments always get placed at the end of a circuit.
2762
+ if length is not None:
2763
+ last_conflict = length - 1
2764
+ else:
2765
+ last_conflict = max(
2766
+ [*qubit_indices.values(), *mkey_indices.values(), *ckey_indices.values(), -1]
2767
+ )
2768
+
2769
+ else:
2770
+ # We start by searching for the `latest_conflict` moment index, which we will increment by
2771
+ # `1` to identify the earliest moment that *does not* conflict with the given operation.
2772
+ # The `latest_conflict` is initialized to `-1` before searching for later conflicting
2773
+ # moments.
2774
+ last_conflict = -1
2775
+
2776
+ # Look for the maximum conflict; i.e. a moment that has a qubit the same as one of this op's
2777
+ # qubits, that has a measurement or control key the same as one of this op's measurement
2778
+ # keys, or that has a measurement key the same as one of this op's control keys. (Control
2779
+ # keys alone can commute past each other). The `ifs` are logically unnecessary but seem to
2780
+ # make this slightly faster.
2781
+ if mop_qubits:
2782
+ last_conflict = max(
2783
+ last_conflict, *[qubit_indices.get(qubit, -1) for qubit in mop_qubits]
2784
+ )
2785
+ if mop_mkeys:
2786
+ last_conflict = max(last_conflict, *[mkey_indices.get(key, -1) for key in mop_mkeys])
2787
+ last_conflict = max(last_conflict, *[ckey_indices.get(key, -1) for key in mop_mkeys])
2788
+ if mop_ckeys:
2789
+ last_conflict = max(last_conflict, *[mkey_indices.get(key, -1) for key in mop_ckeys])
2790
+
2791
+ # The index of the moment to place this moment or operaton ("mop") into.
2792
+ mop_index = last_conflict + 1
2793
+
2794
+ # Update our dicts with data from this `mop` placement. Note `mop_index` will always be greater
2795
+ # than the existing value for all of these, by construction.
2796
+ for qubit in mop_qubits:
2797
+ qubit_indices[qubit] = mop_index
2798
+ for key in mop_mkeys:
2799
+ mkey_indices[key] = mop_index
2800
+ for key in mop_ckeys:
2801
+ ckey_indices[key] = mop_index
2802
+
2803
+ return mop_index
@@ -11,6 +11,7 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+
14
15
  """A structure for encapsulating entire circuits in an operation.
15
16
 
16
17
  A CircuitOperation is an Operation object that wraps a FrozenCircuit. When
@@ -459,9 +460,7 @@ class CircuitOperation(ops.Operation):
459
460
  # TODO: support out-of-line subcircuit definition in string format.
460
461
  msg_lines = str(self.circuit).split('\n')
461
462
  msg_width = max([len(line) for line in msg_lines])
462
- circuit_msg = '\n'.join(
463
- '[ {line:<{width}} ]'.format(line=line, width=msg_width) for line in msg_lines
464
- )
463
+ circuit_msg = '\n'.join(f'[ {line:<{msg_width}} ]' for line in msg_lines)
465
464
  args = []
466
465
 
467
466
  def dict_str(d: Mapping) -> str:
@@ -274,7 +274,7 @@ def test_recursive_params():
274
274
 
275
275
  @pytest.mark.parametrize('add_measurements', [True, False])
276
276
  @pytest.mark.parametrize('use_default_ids_for_initial_rep', [True, False])
277
- def test_repeat(add_measurements, use_default_ids_for_initial_rep):
277
+ def test_repeat(add_measurements: bool, use_default_ids_for_initial_rep: bool) -> None:
278
278
  a, b = cirq.LineQubit.range(2)
279
279
  circuit = cirq.Circuit(cirq.H(a), cirq.CX(a, b))
280
280
  if add_measurements:
@@ -327,9 +327,9 @@ def test_repeat(add_measurements, use_default_ids_for_initial_rep):
327
327
  _ = op_base.repeat()
328
328
 
329
329
  with pytest.raises(TypeError, match='Only integer or sympy repetitions are allowed'):
330
- _ = op_base.repeat(1.3)
331
- assert op_base.repeat(3.00000000001).repetitions == 3
332
- assert op_base.repeat(2.99999999999).repetitions == 3
330
+ _ = op_base.repeat(1.3) # type: ignore[arg-type]
331
+ assert op_base.repeat(3.00000000001).repetitions == 3 # type: ignore[arg-type]
332
+ assert op_base.repeat(2.99999999999).repetitions == 3 # type: ignore[arg-type]
333
333
 
334
334
 
335
335
  @pytest.mark.parametrize('add_measurements', [True, False])
@@ -834,6 +834,17 @@ def test_insert_moment():
834
834
  assert c.operation_at(qubit, actual_index) == operation[0]
835
835
 
836
836
 
837
+ def test_circuit_length_inference():
838
+ # tests that `get_earliest_accommodating_moment_index` properly computes circuit length
839
+ circuit = cirq.Circuit(cirq.X(cirq.q(0)))
840
+ qubit_indices = {cirq.q(0): 0}
841
+ mkey_indices = {}
842
+ ckey_indices = {}
843
+ assert circuits.circuit.get_earliest_accommodating_moment_index(
844
+ cirq.Moment(), qubit_indices, mkey_indices, ckey_indices
845
+ ) == len(circuit)
846
+
847
+
837
848
  def test_insert_inline_near_start():
838
849
  a = cirq.NamedQubit('a')
839
850
  b = cirq.NamedQubit('b')