cirq-core 1.6.0.dev20250520054601__py3-none-any.whl → 1.6.0.dev20250520181654__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.

Files changed (289) hide show
  1. cirq/_compat.py +15 -17
  2. cirq/_compat_test.py +6 -9
  3. cirq/_doc.py +2 -2
  4. cirq/_import.py +6 -6
  5. cirq/_version.py +1 -1
  6. cirq/_version_test.py +1 -1
  7. cirq/circuits/_block_diagram_drawer.py +9 -10
  8. cirq/circuits/_box_drawing_character_data.py +6 -8
  9. cirq/circuits/_bucket_priority_queue.py +7 -7
  10. cirq/circuits/circuit.py +118 -125
  11. cirq/circuits/circuit_operation.py +38 -52
  12. cirq/circuits/circuit_test.py +4 -4
  13. cirq/circuits/frozen_circuit.py +13 -23
  14. cirq/circuits/moment.py +23 -29
  15. cirq/circuits/optimization_pass.py +4 -4
  16. cirq/circuits/optimization_pass_test.py +4 -6
  17. cirq/circuits/qasm_output.py +11 -11
  18. cirq/circuits/text_diagram_drawer.py +21 -36
  19. cirq/contrib/acquaintance/bipartite.py +5 -8
  20. cirq/contrib/acquaintance/executor.py +5 -5
  21. cirq/contrib/acquaintance/executor_test.py +3 -3
  22. cirq/contrib/acquaintance/gates.py +16 -26
  23. cirq/contrib/acquaintance/gates_test.py +3 -3
  24. cirq/contrib/acquaintance/mutation_utils.py +4 -4
  25. cirq/contrib/acquaintance/optimizers.py +4 -4
  26. cirq/contrib/acquaintance/permutation.py +15 -27
  27. cirq/contrib/acquaintance/shift.py +3 -3
  28. cirq/contrib/acquaintance/shift_swap_network.py +4 -4
  29. cirq/contrib/acquaintance/strategies/cubic.py +2 -2
  30. cirq/contrib/acquaintance/strategies/quartic_paired.py +6 -6
  31. cirq/contrib/bayesian_network/bayesian_network_gate.py +9 -10
  32. cirq/contrib/circuitdag/circuit_dag.py +2 -2
  33. cirq/contrib/custom_simulators/custom_state_simulator.py +3 -3
  34. cirq/contrib/custom_simulators/custom_state_simulator_test.py +4 -4
  35. cirq/contrib/graph_device/graph_device.py +5 -5
  36. cirq/contrib/graph_device/hypergraph.py +12 -12
  37. cirq/contrib/graph_device/uniform_graph_device.py +4 -4
  38. cirq/contrib/paulistring/clifford_optimize.py +2 -2
  39. cirq/contrib/paulistring/clifford_target_gateset.py +7 -7
  40. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +31 -31
  41. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +23 -23
  42. cirq/contrib/paulistring/recombine.py +3 -3
  43. cirq/contrib/paulistring/separate.py +2 -2
  44. cirq/contrib/qasm_import/_parser.py +20 -32
  45. cirq/contrib/qcircuit/qcircuit_diagram_info.py +3 -5
  46. cirq/contrib/quantum_volume/quantum_volume.py +24 -24
  47. cirq/contrib/quimb/density_matrix.py +12 -14
  48. cirq/contrib/quimb/mps_simulator.py +20 -20
  49. cirq/contrib/quimb/state_vector.py +6 -10
  50. cirq/contrib/quirk/export_to_quirk.py +3 -3
  51. cirq/contrib/quirk/quirk_gate.py +15 -15
  52. cirq/contrib/routing/device.py +3 -3
  53. cirq/contrib/routing/greedy.py +10 -21
  54. cirq/contrib/routing/initialization.py +2 -2
  55. cirq/contrib/routing/swap_network.py +3 -3
  56. cirq/contrib/routing/utils.py +2 -2
  57. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +8 -8
  58. cirq/contrib/svg/svg.py +3 -3
  59. cirq/devices/grid_device_metadata.py +10 -10
  60. cirq/devices/grid_qubit.py +20 -20
  61. cirq/devices/insertion_noise_model.py +5 -5
  62. cirq/devices/line_qubit.py +13 -13
  63. cirq/devices/named_topologies.py +18 -29
  64. cirq/devices/noise_model.py +3 -3
  65. cirq/devices/noise_properties.py +2 -2
  66. cirq/devices/noise_properties_test.py +1 -3
  67. cirq/devices/noise_utils.py +7 -7
  68. cirq/devices/superconducting_qubits_noise_properties.py +21 -21
  69. cirq/devices/superconducting_qubits_noise_properties_test.py +5 -7
  70. cirq/devices/thermal_noise_model.py +14 -14
  71. cirq/devices/unconstrained_device.py +2 -2
  72. cirq/experiments/benchmarking/parallel_xeb.py +29 -31
  73. cirq/experiments/n_qubit_tomography.py +5 -7
  74. cirq/experiments/qubit_characterizations.py +29 -40
  75. cirq/experiments/qubit_characterizations_test.py +1 -1
  76. cirq/experiments/random_quantum_circuit_generation.py +19 -33
  77. cirq/experiments/random_quantum_circuit_generation_test.py +6 -6
  78. cirq/experiments/readout_confusion_matrix.py +14 -14
  79. cirq/experiments/single_qubit_readout_calibration.py +12 -12
  80. cirq/experiments/t2_decay_experiment.py +7 -7
  81. cirq/experiments/two_qubit_xeb.py +32 -32
  82. cirq/experiments/two_qubit_xeb_test.py +5 -5
  83. cirq/experiments/xeb_fitting.py +25 -25
  84. cirq/experiments/xeb_sampling.py +22 -33
  85. cirq/experiments/xeb_simulation.py +5 -5
  86. cirq/experiments/xeb_simulation_test.py +3 -3
  87. cirq/experiments/z_phase_calibration.py +19 -19
  88. cirq/interop/quirk/cells/arithmetic_cells.py +23 -36
  89. cirq/interop/quirk/cells/cell.py +9 -21
  90. cirq/interop/quirk/cells/composite_cell.py +7 -22
  91. cirq/interop/quirk/cells/control_cells.py +8 -8
  92. cirq/interop/quirk/cells/input_cells.py +4 -4
  93. cirq/interop/quirk/cells/input_rotation_cells.py +5 -5
  94. cirq/interop/quirk/cells/parse.py +20 -23
  95. cirq/interop/quirk/cells/qubit_permutation_cells.py +3 -3
  96. cirq/interop/quirk/cells/swap_cell.py +3 -3
  97. cirq/interop/quirk/cells/testing.py +5 -7
  98. cirq/interop/quirk/url_to_circuit.py +17 -33
  99. cirq/json_resolver_cache.py +6 -6
  100. cirq/linalg/decompositions.py +20 -31
  101. cirq/linalg/diagonalize.py +4 -4
  102. cirq/linalg/diagonalize_test.py +3 -4
  103. cirq/linalg/operator_spaces.py +5 -5
  104. cirq/linalg/predicates.py +7 -7
  105. cirq/linalg/transformations.py +20 -20
  106. cirq/ops/arithmetic_operation.py +13 -15
  107. cirq/ops/boolean_hamiltonian.py +17 -17
  108. cirq/ops/classically_controlled_operation.py +13 -25
  109. cirq/ops/clifford_gate.py +31 -35
  110. cirq/ops/clifford_gate_test.py +2 -3
  111. cirq/ops/common_channels.py +30 -32
  112. cirq/ops/common_gates.py +64 -74
  113. cirq/ops/control_values.py +12 -12
  114. cirq/ops/controlled_gate.py +15 -30
  115. cirq/ops/controlled_gate_test.py +5 -5
  116. cirq/ops/controlled_operation.py +12 -25
  117. cirq/ops/controlled_operation_test.py +5 -5
  118. cirq/ops/dense_pauli_string.py +23 -34
  119. cirq/ops/dense_pauli_string_test.py +1 -2
  120. cirq/ops/diagonal_gate.py +9 -20
  121. cirq/ops/diagonal_gate_test.py +1 -3
  122. cirq/ops/eigen_gate.py +11 -23
  123. cirq/ops/eigen_gate_test.py +6 -8
  124. cirq/ops/fourier_transform.py +5 -5
  125. cirq/ops/fsim_gate.py +14 -14
  126. cirq/ops/gate_operation.py +23 -44
  127. cirq/ops/gateset.py +23 -37
  128. cirq/ops/gateset_test.py +2 -2
  129. cirq/ops/global_phase_op.py +8 -10
  130. cirq/ops/greedy_qubit_manager.py +6 -6
  131. cirq/ops/identity.py +9 -9
  132. cirq/ops/kraus_channel.py +7 -7
  133. cirq/ops/linear_combinations.py +29 -48
  134. cirq/ops/matrix_gates.py +8 -8
  135. cirq/ops/measure_util.py +13 -14
  136. cirq/ops/measurement_gate.py +18 -29
  137. cirq/ops/mixed_unitary_channel.py +8 -8
  138. cirq/ops/named_qubit.py +10 -10
  139. cirq/ops/op_tree.py +7 -7
  140. cirq/ops/parallel_gate.py +5 -5
  141. cirq/ops/parity_gates.py +14 -14
  142. cirq/ops/pauli_gates.py +8 -10
  143. cirq/ops/pauli_interaction_gate.py +6 -6
  144. cirq/ops/pauli_measurement_gate.py +11 -23
  145. cirq/ops/pauli_string.py +35 -52
  146. cirq/ops/pauli_string_phasor.py +4 -14
  147. cirq/ops/pauli_string_raw_types.py +3 -3
  148. cirq/ops/pauli_sum_exponential.py +2 -2
  149. cirq/ops/permutation_gate.py +4 -4
  150. cirq/ops/phased_iswap_gate.py +9 -9
  151. cirq/ops/phased_x_gate.py +10 -10
  152. cirq/ops/phased_x_z_gate.py +11 -11
  153. cirq/ops/projector.py +6 -6
  154. cirq/ops/qubit_manager.py +6 -6
  155. cirq/ops/qubit_order.py +3 -3
  156. cirq/ops/random_gate_channel.py +4 -4
  157. cirq/ops/raw_types.py +48 -70
  158. cirq/ops/state_preparation_channel.py +3 -3
  159. cirq/ops/swap_gates.py +9 -9
  160. cirq/ops/tags.py +2 -4
  161. cirq/ops/three_qubit_gates.py +20 -38
  162. cirq/ops/two_qubit_diagonal_gate.py +5 -5
  163. cirq/ops/uniform_superposition_gate.py +2 -2
  164. cirq/ops/wait_gate.py +5 -5
  165. cirq/protocols/act_on_protocol_test.py +3 -3
  166. cirq/protocols/apply_channel_protocol.py +8 -14
  167. cirq/protocols/apply_mixture_protocol.py +14 -16
  168. cirq/protocols/apply_mixture_protocol_test.py +5 -6
  169. cirq/protocols/apply_unitary_protocol.py +17 -19
  170. cirq/protocols/circuit_diagram_info_protocol.py +19 -30
  171. cirq/protocols/decompose_protocol.py +30 -34
  172. cirq/protocols/inverse_protocol.py +7 -7
  173. cirq/protocols/json_serialization.py +32 -51
  174. cirq/protocols/json_serialization_test.py +9 -10
  175. cirq/protocols/kraus_protocol.py +4 -4
  176. cirq/protocols/kraus_protocol_test.py +3 -3
  177. cirq/protocols/measurement_key_protocol.py +11 -13
  178. cirq/protocols/mixture_protocol.py +4 -4
  179. cirq/protocols/qasm.py +11 -13
  180. cirq/protocols/qid_shape_protocol.py +6 -8
  181. cirq/qis/clifford_tableau.py +12 -12
  182. cirq/qis/measures.py +7 -7
  183. cirq/qis/quantum_state_representation.py +3 -3
  184. cirq/qis/states.py +51 -51
  185. cirq/sim/classical_simulator.py +10 -10
  186. cirq/sim/clifford/clifford_simulator.py +6 -6
  187. cirq/sim/clifford/clifford_tableau_simulation_state_test.py +1 -3
  188. cirq/sim/clifford/stabilizer_sampler.py +4 -4
  189. cirq/sim/clifford/stabilizer_state_ch_form.py +3 -3
  190. cirq/sim/density_matrix_simulation_state.py +15 -15
  191. cirq/sim/density_matrix_simulator.py +11 -11
  192. cirq/sim/density_matrix_utils.py +9 -9
  193. cirq/sim/mux.py +9 -9
  194. cirq/sim/simulation_product_state.py +9 -9
  195. cirq/sim/simulation_product_state_test.py +2 -2
  196. cirq/sim/simulation_state.py +14 -27
  197. cirq/sim/simulation_state_base.py +8 -24
  198. cirq/sim/simulation_utils.py +3 -4
  199. cirq/sim/simulator.py +28 -43
  200. cirq/sim/simulator_base.py +12 -25
  201. cirq/sim/simulator_base_test.py +6 -6
  202. cirq/sim/simulator_test.py +7 -7
  203. cirq/sim/sparse_simulator.py +8 -8
  204. cirq/sim/state_vector.py +8 -8
  205. cirq/sim/state_vector_simulation_state.py +17 -17
  206. cirq/sim/state_vector_simulator.py +4 -4
  207. cirq/study/flatten_expressions.py +12 -14
  208. cirq/study/resolver.py +9 -11
  209. cirq/study/result.py +11 -24
  210. cirq/study/sweepable.py +5 -5
  211. cirq/study/sweeps.py +27 -40
  212. cirq/testing/circuit_compare.py +5 -5
  213. cirq/testing/consistent_controlled_gate_op_test.py +7 -11
  214. cirq/testing/consistent_protocols.py +10 -10
  215. cirq/testing/consistent_protocols_test.py +7 -7
  216. cirq/testing/consistent_qasm.py +4 -4
  217. cirq/testing/consistent_qasm_test.py +2 -3
  218. cirq/testing/devices.py +4 -5
  219. cirq/testing/equals_tester.py +2 -2
  220. cirq/testing/equivalent_basis_map.py +4 -4
  221. cirq/testing/equivalent_repr_eval.py +3 -3
  222. cirq/testing/json.py +14 -14
  223. cirq/testing/logs.py +3 -3
  224. cirq/testing/no_identifier_qubit.py +2 -3
  225. cirq/testing/random_circuit.py +7 -7
  226. cirq/testing/random_circuit_test.py +3 -3
  227. cirq/transformers/analytical_decompositions/clifford_decomposition.py +16 -16
  228. cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +13 -13
  229. cirq/transformers/analytical_decompositions/cphase_to_fsim.py +5 -5
  230. cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +3 -3
  231. cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +3 -3
  232. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +4 -4
  233. cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +6 -7
  234. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry.py +2 -2
  235. cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +7 -7
  236. cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +4 -4
  237. cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +7 -7
  238. cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +11 -11
  239. cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +5 -5
  240. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +14 -14
  241. cirq/transformers/dynamical_decoupling.py +13 -13
  242. cirq/transformers/dynamical_decoupling_test.py +4 -4
  243. cirq/transformers/eject_phased_paulis.py +16 -16
  244. cirq/transformers/eject_z.py +5 -7
  245. cirq/transformers/gauge_compiling/gauge_compiling.py +38 -38
  246. cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +2 -2
  247. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +8 -8
  248. cirq/transformers/insertion_sort.py +5 -5
  249. cirq/transformers/measurement_transformers.py +14 -14
  250. cirq/transformers/merge_k_qubit_gates_test.py +1 -3
  251. cirq/transformers/merge_single_qubit_gates_test.py +1 -3
  252. cirq/transformers/qubit_management_transformers.py +5 -5
  253. cirq/transformers/routing/initial_mapper.py +4 -4
  254. cirq/transformers/routing/line_initial_mapper.py +9 -9
  255. cirq/transformers/routing/mapping_manager.py +7 -7
  256. cirq/transformers/routing/route_circuit_cqc.py +27 -27
  257. cirq/transformers/routing/visualize_routed_circuit.py +4 -4
  258. cirq/transformers/stratify.py +8 -8
  259. cirq/transformers/synchronize_terminal_measurements.py +6 -6
  260. cirq/transformers/target_gatesets/compilation_target_gateset.py +8 -8
  261. cirq/transformers/target_gatesets/compilation_target_gateset_test.py +2 -2
  262. cirq/transformers/target_gatesets/cz_gateset.py +4 -4
  263. cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +5 -5
  264. cirq/transformers/transformer_api.py +11 -26
  265. cirq/transformers/transformer_primitives.py +24 -36
  266. cirq/transformers/transformer_primitives_test.py +3 -3
  267. cirq/value/classical_data.py +18 -18
  268. cirq/value/condition.py +8 -8
  269. cirq/value/digits.py +7 -7
  270. cirq/value/duration.py +12 -12
  271. cirq/value/linear_dict.py +8 -12
  272. cirq/value/measurement_key.py +8 -8
  273. cirq/value/product_state.py +9 -9
  274. cirq/value/value_equality_attr.py +4 -4
  275. cirq/vis/heatmap.py +23 -35
  276. cirq/work/collector.py +9 -17
  277. cirq/work/observable_grouping.py +4 -7
  278. cirq/work/observable_measurement.py +29 -41
  279. cirq/work/observable_measurement_data.py +14 -14
  280. cirq/work/observable_measurement_test.py +2 -2
  281. cirq/work/observable_settings.py +9 -10
  282. cirq/work/pauli_sum_collector.py +5 -5
  283. cirq/work/sampler.py +17 -17
  284. cirq/work/zeros_sampler.py +3 -3
  285. {cirq_core-1.6.0.dev20250520054601.dist-info → cirq_core-1.6.0.dev20250520181654.dist-info}/METADATA +1 -1
  286. {cirq_core-1.6.0.dev20250520054601.dist-info → cirq_core-1.6.0.dev20250520181654.dist-info}/RECORD +289 -289
  287. {cirq_core-1.6.0.dev20250520054601.dist-info → cirq_core-1.6.0.dev20250520181654.dist-info}/WHEEL +1 -1
  288. {cirq_core-1.6.0.dev20250520054601.dist-info → cirq_core-1.6.0.dev20250520181654.dist-info}/licenses/LICENSE +0 -0
  289. {cirq_core-1.6.0.dev20250520054601.dist-info → cirq_core-1.6.0.dev20250520181654.dist-info}/top_level.txt +0 -0
@@ -18,18 +18,7 @@ from __future__ import annotations
18
18
 
19
19
  import cmath
20
20
  import math
21
- from typing import (
22
- Any,
23
- Callable,
24
- cast,
25
- Iterable,
26
- List,
27
- Optional,
28
- Tuple,
29
- TYPE_CHECKING,
30
- TypeVar,
31
- Union,
32
- )
21
+ from typing import Any, Callable, cast, Iterable, TYPE_CHECKING, TypeVar
33
22
 
34
23
  import matplotlib.pyplot as plt
35
24
  import numpy as np
@@ -70,7 +59,7 @@ def _rotation_matrix(angle: float) -> np.ndarray:
70
59
  return np.array([[c, -s], [s, c]])
71
60
 
72
61
 
73
- def deconstruct_single_qubit_matrix_into_angles(mat: np.ndarray) -> Tuple[float, float, float]:
62
+ def deconstruct_single_qubit_matrix_into_angles(mat: np.ndarray) -> tuple[float, float, float]:
74
63
  r"""Breaks down a 2x2 unitary into ZYZ angle parameters.
75
64
 
76
65
  Given a unitary U, this function returns three angles: $\phi_0, \phi_1, \phi_2$,
@@ -108,7 +97,7 @@ def deconstruct_single_qubit_matrix_into_angles(mat: np.ndarray) -> Tuple[float,
108
97
 
109
98
  def unitary_eig(
110
99
  matrix: np.ndarray, check_preconditions: bool = True, atol: float = 1e-8
111
- ) -> Tuple[np.ndarray, np.ndarray]:
100
+ ) -> tuple[np.ndarray, np.ndarray]:
112
101
  r"""Gives the guaranteed unitary eigendecomposition of a normal matrix.
113
102
 
114
103
  All hermitian and unitary matrices are normal matrices. This method was
@@ -169,7 +158,7 @@ def map_eigenvalues(
169
158
 
170
159
  def kron_factor_4x4_to_2x2s(
171
160
  matrix: np.ndarray, rtol=1e-5, atol=1e-8
172
- ) -> Tuple[complex, np.ndarray, np.ndarray]:
161
+ ) -> tuple[complex, np.ndarray, np.ndarray]:
173
162
  """Splits a 4x4 matrix U = kron(A, B) into A, B, and a global factor.
174
163
 
175
164
  Requires the matrix to be the kronecker product of two 2x2 unitaries.
@@ -219,7 +208,7 @@ def kron_factor_4x4_to_2x2s(
219
208
 
220
209
  def so4_to_magic_su2s(
221
210
  mat: np.ndarray, *, rtol: float = 1e-5, atol: float = 1e-8, check_preconditions: bool = True
222
- ) -> Tuple[np.ndarray, np.ndarray]:
211
+ ) -> tuple[np.ndarray, np.ndarray]:
223
212
  """Finds 2x2 special-unitaries A, B where mat = Mag.H @ kron(A, B) @ Mag.
224
213
 
225
214
  Mag is the magic basis matrix:
@@ -265,7 +254,7 @@ class AxisAngleDecomposition:
265
254
  rotation axis, and g is the global phase.
266
255
  """
267
256
 
268
- def __init__(self, *, angle: float, axis: Tuple[float, float, float], global_phase: complex):
257
+ def __init__(self, *, angle: float, axis: tuple[float, float, float], global_phase: complex):
269
258
  if not np.isclose(np.linalg.norm(axis, 2), 1, atol=1e-8):
270
259
  raise ValueError('Axis vector must be normalized.')
271
260
  self.global_phase = complex(global_phase)
@@ -413,9 +402,9 @@ class KakDecomposition:
413
402
  self,
414
403
  *,
415
404
  global_phase: complex = complex(1),
416
- single_qubit_operations_before: Optional[Tuple[np.ndarray, np.ndarray]] = None,
417
- interaction_coefficients: Tuple[float, float, float],
418
- single_qubit_operations_after: Optional[Tuple[np.ndarray, np.ndarray]] = None,
405
+ single_qubit_operations_before: tuple[np.ndarray, np.ndarray] | None = None,
406
+ interaction_coefficients: tuple[float, float, float],
407
+ single_qubit_operations_after: tuple[np.ndarray, np.ndarray] | None = None,
419
408
  ):
420
409
  """Initializes a decomposition for a two-qubit operation U.
421
410
 
@@ -428,12 +417,12 @@ class KakDecomposition:
428
417
  single_qubit_operations_after: a0, a1 from the above equation.
429
418
  """
430
419
  self.global_phase: complex = global_phase
431
- self.single_qubit_operations_before: Tuple[np.ndarray, np.ndarray] = (
420
+ self.single_qubit_operations_before: tuple[np.ndarray, np.ndarray] = (
432
421
  single_qubit_operations_before
433
422
  or (np.eye(2, dtype=np.complex64), np.eye(2, dtype=np.complex64))
434
423
  )
435
424
  self.interaction_coefficients = interaction_coefficients
436
- self.single_qubit_operations_after: Tuple[np.ndarray, np.ndarray] = (
425
+ self.single_qubit_operations_after: tuple[np.ndarray, np.ndarray] = (
437
426
  single_qubit_operations_after
438
427
  or (np.eye(2, dtype=np.complex64), np.eye(2, dtype=np.complex64))
439
428
  )
@@ -525,10 +514,10 @@ class KakDecomposition:
525
514
 
526
515
 
527
516
  def scatter_plot_normalized_kak_interaction_coefficients(
528
- interactions: Iterable[Union[np.ndarray, cirq.SupportsUnitary, KakDecomposition]],
517
+ interactions: Iterable[np.ndarray | cirq.SupportsUnitary | KakDecomposition],
529
518
  *,
530
519
  include_frame: bool = True,
531
- ax: Optional[mplot3d.axes3d.Axes3D] = None,
520
+ ax: mplot3d.axes3d.Axes3D | None = None,
532
521
  **kwargs,
533
522
  ):
534
523
  r"""Plots the interaction coefficients of many two-qubit operations.
@@ -610,8 +599,8 @@ def scatter_plot_normalized_kak_interaction_coefficients(
610
599
  ax = cast(mplot3d.axes3d.Axes3D, fig.add_subplot(1, 1, 1, projection='3d'))
611
600
 
612
601
  def coord_transform(
613
- pts: Union[List[Tuple[int, int, int]], np.ndarray],
614
- ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
602
+ pts: list[tuple[int, int, int]] | np.ndarray,
603
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
615
604
  if len(pts) == 0:
616
605
  return np.array([]), np.array([]), np.array([])
617
606
  xs, ys, zs = np.transpose(pts)
@@ -637,7 +626,7 @@ def scatter_plot_normalized_kak_interaction_coefficients(
637
626
 
638
627
  # parse input and extract KAK vector
639
628
  if not isinstance(interactions, np.ndarray):
640
- interactions_extracted: List[np.ndarray] = [
629
+ interactions_extracted: list[np.ndarray] = [
641
630
  a if isinstance(a, np.ndarray) else protocols.unitary(a) for a in interactions
642
631
  ]
643
632
  else:
@@ -786,9 +775,9 @@ KAK_GAMMA = np.array([[1, 1, 1, 1],
786
775
 
787
776
 
788
777
  def kak_decomposition(
789
- unitary_object: Union[
790
- np.ndarray, cirq.SupportsUnitary, cirq.Gate, cirq.Operation, KakDecomposition
791
- ],
778
+ unitary_object: (
779
+ np.ndarray | cirq.SupportsUnitary | cirq.Gate | cirq.Operation | KakDecomposition
780
+ ),
792
781
  *,
793
782
  rtol: float = 1e-5,
794
783
  atol: float = 1e-8,
@@ -858,7 +847,7 @@ def kak_decomposition(
858
847
 
859
848
 
860
849
  def kak_vector(
861
- unitary: Union[Iterable[np.ndarray], np.ndarray],
850
+ unitary: Iterable[np.ndarray] | np.ndarray,
862
851
  *,
863
852
  rtol: float = 1e-5,
864
853
  atol: float = 1e-8,
@@ -16,7 +16,7 @@
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
- from typing import Callable, List, Tuple
19
+ from typing import Callable
20
20
 
21
21
  import numpy as np
22
22
 
@@ -54,7 +54,7 @@ def diagonalize_real_symmetric_matrix(
54
54
 
55
55
  def _contiguous_groups(
56
56
  length: int, comparator: Callable[[int, int], bool]
57
- ) -> List[Tuple[int, int]]:
57
+ ) -> list[tuple[int, int]]:
58
58
  """Splits range(length) into approximate equivalence classes.
59
59
 
60
60
  Args:
@@ -157,7 +157,7 @@ def bidiagonalize_real_matrix_pair_with_symmetric_products(
157
157
  rtol: float = 1e-5,
158
158
  atol: float = 1e-8,
159
159
  check_preconditions: bool = True,
160
- ) -> Tuple[np.ndarray, np.ndarray]:
160
+ ) -> tuple[np.ndarray, np.ndarray]:
161
161
  """Finds orthogonal matrices that diagonalize both mat1 and mat2.
162
162
 
163
163
  Requires mat1 and mat2 to be real.
@@ -228,7 +228,7 @@ def bidiagonalize_real_matrix_pair_with_symmetric_products(
228
228
 
229
229
  def bidiagonalize_unitary_with_special_orthogonals(
230
230
  mat: np.ndarray, *, rtol: float = 1e-5, atol: float = 1e-8, check_preconditions: bool = True
231
- ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
231
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
232
232
  """Finds orthogonal matrices L, R such that L @ matrix @ R is diagonal.
233
233
 
234
234
  Args:
@@ -15,7 +15,6 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import random
18
- from typing import Optional, Tuple
19
18
 
20
19
  import numpy as np
21
20
  import pytest
@@ -31,7 +30,7 @@ CNOT = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]])
31
30
  QFT = np.array([[1, 1, 1, 1], [1, 1j, -1, -1j], [1, -1, 1, -1], [1, -1j, -1, 1j]]) * 0.5
32
31
 
33
32
 
34
- def random_real_diagonal_matrix(n: int, d: Optional[int] = None) -> np.ndarray:
33
+ def random_real_diagonal_matrix(n: int, d: int | None = None) -> np.ndarray:
35
34
  return np.diag([random.random() if d is None or k < d else 0 for k in range(n)])
36
35
 
37
36
 
@@ -50,8 +49,8 @@ def random_block_diagonal_symmetric_matrix(*ns: int) -> np.ndarray:
50
49
 
51
50
 
52
51
  def random_bi_diagonalizable_pair(
53
- n: int, d1: Optional[int] = None, d2: Optional[int] = None
54
- ) -> Tuple[np.ndarray, np.ndarray]:
52
+ n: int, d1: int | None = None, d2: int | None = None
53
+ ) -> tuple[np.ndarray, np.ndarray]:
55
54
  u = cirq.testing.random_orthogonal(n)
56
55
  s = random_real_diagonal_matrix(n, d1)
57
56
  z = random_real_diagonal_matrix(n, d2)
@@ -16,7 +16,7 @@
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
- from typing import Dict, Tuple, TYPE_CHECKING
19
+ from typing import TYPE_CHECKING
20
20
 
21
21
  import numpy as np
22
22
  import sympy
@@ -36,7 +36,7 @@ PAULI_BASIS = {
36
36
  document(PAULI_BASIS, """The four Pauli matrices (including identity) keyed by character.""")
37
37
 
38
38
 
39
- def kron_bases(*bases: Dict[str, np.ndarray], repeat: int = 1) -> Dict[str, np.ndarray]:
39
+ def kron_bases(*bases: dict[str, np.ndarray], repeat: int = 1) -> dict[str, np.ndarray]:
40
40
  """Creates tensor product of bases."""
41
41
  product_basis = {'': np.array([[1]])}
42
42
  for basis in bases * repeat:
@@ -57,7 +57,7 @@ def hilbert_schmidt_inner_product(m1: np.ndarray, m2: np.ndarray) -> complex:
57
57
 
58
58
 
59
59
  def expand_matrix_in_orthogonal_basis(
60
- m: np.ndarray, basis: Dict[str, np.ndarray]
60
+ m: np.ndarray, basis: dict[str, np.ndarray]
61
61
  ) -> value.LinearDict[str]:
62
62
  """Computes coefficients of expansion of m in basis.
63
63
 
@@ -74,7 +74,7 @@ def expand_matrix_in_orthogonal_basis(
74
74
 
75
75
 
76
76
  def matrix_from_basis_coefficients(
77
- expansion: value.LinearDict[str], basis: Dict[str, np.ndarray]
77
+ expansion: value.LinearDict[str], basis: dict[str, np.ndarray]
78
78
  ) -> np.ndarray:
79
79
  """Computes linear combination of basis vectors with given coefficients."""
80
80
  some_element = next(iter(basis.values()))
@@ -90,7 +90,7 @@ def pow_pauli_combination(
90
90
  ay: cirq.TParamValComplex,
91
91
  az: cirq.TParamValComplex,
92
92
  exponent: int,
93
- ) -> Tuple[
93
+ ) -> tuple[
94
94
  cirq.TParamValComplex, cirq.TParamValComplex, cirq.TParamValComplex, cirq.TParamValComplex
95
95
  ]:
96
96
  """Computes non-negative integer power of single-qubit Pauli combination.
cirq/linalg/predicates.py CHANGED
@@ -17,7 +17,7 @@
17
17
  from __future__ import annotations
18
18
 
19
19
  from types import EllipsisType
20
- from typing import cast, List, Optional, Sequence, Tuple, Union
20
+ from typing import cast, Sequence, Union
21
21
 
22
22
  import numpy as np
23
23
 
@@ -231,9 +231,9 @@ def slice_for_qubits_equal_to(
231
231
  little_endian_qureg_value: int = 0,
232
232
  *, # Forces keyword args.
233
233
  big_endian_qureg_value: int = 0,
234
- num_qubits: Optional[int] = None,
235
- qid_shape: Optional[Tuple[int, ...]] = None,
236
- ) -> Tuple[Union[slice, int, EllipsisType], ...]:
234
+ num_qubits: int | None = None,
235
+ qid_shape: tuple[int, ...] | None = None,
236
+ ) -> tuple[slice | int | EllipsisType, ...]:
237
237
  """Returns an index corresponding to a desired subset of an np.ndarray.
238
238
 
239
239
  It is assumed that the np.ndarray's shape is of the form (2, 2, 2, ..., 2).
@@ -288,10 +288,10 @@ def slice_for_qubits_equal_to(
288
288
  qid_shape_specified = qid_shape is not None
289
289
  if qid_shape is not None or num_qubits is not None:
290
290
  if num_qubits is None:
291
- num_qubits = len(cast(Tuple[int, ...], qid_shape))
291
+ num_qubits = len(cast(tuple[int, ...], qid_shape))
292
292
  elif qid_shape is None:
293
293
  qid_shape = (2,) * num_qubits
294
- if num_qubits != len(cast(Tuple[int, ...], qid_shape)):
294
+ if num_qubits != len(cast(tuple[int, ...], qid_shape)):
295
295
  raise ValueError('len(qid_shape) != num_qubits')
296
296
  if little_endian_qureg_value and big_endian_qureg_value:
297
297
  raise ValueError(
@@ -302,7 +302,7 @@ def slice_for_qubits_equal_to(
302
302
  out_size = (
303
303
  cast(int, num_qubits) if out_size_specified else max(target_qubit_axes, default=-1) + 1
304
304
  )
305
- result = cast(List[Union[slice, int, EllipsisType]], [slice(None)] * out_size)
305
+ result = cast(list[Union[slice, int, EllipsisType]], [slice(None)] * out_size)
306
306
  if not out_size_specified:
307
307
  result.append(Ellipsis)
308
308
  if qid_shape is None:
@@ -19,7 +19,7 @@ from __future__ import annotations
19
19
  import dataclasses
20
20
  import functools
21
21
  from types import EllipsisType
22
- from typing import Any, List, Optional, Sequence, Tuple, Union
22
+ from typing import Any, Sequence
23
23
 
24
24
  import numpy as np
25
25
 
@@ -62,7 +62,7 @@ def reflection_matrix_pow(reflection_matrix: np.ndarray, exponent: float):
62
62
  return pos_part_raised + neg_part_raised
63
63
 
64
64
 
65
- def match_global_phase(a: np.ndarray, b: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
65
+ def match_global_phase(a: np.ndarray, b: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
66
66
  """Phases the given matrices so that they agree on the phase of one entry.
67
67
 
68
68
  To maximize precision, the position with the largest entry from one of the
@@ -104,7 +104,7 @@ def targeted_left_multiply(
104
104
  left_matrix: np.ndarray,
105
105
  right_target: np.ndarray,
106
106
  target_axes: Sequence[int],
107
- out: Optional[np.ndarray] = None,
107
+ out: np.ndarray | None = None,
108
108
  ) -> np.ndarray:
109
109
  """Left-multiplies the given axes of the target tensor by the given matrix.
110
110
 
@@ -179,7 +179,7 @@ class _SliceConfig:
179
179
 
180
180
  @dataclasses.dataclass
181
181
  class _BuildFromSlicesArgs:
182
- slices: Tuple[_SliceConfig, ...]
182
+ slices: tuple[_SliceConfig, ...]
183
183
  scale: complex
184
184
 
185
185
 
@@ -237,8 +237,8 @@ def _build_from_slices(
237
237
  d = len(source.shape)
238
238
  out[...] = 0
239
239
  for arg in args:
240
- source_slice: List[Any] = [slice(None)] * d
241
- target_slice: List[Any] = [slice(None)] * d
240
+ source_slice: list[Any] = [slice(None)] * d
241
+ target_slice: list[Any] = [slice(None)] * d
242
242
  for sleis in arg.slices:
243
243
  source_slice[sleis.axis] = sleis.source_index
244
244
  target_slice[sleis.axis] = sleis.target_index
@@ -250,9 +250,9 @@ def targeted_conjugate_about(
250
250
  tensor: np.ndarray,
251
251
  target: np.ndarray,
252
252
  indices: Sequence[int],
253
- conj_indices: Optional[Sequence[int]] = None,
254
- buffer: Optional[np.ndarray] = None,
255
- out: Optional[np.ndarray] = None,
253
+ conj_indices: Sequence[int] | None = None,
254
+ buffer: np.ndarray | None = None,
255
+ out: np.ndarray | None = None,
256
256
  ) -> np.ndarray:
257
257
  r"""Conjugates the given tensor about the target tensor.
258
258
 
@@ -301,8 +301,8 @@ def targeted_conjugate_about(
301
301
  return targeted_left_multiply(np.conjugate(tensor), first_multiply, conj_indices, out=out)
302
302
 
303
303
 
304
- _TSliceAtom = Union[int, slice, EllipsisType]
305
- _TSlice = Union[_TSliceAtom, Sequence[_TSliceAtom]]
304
+ _TSliceAtom = int | slice | EllipsisType
305
+ _TSlice = _TSliceAtom | Sequence[_TSliceAtom]
306
306
 
307
307
 
308
308
  def apply_matrix_to_slices(
@@ -310,7 +310,7 @@ def apply_matrix_to_slices(
310
310
  matrix: np.ndarray,
311
311
  slices: Sequence[_TSlice],
312
312
  *,
313
- out: Optional[np.ndarray] = None,
313
+ out: np.ndarray | None = None,
314
314
  ) -> np.ndarray:
315
315
  r"""Left-multiplies an NxN matrix onto N slices of a numpy array.
316
316
 
@@ -420,8 +420,8 @@ class EntangledStateError(ValueError):
420
420
 
421
421
 
422
422
  def partial_trace_of_state_vector_as_mixture(
423
- state_vector: np.ndarray, keep_indices: List[int], *, atol: float = 1e-8
424
- ) -> Tuple[Tuple[float, np.ndarray], ...]:
423
+ state_vector: np.ndarray, keep_indices: list[int], *, atol: float = 1e-8
424
+ ) -> tuple[tuple[float, np.ndarray], ...]:
425
425
  """Returns a mixture representing a state vector with only some qubits kept.
426
426
 
427
427
  The input state vector can have any shape, but if it is one-dimensional it
@@ -455,7 +455,7 @@ def partial_trace_of_state_vector_as_mixture(
455
455
  if 2**dims != state_vector.size:
456
456
  raise ValueError(f'Cannot infer underlying shape of {state_vector.shape}.')
457
457
  state_vector = state_vector.reshape((2,) * dims)
458
- ret_shape: Tuple[int, ...] = (2 ** len(keep_indices),)
458
+ ret_shape: tuple[int, ...] = (2 ** len(keep_indices),)
459
459
  else:
460
460
  ret_shape = tuple(state_vector.shape[i] for i in keep_indices)
461
461
 
@@ -476,7 +476,7 @@ def partial_trace_of_state_vector_as_mixture(
476
476
 
477
477
  def sub_state_vector(
478
478
  state_vector: np.ndarray,
479
- keep_indices: List[int],
479
+ keep_indices: list[int],
480
480
  *,
481
481
  default: np.ndarray = RaiseValueErrorIfNotProvided,
482
482
  atol: float = 1e-6,
@@ -536,7 +536,7 @@ def sub_state_vector(
536
536
 
537
537
  n_qubits = int(np.log2(state_vector.size))
538
538
  keep_dims = 1 << len(keep_indices)
539
- ret_shape: Union[Tuple[int], Tuple[int, ...]]
539
+ ret_shape: tuple[int] | tuple[int, ...]
540
540
  if state_vector.shape == (state_vector.size,):
541
541
  ret_shape = (keep_dims,)
542
542
  state_vector = state_vector.reshape((2,) * n_qubits)
@@ -634,7 +634,7 @@ def density_matrix_kronecker_product(t1: np.ndarray, t2: np.ndarray) -> np.ndarr
634
634
 
635
635
  def factor_state_vector(
636
636
  t: np.ndarray, axes: Sequence[int], *, validate=True, atol=1e-07
637
- ) -> Tuple[np.ndarray, np.ndarray]:
637
+ ) -> tuple[np.ndarray, np.ndarray]:
638
638
  """Factors a state vector into two independent state vectors.
639
639
 
640
640
  This function should only be called on state vectors that are known to be
@@ -680,7 +680,7 @@ def factor_state_vector(
680
680
 
681
681
  def factor_density_matrix(
682
682
  t: np.ndarray, axes: Sequence[int], *, validate=True, atol=1e-07
683
- ) -> Tuple[np.ndarray, np.ndarray]:
683
+ ) -> tuple[np.ndarray, np.ndarray]:
684
684
  """Factors a density matrix into two independent density matrices.
685
685
 
686
686
  This function should only be called on density matrices that are known to
@@ -748,7 +748,7 @@ def transpose_density_matrix_to_axis_order(t: np.ndarray, axes: Sequence[int]):
748
748
  return transpose_state_vector_to_axis_order(t, axes)
749
749
 
750
750
 
751
- def _volumes(shape: Sequence[int]) -> List[int]:
751
+ def _volumes(shape: Sequence[int]) -> list[int]:
752
752
  r"""Returns a list of the volume spanned by each dimension.
753
753
 
754
754
  Given a shape=[d_0, d_1, .., d_n] the volume spanned by each dimension is
@@ -17,7 +17,7 @@ from __future__ import annotations
17
17
 
18
18
  import abc
19
19
  import itertools
20
- from typing import cast, Iterable, List, Sequence, Tuple, TYPE_CHECKING, Union
20
+ from typing import cast, Iterable, Sequence, TYPE_CHECKING
21
21
 
22
22
  import numpy as np
23
23
  from typing_extensions import Self
@@ -88,7 +88,7 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
88
88
  """
89
89
 
90
90
  @abc.abstractmethod
91
- def registers(self) -> Sequence[Union[int, Sequence[int]]]:
91
+ def registers(self) -> Sequence[int | Sequence[int]]:
92
92
  """The data acted upon by the arithmetic gate.
93
93
 
94
94
  Each register in the list can either be a classical constant (an `int`),
@@ -105,7 +105,7 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
105
105
  raise NotImplementedError()
106
106
 
107
107
  @abc.abstractmethod
108
- def with_registers(self, *new_registers: Union[int, Sequence[int]]) -> Self:
108
+ def with_registers(self, *new_registers: int | Sequence[int]) -> Self:
109
109
  """Returns the same fate targeting different registers.
110
110
 
111
111
  Args:
@@ -119,7 +119,7 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
119
119
  raise NotImplementedError()
120
120
 
121
121
  @abc.abstractmethod
122
- def apply(self, *register_values: int) -> Union[int, Iterable[int]]:
122
+ def apply(self, *register_values: int) -> int | Iterable[int]:
123
123
  """Returns the result of the gate operating on classical values.
124
124
 
125
125
  For example, an addition takes two values (the target and the source),
@@ -164,7 +164,7 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
164
164
  """
165
165
  raise NotImplementedError()
166
166
 
167
- def _qid_shape_(self) -> Tuple[int, ...]:
167
+ def _qid_shape_(self) -> tuple[int, ...]:
168
168
  shape = []
169
169
  for r in self.registers():
170
170
  if isinstance(r, Sequence):
@@ -174,9 +174,9 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
174
174
 
175
175
  def _apply_unitary_(self, args: cirq.ApplyUnitaryArgs):
176
176
  registers = self.registers()
177
- input_ranges: List[Sequence[int]] = []
178
- shape: List[int] = []
179
- overflow_sizes: List[int] = []
177
+ input_ranges: list[Sequence[int]] = []
178
+ shape: list[int] = []
179
+ overflow_sizes: list[int] = []
180
180
  for register in registers:
181
181
  if isinstance(register, int):
182
182
  input_ranges.append([register])
@@ -198,8 +198,8 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
198
198
  output = self.apply(*input_seq)
199
199
 
200
200
  # Wrap into list.
201
- inputs: List[int] = list(input_seq)
202
- outputs: List[int] = [output] if isinstance(output, int) else list(output)
201
+ inputs: list[int] = list(input_seq)
202
+ outputs: list[int] = [output] if isinstance(output, int) else list(output)
203
203
 
204
204
  # Omitted tail values default to the corresponding input value.
205
205
  if len(outputs) < len(inputs):
@@ -221,8 +221,8 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
221
221
  outputs[i] %= overflow_sizes[i]
222
222
 
223
223
  # Copy amplitude to new location.
224
- cast(List[Union[int, slice]], outputs).append(slice(None))
225
- cast(List[Union[int, slice]], inputs).append(slice(None))
224
+ cast(list[int | slice], outputs).append(slice(None))
225
+ cast(list[int | slice], inputs).append(slice(None))
226
226
  dst[tuple(outputs)] = src[tuple(inputs)]
227
227
 
228
228
  # In case the reshaped arrays were copies instead of views.
@@ -233,9 +233,7 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
233
233
 
234
234
 
235
235
  def _describe_bad_arithmetic_changed_const(
236
- registers: Sequence[Union[int, Sequence[Union[cirq.Qid, int]]]],
237
- inputs: List[int],
238
- outputs: List[int],
236
+ registers: Sequence[int | Sequence[cirq.Qid | int]], inputs: list[int], outputs: list[int]
239
237
  ) -> str:
240
238
  from cirq.circuits import TextDiagramDrawer
241
239
 
@@ -27,7 +27,7 @@ from __future__ import annotations
27
27
 
28
28
  import functools
29
29
  import itertools
30
- from typing import Any, Dict, Generator, List, Sequence, Tuple
30
+ from typing import Any, Generator, Sequence
31
31
 
32
32
  import sympy.parsing.sympy_parser as sympy_parser
33
33
 
@@ -80,13 +80,13 @@ class BooleanHamiltonianGate(raw_types.Gate):
80
80
  self._boolean_strs: Sequence[str] = boolean_strs
81
81
  self._theta: float = theta
82
82
 
83
- def _qid_shape_(self) -> Tuple[int, ...]:
83
+ def _qid_shape_(self) -> tuple[int, ...]:
84
84
  return (2,) * len(self._parameter_names)
85
85
 
86
86
  def _value_equality_values_(self) -> Any:
87
87
  return tuple(self._parameter_names), tuple(self._boolean_strs), self._theta
88
88
 
89
- def _json_dict_(self) -> Dict[str, Any]:
89
+ def _json_dict_(self) -> dict[str, Any]:
90
90
  return {
91
91
  'parameter_names': self._parameter_names,
92
92
  'boolean_strs': self._boolean_strs,
@@ -121,7 +121,7 @@ class BooleanHamiltonianGate(raw_types.Gate):
121
121
  )
122
122
 
123
123
 
124
- def _gray_code_comparator(k1: Tuple[int, ...], k2: Tuple[int, ...], flip: bool = False) -> int:
124
+ def _gray_code_comparator(k1: tuple[int, ...], k2: tuple[int, ...], flip: bool = False) -> int:
125
125
  """Compares two Gray-encoded binary numbers.
126
126
 
127
127
  Args:
@@ -144,8 +144,8 @@ def _gray_code_comparator(k1: Tuple[int, ...], k2: Tuple[int, ...], flip: bool =
144
144
 
145
145
 
146
146
  def _simplify_commuting_cnots(
147
- cnots: List[Tuple[int, int]], flip_control_and_target: bool
148
- ) -> Tuple[bool, List[Tuple[int, int]]]:
147
+ cnots: list[tuple[int, int]], flip_control_and_target: bool
148
+ ) -> tuple[bool, list[tuple[int, int]]]:
149
149
  """Attempts to commute CNOTs and remove cancelling pairs.
150
150
 
151
151
  Commutation relations are based on 9 (flip_control_and_target=False) or 10
@@ -184,7 +184,7 @@ def _simplify_commuting_cnots(
184
184
  target, control = (0, 1) if flip_control_and_target else (1, 0)
185
185
 
186
186
  to_remove = set()
187
- qubit_to_index: List[Tuple[int, Dict[int, int]]] = []
187
+ qubit_to_index: list[tuple[int, dict[int, int]]] = []
188
188
  for j in range(len(cnots)):
189
189
  if not qubit_to_index or cnots[j][target] != qubit_to_index[-1][0]:
190
190
  # The targets (resp. control) don't match, so we create a new dict.
@@ -205,8 +205,8 @@ def _simplify_commuting_cnots(
205
205
 
206
206
 
207
207
  def _simplify_cnots_triplets(
208
- cnots: List[Tuple[int, int]], flip_control_and_target: bool
209
- ) -> Tuple[bool, List[Tuple[int, int]]]:
208
+ cnots: list[tuple[int, int]], flip_control_and_target: bool
209
+ ) -> tuple[bool, list[tuple[int, int]]]:
210
210
  """Simplifies CNOT pairs according to equation 11 of [4].
211
211
 
212
212
  CNOT(i, j) @ CNOT(j, k) == CNOT(j, k) @ CNOT(i, k) @ CNOT(i, j)
@@ -231,7 +231,7 @@ def _simplify_cnots_triplets(
231
231
  # First, we look back for as long as the controls (resp. targets) are the same.
232
232
  # They all commute, so all are potential candidates for being simplified.
233
233
  # prev_match_index is qubit to index in `cnots` array.
234
- prev_match_index: Dict[int, int] = {}
234
+ prev_match_index: dict[int, int] = {}
235
235
  for i in range(j - 1, -1, -1):
236
236
  # These CNOTs have the same target (resp. control) and though they are not candidates
237
237
  # for simplification, since they commute, we can keep looking for candidates.
@@ -245,7 +245,7 @@ def _simplify_cnots_triplets(
245
245
  # Next, we look forward for as long as the targets (resp. controls) are the
246
246
  # same. They all commute, so all are potential candidates for being simplified.
247
247
  # post_match_index is qubit to index in `cnots` array.
248
- post_match_index: Dict[int, int] = {}
248
+ post_match_index: dict[int, int] = {}
249
249
  for k in range(j + 1, len(cnots)):
250
250
  # These CNOTs have the same control (resp. target) and though they are not candidates
251
251
  # for simplification, since they commute, we can keep looking for candidates.
@@ -260,7 +260,7 @@ def _simplify_cnots_triplets(
260
260
  keys = prev_match_index.keys() & post_match_index.keys()
261
261
  for key in keys:
262
262
  # We perform the swap which removes the pivot.
263
- new_idx: List[int] = (
263
+ new_idx: list[int] = (
264
264
  # Anything strictly before the pivot that is not the CNOT to swap.
265
265
  [idx for idx in range(j) if idx != prev_match_index[key]]
266
266
  # The two swapped CNOTs.
@@ -275,7 +275,7 @@ def _simplify_cnots_triplets(
275
275
  return False, cnots
276
276
 
277
277
 
278
- def _simplify_cnots(cnots: List[Tuple[int, int]]) -> List[Tuple[int, int]]:
278
+ def _simplify_cnots(cnots: list[tuple[int, int]]) -> list[tuple[int, int]]:
279
279
  """Takes a series of CNOTs and tries to applies rule to cancel out gates.
280
280
 
281
281
  Algorithm based on "Efficient quantum circuits for diagonal unitaries without ancillas" by
@@ -302,7 +302,7 @@ def _simplify_cnots(cnots: List[Tuple[int, int]]) -> List[Tuple[int, int]]:
302
302
 
303
303
 
304
304
  def _get_gates_from_hamiltonians(
305
- hamiltonian_polynomial_list: List[cirq.PauliSum], qubit_map: Dict[str, cirq.Qid], theta: float
305
+ hamiltonian_polynomial_list: list[cirq.PauliSum], qubit_map: dict[str, cirq.Qid], theta: float
306
306
  ) -> Generator[cirq.Operation, None, None]:
307
307
  """Builds a circuit according to [1].
308
308
 
@@ -326,8 +326,8 @@ def _get_gates_from_hamiltonians(
326
326
  qubit_idx = tuple(sorted(qubit_indices[qubit] for qubit in pauli_string.qubits))
327
327
  hamiltonians[qubit_idx] = w
328
328
 
329
- def _apply_cnots(prevh: Tuple[int, ...], currh: Tuple[int, ...]):
330
- cnots: List[Tuple[int, int]] = []
329
+ def _apply_cnots(prevh: tuple[int, ...], currh: tuple[int, ...]):
330
+ cnots: list[tuple[int, int]] = []
331
331
 
332
332
  cnots.extend((prevh[i], prevh[-1]) for i in range(len(prevh) - 1))
333
333
  cnots.extend((currh[i], currh[-1]) for i in range(len(currh) - 1))
@@ -341,7 +341,7 @@ def _get_gates_from_hamiltonians(
341
341
  hamiltonians.keys(), key=functools.cmp_to_key(_gray_code_comparator)
342
342
  )
343
343
 
344
- previous_h: Tuple[int, ...] = ()
344
+ previous_h: tuple[int, ...] = ()
345
345
  for h in sorted_hamiltonian_keys:
346
346
  w = hamiltonians[h]
347
347
  yield _apply_cnots(previous_h, h)