cirq-core 1.1.0.dev20221220224914__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 (228) 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/contrib/acquaintance/bipartite.py +1 -1
  18. cirq/contrib/acquaintance/devices.py +2 -2
  19. cirq/contrib/acquaintance/executor.py +5 -2
  20. cirq/contrib/acquaintance/gates.py +3 -2
  21. cirq/contrib/acquaintance/permutation.py +13 -2
  22. cirq/contrib/acquaintance/testing.py +3 -5
  23. cirq/contrib/paulistring/recombine.py +3 -6
  24. cirq/contrib/qasm_import/_parser.py +17 -21
  25. cirq/contrib/qasm_import/_parser_test.py +30 -45
  26. cirq/contrib/qcircuit/qcircuit_test.py +3 -7
  27. cirq/contrib/quantum_volume/quantum_volume.py +3 -3
  28. cirq/contrib/quimb/mps_simulator.py +1 -1
  29. cirq/contrib/quimb/state_vector.py +2 -0
  30. cirq/contrib/quirk/quirk_gate.py +1 -0
  31. cirq/contrib/svg/svg.py +4 -7
  32. cirq/contrib/svg/svg_test.py +29 -1
  33. cirq/devices/grid_qubit.py +26 -28
  34. cirq/devices/grid_qubit_test.py +21 -5
  35. cirq/devices/line_qubit.py +10 -12
  36. cirq/devices/line_qubit_test.py +9 -2
  37. cirq/devices/named_topologies.py +1 -1
  38. cirq/devices/noise_model.py +4 -1
  39. cirq/devices/superconducting_qubits_noise_properties.py +1 -3
  40. cirq/experiments/n_qubit_tomography.py +1 -1
  41. cirq/experiments/qubit_characterizations.py +2 -2
  42. cirq/experiments/single_qubit_readout_calibration.py +1 -1
  43. cirq/experiments/t2_decay_experiment.py +1 -1
  44. cirq/experiments/xeb_simulation_test.py +2 -2
  45. cirq/interop/quirk/cells/testing.py +1 -1
  46. cirq/json_resolver_cache.py +1 -0
  47. cirq/linalg/__init__.py +2 -0
  48. cirq/linalg/decompositions_test.py +4 -4
  49. cirq/linalg/diagonalize_test.py +5 -6
  50. cirq/linalg/transformations.py +72 -9
  51. cirq/linalg/transformations_test.py +23 -7
  52. cirq/ops/__init__.py +4 -0
  53. cirq/ops/arithmetic_operation.py +4 -6
  54. cirq/ops/classically_controlled_operation.py +10 -3
  55. cirq/ops/clifford_gate.py +1 -7
  56. cirq/ops/common_channels.py +21 -15
  57. cirq/ops/common_gate_families.py +2 -3
  58. cirq/ops/common_gates.py +48 -11
  59. cirq/ops/common_gates_test.py +4 -0
  60. cirq/ops/controlled_gate.py +44 -18
  61. cirq/ops/controlled_operation.py +13 -5
  62. cirq/ops/dense_pauli_string.py +14 -19
  63. cirq/ops/diagonal_gate.py +3 -4
  64. cirq/ops/eigen_gate.py +8 -10
  65. cirq/ops/eigen_gate_test.py +6 -0
  66. cirq/ops/gate_operation.py +11 -6
  67. cirq/ops/gate_operation_test.py +11 -2
  68. cirq/ops/gateset.py +2 -1
  69. cirq/ops/gateset_test.py +38 -5
  70. cirq/ops/global_phase_op.py +28 -2
  71. cirq/ops/global_phase_op_test.py +21 -0
  72. cirq/ops/identity.py +1 -1
  73. cirq/ops/kraus_channel_test.py +2 -2
  74. cirq/ops/linear_combinations.py +7 -6
  75. cirq/ops/linear_combinations_test.py +26 -10
  76. cirq/ops/matrix_gates.py +8 -4
  77. cirq/ops/matrix_gates_test.py +25 -3
  78. cirq/ops/measure_util.py +13 -5
  79. cirq/ops/measure_util_test.py +8 -2
  80. cirq/ops/measurement_gate.py +1 -1
  81. cirq/ops/measurement_gate_test.py +9 -4
  82. cirq/ops/mixed_unitary_channel_test.py +4 -4
  83. cirq/ops/named_qubit.py +2 -4
  84. cirq/ops/parity_gates.py +5 -1
  85. cirq/ops/parity_gates_test.py +6 -0
  86. cirq/ops/pauli_gates.py +9 -9
  87. cirq/ops/pauli_string.py +4 -2
  88. cirq/ops/pauli_string_raw_types.py +4 -11
  89. cirq/ops/pauli_string_test.py +13 -13
  90. cirq/ops/pauli_sum_exponential.py +6 -1
  91. cirq/ops/qubit_manager.py +97 -0
  92. cirq/ops/qubit_manager_test.py +66 -0
  93. cirq/ops/raw_types.py +75 -33
  94. cirq/ops/raw_types_test.py +34 -0
  95. cirq/ops/three_qubit_gates.py +16 -10
  96. cirq/ops/three_qubit_gates_test.py +4 -2
  97. cirq/ops/two_qubit_diagonal_gate.py +3 -3
  98. cirq/ops/wait_gate.py +1 -1
  99. cirq/protocols/__init__.py +1 -0
  100. cirq/protocols/act_on_protocol.py +3 -3
  101. cirq/protocols/act_on_protocol_test.py +5 -5
  102. cirq/protocols/apply_channel_protocol.py +9 -8
  103. cirq/protocols/apply_mixture_protocol.py +8 -8
  104. cirq/protocols/apply_mixture_protocol_test.py +1 -1
  105. cirq/protocols/apply_unitary_protocol.py +66 -19
  106. cirq/protocols/apply_unitary_protocol_test.py +50 -0
  107. cirq/protocols/circuit_diagram_info_protocol.py +7 -9
  108. cirq/protocols/decompose_protocol.py +167 -125
  109. cirq/protocols/decompose_protocol_test.py +132 -2
  110. cirq/protocols/has_stabilizer_effect_protocol.py +2 -1
  111. cirq/protocols/inverse_protocol.py +2 -2
  112. cirq/protocols/json_serialization_test.py +3 -3
  113. cirq/protocols/json_test_data/Linspace.json +20 -7
  114. cirq/protocols/json_test_data/Linspace.repr +4 -1
  115. cirq/protocols/json_test_data/Points.json +19 -8
  116. cirq/protocols/json_test_data/Points.repr +4 -1
  117. cirq/protocols/json_test_data/Result.repr_inward +1 -1
  118. cirq/protocols/json_test_data/ResultDict.repr +1 -1
  119. cirq/protocols/json_test_data/ResultDict.repr_inward +1 -1
  120. cirq/protocols/json_test_data/TrialResult.repr_inward +1 -1
  121. cirq/protocols/json_test_data/XPowGate.json +13 -5
  122. cirq/protocols/json_test_data/XPowGate.repr +1 -1
  123. cirq/protocols/json_test_data/ZPowGate.json +13 -5
  124. cirq/protocols/json_test_data/ZPowGate.repr +1 -1
  125. cirq/protocols/json_test_data/ZipLongest.json +19 -0
  126. cirq/protocols/json_test_data/ZipLongest.repr +1 -0
  127. cirq/protocols/json_test_data/spec.py +1 -0
  128. cirq/protocols/kraus_protocol.py +3 -4
  129. cirq/protocols/measurement_key_protocol.py +3 -1
  130. cirq/protocols/mixture_protocol.py +3 -2
  131. cirq/protocols/phase_protocol.py +3 -3
  132. cirq/protocols/pow_protocol.py +1 -2
  133. cirq/protocols/qasm.py +4 -4
  134. cirq/protocols/qid_shape_protocol.py +8 -8
  135. cirq/protocols/resolve_parameters.py +8 -3
  136. cirq/protocols/resolve_parameters_test.py +3 -3
  137. cirq/protocols/unitary_protocol.py +19 -11
  138. cirq/protocols/unitary_protocol_test.py +37 -0
  139. cirq/qis/channels.py +1 -1
  140. cirq/qis/clifford_tableau.py +4 -5
  141. cirq/qis/quantum_state_representation.py +7 -9
  142. cirq/qis/states.py +21 -13
  143. cirq/qis/states_test.py +7 -0
  144. cirq/sim/clifford/clifford_simulator.py +3 -3
  145. cirq/sim/density_matrix_simulation_state.py +2 -1
  146. cirq/sim/density_matrix_simulator.py +1 -1
  147. cirq/sim/density_matrix_simulator_test.py +9 -5
  148. cirq/sim/density_matrix_utils.py +7 -32
  149. cirq/sim/mux.py +2 -2
  150. cirq/sim/simulation_state.py +58 -18
  151. cirq/sim/simulation_state_base.py +5 -2
  152. cirq/sim/simulation_state_test.py +121 -9
  153. cirq/sim/simulation_utils.py +59 -0
  154. cirq/sim/simulation_utils_test.py +32 -0
  155. cirq/sim/simulator.py +2 -1
  156. cirq/sim/simulator_base_test.py +3 -3
  157. cirq/sim/sparse_simulator.py +1 -1
  158. cirq/sim/sparse_simulator_test.py +5 -5
  159. cirq/sim/state_vector.py +7 -36
  160. cirq/sim/state_vector_simulation_state.py +18 -1
  161. cirq/sim/state_vector_simulator.py +3 -2
  162. cirq/sim/state_vector_simulator_test.py +24 -2
  163. cirq/sim/state_vector_test.py +46 -15
  164. cirq/study/__init__.py +1 -0
  165. cirq/study/flatten_expressions.py +2 -2
  166. cirq/study/resolver.py +2 -0
  167. cirq/study/resolver_test.py +1 -1
  168. cirq/study/result.py +1 -1
  169. cirq/study/sweeps.py +103 -9
  170. cirq/study/sweeps_test.py +64 -0
  171. cirq/testing/__init__.py +4 -0
  172. cirq/testing/circuit_compare.py +15 -18
  173. cirq/testing/consistent_act_on.py +4 -4
  174. cirq/testing/consistent_controlled_gate_op_test.py +1 -1
  175. cirq/testing/consistent_decomposition.py +11 -2
  176. cirq/testing/consistent_decomposition_test.py +8 -1
  177. cirq/testing/consistent_protocols.py +2 -0
  178. cirq/testing/consistent_protocols_test.py +8 -4
  179. cirq/testing/consistent_qasm.py +8 -15
  180. cirq/testing/consistent_specified_has_unitary.py +1 -1
  181. cirq/testing/consistent_unitary.py +85 -0
  182. cirq/testing/consistent_unitary_test.py +96 -0
  183. cirq/testing/equivalent_repr_eval.py +10 -10
  184. cirq/testing/json.py +3 -3
  185. cirq/testing/logs.py +1 -1
  186. cirq/testing/order_tester.py +4 -5
  187. cirq/testing/random_circuit.py +3 -5
  188. cirq/testing/sample_gates.py +79 -0
  189. cirq/testing/sample_gates_test.py +59 -0
  190. cirq/transformers/__init__.py +2 -0
  191. cirq/transformers/analytical_decompositions/__init__.py +8 -0
  192. cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +130 -0
  193. cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +58 -0
  194. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +230 -0
  195. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +112 -0
  196. cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +1 -3
  197. cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +1 -1
  198. cirq/transformers/expand_composite.py +1 -1
  199. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +4 -4
  200. cirq/transformers/measurement_transformers.py +4 -4
  201. cirq/transformers/merge_single_qubit_gates.py +17 -4
  202. cirq/transformers/routing/route_circuit_cqc.py +2 -2
  203. cirq/transformers/stratify.py +125 -62
  204. cirq/transformers/stratify_test.py +20 -16
  205. cirq/transformers/transformer_api.py +1 -1
  206. cirq/transformers/transformer_primitives.py +3 -2
  207. cirq/transformers/transformer_primitives_test.py +11 -0
  208. cirq/value/abc_alt.py +3 -2
  209. cirq/value/abc_alt_test.py +1 -0
  210. cirq/value/classical_data.py +10 -10
  211. cirq/value/digits.py +2 -2
  212. cirq/value/linear_dict.py +18 -19
  213. cirq/value/product_state.py +7 -6
  214. cirq/value/value_equality_attr.py +2 -2
  215. cirq/vis/heatmap.py +1 -1
  216. cirq/vis/heatmap_test.py +2 -2
  217. cirq/work/collector.py +2 -2
  218. cirq/work/observable_measurement_data.py +5 -5
  219. cirq/work/observable_readout_calibration.py +3 -1
  220. cirq/work/observable_settings.py +1 -1
  221. cirq/work/pauli_sum_collector.py +9 -8
  222. cirq/work/sampler.py +2 -0
  223. cirq/work/zeros_sampler.py +2 -2
  224. {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/METADATA +7 -15
  225. {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/RECORD +228 -214
  226. {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/WHEEL +1 -1
  227. {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/LICENSE +0 -0
  228. {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/top_level.txt +0 -0
@@ -28,7 +28,13 @@ from typing import (
28
28
  import numpy as np
29
29
 
30
30
  from cirq import protocols, value, _import
31
- from cirq.ops import raw_types, controlled_operation as cop, matrix_gates, control_values as cv
31
+ from cirq.ops import (
32
+ raw_types,
33
+ controlled_operation as cop,
34
+ op_tree,
35
+ matrix_gates,
36
+ control_values as cv,
37
+ )
32
38
  from cirq.type_workarounds import NotImplementedType
33
39
 
34
40
  if TYPE_CHECKING:
@@ -51,7 +57,7 @@ class ControlledGate(raw_types.Gate):
51
57
  def __init__(
52
58
  self,
53
59
  sub_gate: 'cirq.Gate',
54
- num_controls: int = None,
60
+ num_controls: Optional[int] = None,
55
61
  control_values: Optional[
56
62
  Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
57
63
  ] = None,
@@ -143,7 +149,14 @@ class ControlledGate(raw_types.Gate):
143
149
  def _qid_shape_(self) -> Tuple[int, ...]:
144
150
  return self.control_qid_shape + protocols.qid_shape(self.sub_gate)
145
151
 
146
- def _decompose_(self, qubits):
152
+ def _decompose_(
153
+ self, qubits: Tuple['cirq.Qid', ...]
154
+ ) -> Union[None, NotImplementedType, 'cirq.OP_TREE']:
155
+ return self._decompose_with_context_(qubits)
156
+
157
+ def _decompose_with_context_(
158
+ self, qubits: Tuple['cirq.Qid', ...], context: Optional['cirq.DecompositionContext'] = None
159
+ ) -> Union[None, NotImplementedType, 'cirq.OP_TREE']:
147
160
  if (
148
161
  protocols.has_unitary(self.sub_gate)
149
162
  and protocols.num_qubits(self.sub_gate) == 1
@@ -166,18 +179,27 @@ class ControlledGate(raw_types.Gate):
166
179
  z_sub_gate = common_gates.ZPowGate(
167
180
  exponent=self.sub_gate.exponent, global_shift=self.sub_gate.global_shift
168
181
  )
169
- kwargs = {
170
- 'num_controls': self.num_controls() + 1,
171
- 'control_values': self.control_values & cv.ProductOfSums(((1,),)),
172
- 'control_qid_shape': self.control_qid_shape + (2,),
173
- }
182
+ num_controls = self.num_controls() + 1
183
+ control_values = self.control_values & cv.ProductOfSums(((1,),))
184
+ control_qid_shape = self.control_qid_shape + (2,)
174
185
  controlled_z = (
175
- z_sub_gate.controlled(**kwargs)
186
+ z_sub_gate.controlled(
187
+ num_controls=num_controls,
188
+ control_values=control_values,
189
+ control_qid_shape=control_qid_shape,
190
+ )
176
191
  if protocols.is_parameterized(self)
177
- else ControlledGate(z_sub_gate, **kwargs)
192
+ else ControlledGate(
193
+ z_sub_gate,
194
+ num_controls=num_controls,
195
+ control_values=control_values,
196
+ control_qid_shape=control_qid_shape,
197
+ )
178
198
  )
179
199
  if self != controlled_z:
180
- return protocols.decompose_once_with_qubits(controlled_z, qubits, NotImplemented)
200
+ return protocols.decompose_once_with_qubits(
201
+ controlled_z, qubits, NotImplemented, context=context
202
+ )
181
203
 
182
204
  if isinstance(self.sub_gate, matrix_gates.MatrixGate):
183
205
  # Default decompositions of 2/3 qubit `cirq.MatrixGate` ignores global phase, which is
@@ -185,17 +207,21 @@ class ControlledGate(raw_types.Gate):
185
207
  return NotImplemented
186
208
 
187
209
  result = protocols.decompose_once_with_qubits(
188
- self.sub_gate, qubits[self.num_controls() :], NotImplemented
210
+ self.sub_gate,
211
+ qubits[self.num_controls() :],
212
+ NotImplemented,
213
+ flatten=False,
214
+ context=context,
189
215
  )
190
216
  if result is NotImplemented:
191
217
  return NotImplemented
192
218
 
193
- decomposed: List['cirq.Operation'] = []
194
- for op in result:
195
- decomposed.append(
196
- op.controlled_by(*qubits[: self.num_controls()], control_values=self.control_values)
197
- )
198
- return decomposed
219
+ return op_tree.transform_op_tree(
220
+ result,
221
+ lambda op: op.controlled_by(
222
+ *qubits[: self.num_controls()], control_values=self.control_values
223
+ ),
224
+ )
199
225
 
200
226
  def on(self, *qubits: 'cirq.Qid') -> cop.ControlledOperation:
201
227
  if len(qubits) == 0:
@@ -34,6 +34,7 @@ from cirq.ops import (
34
34
  eigen_gate,
35
35
  gate_operation,
36
36
  matrix_gates,
37
+ op_tree,
37
38
  raw_types,
38
39
  control_values as cv,
39
40
  )
@@ -145,7 +146,12 @@ class ControlledOperation(raw_types.Operation):
145
146
  )
146
147
 
147
148
  def _decompose_(self):
148
- result = protocols.decompose_once_with_qubits(self.gate, self.qubits, NotImplemented)
149
+ return self._decompose_with_context_()
150
+
151
+ def _decompose_with_context_(self, context: Optional['cirq.DecompositionContext'] = None):
152
+ result = protocols.decompose_once_with_qubits(
153
+ self.gate, self.qubits, NotImplemented, flatten=False, context=context
154
+ )
149
155
  if result is not NotImplemented:
150
156
  return result
151
157
 
@@ -154,13 +160,15 @@ class ControlledOperation(raw_types.Operation):
154
160
  # local phase in the controlled variant and hence cannot be ignored.
155
161
  return NotImplemented
156
162
 
157
- result = protocols.decompose_once(self.sub_operation, NotImplemented)
163
+ result = protocols.decompose_once(
164
+ self.sub_operation, NotImplemented, flatten=False, context=context
165
+ )
158
166
  if result is NotImplemented:
159
167
  return NotImplemented
160
168
 
161
- return [
162
- op.controlled_by(*self.controls, control_values=self.control_values) for op in result
163
- ]
169
+ return op_tree.transform_op_tree(
170
+ result, lambda op: op.controlled_by(*self.controls, control_values=self.control_values)
171
+ )
164
172
 
165
173
  def _value_equality_values_(self):
166
174
  sorted_controls, expanded_cvals = tuple(
@@ -27,11 +27,10 @@ from typing import (
27
27
  overload,
28
28
  Sequence,
29
29
  Tuple,
30
- Type,
31
30
  TYPE_CHECKING,
32
- TypeVar,
33
31
  Union,
34
32
  )
33
+ from typing_extensions import Self
35
34
 
36
35
  import numpy as np
37
36
  import sympy
@@ -53,8 +52,6 @@ PAULI_GATES: List[Union['cirq.Pauli', 'cirq.IdentityGate']] = [
53
52
  pauli_gates.Z,
54
53
  ]
55
54
 
56
- TCls = TypeVar('TCls', bound='BaseDensePauliString')
57
-
58
55
 
59
56
  @value.value_equality(approximate=True, distinct_child_types=True)
60
57
  class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
@@ -132,7 +129,7 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
132
129
  return self.coefficient, tuple(PAULI_CHARS[p] for p in self.pauli_mask)
133
130
 
134
131
  @classmethod
135
- def one_hot(cls: Type[TCls], *, index: int, length: int, pauli: 'cirq.PAULI_GATE_LIKE') -> TCls:
132
+ def one_hot(cls, *, index: int, length: int, pauli: 'cirq.PAULI_GATE_LIKE') -> Self:
136
133
  """Creates a dense pauli string with only one non-identity Pauli.
137
134
 
138
135
  Args:
@@ -149,7 +146,7 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
149
146
  return concrete_cls(pauli_mask=mask)
150
147
 
151
148
  @classmethod
152
- def eye(cls: Type[TCls], length: int) -> TCls:
149
+ def eye(cls, length: int) -> Self:
153
150
  """Creates a dense pauli string containing only identity gates.
154
151
 
155
152
  Args:
@@ -198,7 +195,7 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
198
195
  def _parameter_names_(self) -> AbstractSet[str]:
199
196
  return protocols.parameter_names(self.coefficient)
200
197
 
201
- def _resolve_parameters_(self: TCls, resolver: 'cirq.ParamResolver', recursive: bool) -> TCls:
198
+ def _resolve_parameters_(self, resolver: 'cirq.ParamResolver', recursive: bool) -> Self:
202
199
  return self.copy(
203
200
  coefficient=protocols.resolve_parameters(self.coefficient, resolver, recursive)
204
201
  )
@@ -206,7 +203,7 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
206
203
  def __pos__(self):
207
204
  return self
208
205
 
209
- def __pow__(self: TCls, power: Union[int, float]) -> Union[NotImplementedType, TCls]:
206
+ def __pow__(self, power: Union[int, float]) -> Union[NotImplementedType, Self]:
210
207
  concrete_class = type(self)
211
208
  if isinstance(power, int):
212
209
  i_group = [1, +1j, -1, -1j]
@@ -221,11 +218,11 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
221
218
  return NotImplemented
222
219
 
223
220
  @overload
224
- def __getitem__(self: TCls, item: int) -> Union['cirq.Pauli', 'cirq.IdentityGate']:
221
+ def __getitem__(self, item: int) -> Union['cirq.Pauli', 'cirq.IdentityGate']:
225
222
  pass
226
223
 
227
224
  @overload
228
- def __getitem__(self: TCls, item: slice) -> TCls:
225
+ def __getitem__(self, item: slice) -> Self:
229
226
  pass
230
227
 
231
228
  def __getitem__(self, item):
@@ -304,7 +301,7 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
304
301
 
305
302
  return NotImplemented
306
303
 
307
- def tensor_product(self: TCls, other: 'BaseDensePauliString') -> TCls:
304
+ def tensor_product(self, other: 'BaseDensePauliString') -> Self:
308
305
  """Concatenates dense pauli strings and multiplies their coefficients.
309
306
 
310
307
  Args:
@@ -319,7 +316,7 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
319
316
  pauli_mask=np.concatenate([self.pauli_mask, other.pauli_mask]),
320
317
  )
321
318
 
322
- def __abs__(self: TCls) -> TCls:
319
+ def __abs__(self) -> Self:
323
320
  coef = self.coefficient
324
321
  return type(self)(
325
322
  coefficient=sympy.Abs(coef) if isinstance(coef, sympy.Expr) else abs(coef),
@@ -405,10 +402,10 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
405
402
 
406
403
  @abc.abstractmethod
407
404
  def copy(
408
- self: TCls,
405
+ self,
409
406
  coefficient: Optional[Union[sympy.Expr, int, float, complex]] = None,
410
407
  pauli_mask: Union[None, str, Iterable[int], np.ndarray] = None,
411
- ) -> TCls:
408
+ ) -> Self:
412
409
  """Returns a copy with possibly modified contents.
413
410
 
414
411
  Args:
@@ -492,17 +489,15 @@ class MutableDensePauliString(BaseDensePauliString):
492
489
  """
493
490
 
494
491
  @overload
495
- def __setitem__(
496
- self: 'MutableDensePauliString', key: int, value: 'cirq.PAULI_GATE_LIKE'
497
- ) -> 'MutableDensePauliString':
492
+ def __setitem__(self, key: int, value: 'cirq.PAULI_GATE_LIKE') -> Self:
498
493
  pass
499
494
 
500
495
  @overload
501
496
  def __setitem__(
502
- self: 'MutableDensePauliString',
497
+ self,
503
498
  key: slice,
504
499
  value: Union[Iterable['cirq.PAULI_GATE_LIKE'], np.ndarray, BaseDensePauliString],
505
- ) -> 'MutableDensePauliString':
500
+ ) -> Self:
506
501
  pass
507
502
 
508
503
  def __setitem__(self, key, value):
cirq/ops/diagonal_gate.py CHANGED
@@ -147,7 +147,7 @@ class DiagonalGate(raw_types.Gate):
147
147
  diag_str += ', '.join(proper_repr(angle) for angle in rounded_angles[-2:])
148
148
  diag_str = f'diag({diag_str})'
149
149
  return protocols.CircuitDiagramInfo(
150
- [diag_str] + ['#' + str(i) for i in range(2, self._num_qubits_() + 1)]
150
+ [diag_str] + [f"#{i}" for i in range(2, self._num_qubits_() + 1)]
151
151
  )
152
152
 
153
153
  def __pow__(self, exponent: Any) -> 'DiagonalGate':
@@ -213,6 +213,5 @@ class DiagonalGate(raw_types.Gate):
213
213
  return protocols.obj_to_dict_helper(self, attribute_names=["diag_angles_radians"])
214
214
 
215
215
  def __repr__(self) -> str:
216
- return 'cirq.DiagonalGate([{}])'.format(
217
- ','.join(proper_repr(angle) for angle in self._diag_angles_radians)
218
- )
216
+ angles = ','.join(proper_repr(angle) for angle in self._diag_angles_radians)
217
+ return f'cirq.DiagonalGate([{angles}])'
cirq/ops/eigen_gate.py CHANGED
@@ -11,7 +11,10 @@
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
+ import abc
14
15
  import fractions
16
+ import math
17
+ import numbers
15
18
  from typing import (
16
19
  AbstractSet,
17
20
  Any,
@@ -23,25 +26,20 @@ from typing import (
23
26
  Optional,
24
27
  Tuple,
25
28
  TYPE_CHECKING,
26
- TypeVar,
27
29
  Union,
28
30
  )
29
- import abc
30
- import math
31
- import numbers
32
31
 
33
32
  import numpy as np
34
33
  import sympy
35
34
 
36
35
  from cirq import value, protocols
36
+ from cirq.linalg import tolerance
37
37
  from cirq.ops import raw_types
38
38
  from cirq.type_workarounds import NotImplementedType
39
39
 
40
40
  if TYPE_CHECKING:
41
41
  import cirq
42
42
 
43
- TSelf = TypeVar('TSelf', bound='EigenGate')
44
-
45
43
 
46
44
  EigenComponent = NamedTuple(
47
45
  'EigenComponent',
@@ -135,7 +133,7 @@ class EigenGate(raw_types.Gate):
135
133
  return self._global_shift
136
134
 
137
135
  # virtual method
138
- def _with_exponent(self: TSelf, exponent: value.TParamVal) -> 'EigenGate':
136
+ def _with_exponent(self, exponent: value.TParamVal) -> 'EigenGate':
139
137
  """Return the same kind of gate, but with a different exponent.
140
138
 
141
139
  Child classes should override this method if they have an __init__
@@ -301,7 +299,7 @@ class EigenGate(raw_types.Gate):
301
299
  real_periods = [abs(2 / e) for e in exponents if e != 0]
302
300
  return _approximate_common_period(real_periods)
303
301
 
304
- def __pow__(self: TSelf, exponent: Union[float, sympy.Symbol]) -> 'EigenGate':
302
+ def __pow__(self, exponent: Union[float, sympy.Symbol]) -> 'EigenGate':
305
303
  new_exponent = protocols.mul(self._exponent, exponent, NotImplemented)
306
304
  if new_exponent is NotImplemented:
307
305
  return NotImplemented
@@ -388,8 +386,8 @@ class EigenGate(raw_types.Gate):
388
386
  return False
389
387
 
390
388
  period = self_without_phase._period()
391
- canonical_diff = (exponents[0] - exponents[1]) % period
392
- return np.isclose(canonical_diff, 0, atol=atol)
389
+ exponents_diff = exponents[0] - exponents[1]
390
+ return tolerance.near_zero_mod(exponents_diff, period, atol=atol)
393
391
 
394
392
  def _json_dict_(self) -> Dict[str, Any]:
395
393
  return protocols.obj_to_dict_helper(self, ['exponent', 'global_shift'])
@@ -363,6 +363,12 @@ class WeightedZPowGate(cirq.EigenGate, cirq.testing.SingleQubitGate):
363
363
  (cirq.X, cirq.Y, False),
364
364
  (cirq.rz(np.pi), cirq.Z, True),
365
365
  (cirq.X**0.3, cirq.Z**0.3, False),
366
+ (cirq.Z, cirq.Z ** (1 - 1e-10), True),
367
+ (cirq.Z, cirq.Z ** (1 + 1e-10), True),
368
+ (cirq.Z, cirq.Z ** (3 - 1e-10), True),
369
+ (cirq.Z, cirq.Z ** (3 + 1e-10), True),
370
+ (cirq.Z**2, cirq.Z ** (4 - 1e-10), True),
371
+ (cirq.Z**2, cirq.Z ** (4 + 1e-10), True),
366
372
  ],
367
373
  )
368
374
  def test_equal_up_to_global_phase(gate1, gate2, eq_up_to_global_phase):
@@ -31,6 +31,7 @@ from typing import (
31
31
  Union,
32
32
  List,
33
33
  )
34
+ from typing_extensions import Self
34
35
 
35
36
  import numpy as np
36
37
 
@@ -42,9 +43,6 @@ if TYPE_CHECKING:
42
43
  import cirq
43
44
 
44
45
 
45
- TSelf = TypeVar('TSelf', bound='GateOperation')
46
-
47
-
48
46
  @value.value_equality(approximate=True)
49
47
  class GateOperation(raw_types.Operation):
50
48
  """An application of a gate to a sequence of qubits.
@@ -73,8 +71,8 @@ class GateOperation(raw_types.Operation):
73
71
  """The qubits targeted by the operation."""
74
72
  return self._qubits
75
73
 
76
- def with_qubits(self: TSelf, *new_qubits: 'cirq.Qid') -> TSelf:
77
- return cast(TSelf, self.gate.on(*new_qubits))
74
+ def with_qubits(self, *new_qubits: 'cirq.Qid') -> Self:
75
+ return cast(Self, self.gate.on(*new_qubits))
78
76
 
79
77
  def with_gate(self, new_gate: 'cirq.Gate') -> 'cirq.Operation':
80
78
  if self.gate is new_gate:
@@ -162,7 +160,14 @@ class GateOperation(raw_types.Operation):
162
160
  return len(self._qubits)
163
161
 
164
162
  def _decompose_(self) -> 'cirq.OP_TREE':
165
- return protocols.decompose_once_with_qubits(self.gate, self.qubits, NotImplemented)
163
+ return self._decompose_with_context_()
164
+
165
+ def _decompose_with_context_(
166
+ self, context: Optional['cirq.DecompositionContext'] = None
167
+ ) -> 'cirq.OP_TREE':
168
+ return protocols.decompose_once_with_qubits(
169
+ self.gate, self.qubits, NotImplemented, flatten=False, context=context
170
+ )
166
171
 
167
172
  def _pauli_expansion_(self) -> value.LinearDict[str]:
168
173
  getter = getattr(self.gate, '_pauli_expansion_', None)
@@ -41,10 +41,19 @@ def test_immutable():
41
41
  a, b = cirq.LineQubit.range(2)
42
42
  op = cirq.X(a)
43
43
 
44
- with pytest.raises(AttributeError, match="can't set attribute"):
44
+ # Match one of two strings. The second one is message returned since python 3.11.
45
+ with pytest.raises(
46
+ AttributeError,
47
+ match="(can't set attribute)|"
48
+ "(property 'gate' of 'SingleQubitPauliStringGateOperation' object has no setter)",
49
+ ):
45
50
  op.gate = cirq.Y
46
51
 
47
- with pytest.raises(AttributeError, match="can't set attribute"):
52
+ with pytest.raises(
53
+ AttributeError,
54
+ match="(can't set attribute)|"
55
+ "(property 'qubits' of 'SingleQubitPauliStringGateOperation' object has no setter)",
56
+ ):
48
57
  op.qubits = [b]
49
58
 
50
59
 
cirq/ops/gateset.py CHANGED
@@ -257,11 +257,12 @@ class GateFamily:
257
257
 
258
258
  def _value_equality_values_(self) -> Any:
259
259
  # `isinstance` is used to ensure the a gate type and gate instance is not compared.
260
+ description = self.description if self.description != self._default_description() else None
260
261
  return (
261
262
  isinstance(self.gate, raw_types.Gate),
262
263
  self.gate,
263
264
  self.name,
264
- self.description,
265
+ description,
265
266
  self._ignore_global_phase,
266
267
  self._tags_to_accept,
267
268
  self._tags_to_ignore,
cirq/ops/gateset_test.py CHANGED
@@ -37,8 +37,10 @@ class CustomXPowGate(cirq.EigenGate):
37
37
  if self._exponent == 1:
38
38
  return 'cirq.ops.gateset_test.CustomX'
39
39
  return f'(cirq.ops.gateset_test.CustomX**{proper_repr(self._exponent)})'
40
- return 'cirq.ops.gateset_test.CustomXPowGate(exponent={}, global_shift={!r})'.format(
41
- proper_repr(self._exponent), self._global_shift
40
+ return (
41
+ 'cirq.ops.gateset_test.CustomXPowGate('
42
+ f'exponent={proper_repr(self._exponent)}, '
43
+ f'global_shift={self._global_shift!r})'
42
44
  )
43
45
 
44
46
  def _num_qubits_(self) -> int:
@@ -81,6 +83,27 @@ def test_gate_family_default_name_and_description(gate, tags_to_accept, tags_to_
81
83
  assert (ignored_match is None) == (tags_to_ignore == [])
82
84
 
83
85
 
86
+ @pytest.mark.parametrize(
87
+ 'tags_to_accept_fam1, tags_to_ignore_fam1, tags_to_accept_fam2, tags_to_ignore_fam2',
88
+ [
89
+ (tuple("ab"), tuple("cd"), tuple("ba"), tuple("dc")),
90
+ (tuple("ab"), [], tuple("ba"), []),
91
+ ([], tuple("ab"), [], tuple("ba")),
92
+ ],
93
+ )
94
+ def test_gate_family_equality_with_tags(
95
+ tags_to_accept_fam1, tags_to_ignore_fam1, tags_to_accept_fam2, tags_to_ignore_fam2
96
+ ):
97
+ gate_fam1 = cirq.GateFamily(
98
+ cirq.X, tags_to_accept=tags_to_accept_fam1, tags_to_ignore=tags_to_ignore_fam1
99
+ )
100
+ gate_fam2 = cirq.GateFamily(
101
+ cirq.X, tags_to_accept=tags_to_accept_fam2, tags_to_ignore=tags_to_ignore_fam2
102
+ )
103
+
104
+ assert gate_fam1 == gate_fam2
105
+
106
+
84
107
  def test_invalid_gate_family():
85
108
  with pytest.raises(ValueError, match='instance or subclass of `cirq.Gate`'):
86
109
  _ = cirq.GateFamily(gate=cirq.Operation)
@@ -94,11 +117,21 @@ def test_invalid_gate_family():
94
117
 
95
118
  def test_gate_family_immutable():
96
119
  g = cirq.GateFamily(CustomX)
97
- with pytest.raises(AttributeError, match="can't set attribute"):
120
+ # Match one of two strings. The second one is message returned since python 3.11.
121
+ with pytest.raises(
122
+ AttributeError,
123
+ match="(can't set attribute)|(property 'gate' of 'GateFamily' object has no setter)",
124
+ ):
98
125
  g.gate = CustomXPowGate
99
- with pytest.raises(AttributeError, match="can't set attribute"):
126
+ with pytest.raises(
127
+ AttributeError,
128
+ match="(can't set attribute)|(property 'name' of 'GateFamily' object has no setter)",
129
+ ):
100
130
  g.name = 'new name'
101
- with pytest.raises(AttributeError, match="can't set attribute"):
131
+ with pytest.raises(
132
+ AttributeError,
133
+ match="(can't set attribute)|(property 'description' of 'GateFamily' object has no setter)",
134
+ ):
102
135
  g.description = 'new description'
103
136
 
104
137
 
@@ -13,14 +13,14 @@
13
13
  # limitations under the License.
14
14
  """A no-qubit global phase operation."""
15
15
 
16
- from typing import AbstractSet, Any, cast, Dict, Sequence, Tuple, Union
16
+ from typing import AbstractSet, Any, cast, Dict, Sequence, Tuple, Union, Optional, Collection
17
17
 
18
18
  import numpy as np
19
19
  import sympy
20
20
 
21
21
  import cirq
22
22
  from cirq import value, protocols
23
- from cirq.ops import raw_types
23
+ from cirq.ops import raw_types, controlled_gate, control_values as cv
24
24
  from cirq.type_workarounds import NotImplementedType
25
25
 
26
26
 
@@ -91,6 +91,32 @@ class GlobalPhaseGate(raw_types.Gate):
91
91
  coefficient = protocols.resolve_parameters(self.coefficient, resolver, recursive)
92
92
  return GlobalPhaseGate(coefficient=coefficient)
93
93
 
94
+ def controlled(
95
+ self,
96
+ num_controls: Optional[int] = None,
97
+ control_values: Optional[
98
+ Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
99
+ ] = None,
100
+ control_qid_shape: Optional[Tuple[int, ...]] = None,
101
+ ) -> raw_types.Gate:
102
+ result = super().controlled(num_controls, control_values, control_qid_shape)
103
+ if (
104
+ not self._is_parameterized_()
105
+ and isinstance(result, controlled_gate.ControlledGate)
106
+ and isinstance(result.control_values, cv.ProductOfSums)
107
+ and result.control_values[-1] == (1,)
108
+ and result.control_qid_shape[-1] == 2
109
+ ):
110
+ # A `GlobalPhaseGate` controlled on a qubit in state `|1>` is equivalent
111
+ # to applying a `ZPowGate`. This override ensures that `global_phase_gate.controlled()`
112
+ # returns a `ZPowGate` instead of a `ControlledGate(sub_gate=global_phase_gate)`.
113
+ coefficient = complex(self.coefficient)
114
+ exponent = float(np.angle(coefficient) / np.pi)
115
+ return cirq.ZPowGate(exponent=exponent).controlled(
116
+ result.num_controls() - 1, result.control_values[:-1], result.control_qid_shape[:-1]
117
+ )
118
+ return result
119
+
94
120
 
95
121
  def global_phase_operation(
96
122
  coefficient: 'cirq.TParamValComplex', atol: float = 1e-8
@@ -279,3 +279,24 @@ def test_resolve_error(resolve_fn):
279
279
  gpt = cirq.GlobalPhaseGate(coefficient=t)
280
280
  with pytest.raises(ValueError, match='Coefficient is not unitary'):
281
281
  resolve_fn(gpt, {'t': -2})
282
+
283
+
284
+ @pytest.mark.parametrize(
285
+ 'coeff, exp', [(-1, 1), (1j, 0.5), (-1j, -0.5), (1 / np.sqrt(2) * (1 + 1j), 0.25)]
286
+ )
287
+ def test_global_phase_gate_controlled(coeff, exp):
288
+ g = cirq.GlobalPhaseGate(coeff)
289
+ op = cirq.global_phase_operation(coeff)
290
+ q = cirq.LineQubit.range(3)
291
+ for num_controls, target_gate in zip(range(1, 4), [cirq.Z, cirq.CZ, cirq.CCZ]):
292
+ assert g.controlled(num_controls) == target_gate**exp
293
+ np.testing.assert_allclose(
294
+ cirq.unitary(cirq.ControlledGate(g, num_controls)),
295
+ cirq.unitary(g.controlled(num_controls)),
296
+ )
297
+ assert op.controlled_by(*q[:num_controls]) == target_gate(*q[:num_controls]) ** exp
298
+ assert g.controlled(control_values=[0]) == cirq.ControlledGate(g, control_values=[0])
299
+ xor_control_values = cirq.SumOfProducts(((0, 0), (1, 1)))
300
+ assert g.controlled(control_values=xor_control_values) == cirq.ControlledGate(
301
+ g, control_values=xor_control_values
302
+ )
cirq/ops/identity.py CHANGED
@@ -42,7 +42,7 @@ class IdentityGate(raw_types.Gate):
42
42
  """Inits IdentityGate.
43
43
 
44
44
  Args:
45
- num_qubits: The number of qubits for the idenity gate.
45
+ num_qubits: The number of qubits for the identity gate.
46
46
  qid_shape: Specifies the dimension of each qid the measurement
47
47
  applies to. The default is 2 for every qubit.
48
48
 
@@ -105,8 +105,8 @@ def test_kraus_channel_repr():
105
105
  repr(x_meas)
106
106
  == """\
107
107
  cirq.KrausChannel(kraus_ops=[\
108
- np.array([[(0.5+0j), (0.5+0j)], [(0.5+0j), (0.5+0j)]], dtype=np.complex64), \
109
- np.array([[(0.5+0j), (-0.5+0j)], [(-0.5+0j), (0.5+0j)]], dtype=np.complex64)], \
108
+ np.array([[(0.5+0j), (0.5+0j)], [(0.5+0j), (0.5+0j)]], dtype=np.dtype('complex64')), \
109
+ np.array([[(0.5+0j), (-0.5+0j)], [(-0.5+0j), (0.5+0j)]], dtype=np.dtype('complex64'))], \
110
110
  key='x_meas')"""
111
111
  )
112
112
 
@@ -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
  from collections import defaultdict
15
16
  from typing import (
16
17
  AbstractSet,
@@ -440,7 +441,7 @@ class PauliSum:
440
441
  def wrap(val: PauliSumLike) -> 'PauliSum':
441
442
  """Convert a `cirq.PauliSumLike` object to a PauliSum
442
443
 
443
- Attemps to convert an existing int, float, complex, `cirq.PauliString`,
444
+ Attempts to convert an existing int, float, complex, `cirq.PauliString`,
444
445
  `cirq.PauliSum` or `cirq.SingleQubitPauliStringGateOperation` into
445
446
  a `cirq.PauliSum` object. For example:
446
447
 
@@ -651,7 +652,7 @@ class PauliSum:
651
652
  if any(abs(p.coefficient.imag) > 0.0001 for p in self):
652
653
  raise NotImplementedError(
653
654
  "Cannot compute expectation value of a non-Hermitian "
654
- "PauliString <{}>. Coefficient must be real.".format(self)
655
+ f"PauliString <{self}>. Coefficient must be real."
655
656
  )
656
657
 
657
658
  # TODO: Avoid enforce specific complex type. This is necessary to
@@ -713,7 +714,7 @@ class PauliSum:
713
714
  if any(abs(p.coefficient.imag) > 0.0001 for p in self):
714
715
  raise NotImplementedError(
715
716
  "Cannot compute expectation value of a non-Hermitian "
716
- "PauliString <{}>. Coefficient must be real.".format(self)
717
+ f"PauliString <{self}>. Coefficient must be real."
717
718
  )
718
719
 
719
720
  # FIXME: Avoid enforce specific complex type. This is necessary to
@@ -839,10 +840,10 @@ class PauliSum:
839
840
  if exponent == 0:
840
841
  return PauliSum(value.LinearDict({frozenset(): 1 + 0j}))
841
842
  if exponent > 0:
842
- base = self.copy()
843
+ result = self.copy()
843
844
  for _ in range(exponent - 1):
844
- base *= base
845
- return base
845
+ result *= self
846
+ return result
846
847
  return NotImplemented
847
848
 
848
849
  def __truediv__(self, a: value.Scalar):