cirq-core 1.4.0.dev20240529225110__py3-none-any.whl → 1.5.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.

Potentially problematic release.


This version of cirq-core might be problematic. Click here for more details.

Files changed (590) hide show
  1. cirq/__init__.py +587 -569
  2. cirq/_compat.py +9 -0
  3. cirq/_compat_test.py +11 -9
  4. cirq/_import.py +7 -8
  5. cirq/_version.py +31 -1
  6. cirq/_version_test.py +1 -1
  7. cirq/circuits/__init__.py +15 -9
  8. cirq/circuits/_block_diagram_drawer.py +1 -2
  9. cirq/circuits/_block_diagram_drawer_test.py +3 -3
  10. cirq/circuits/_box_drawing_character_data.py +0 -1
  11. cirq/circuits/_box_drawing_character_data_test.py +2 -2
  12. cirq/circuits/_bucket_priority_queue.py +0 -1
  13. cirq/circuits/_bucket_priority_queue_test.py +1 -1
  14. cirq/circuits/circuit.py +336 -234
  15. cirq/circuits/circuit_operation.py +102 -52
  16. cirq/circuits/circuit_operation_test.py +85 -4
  17. cirq/circuits/circuit_test.py +101 -32
  18. cirq/circuits/frozen_circuit.py +36 -32
  19. cirq/circuits/insert_strategy.py +10 -0
  20. cirq/circuits/insert_strategy_test.py +20 -0
  21. cirq/circuits/moment.py +79 -80
  22. cirq/circuits/moment_test.py +105 -2
  23. cirq/circuits/optimization_pass.py +15 -15
  24. cirq/circuits/optimization_pass_test.py +8 -9
  25. cirq/circuits/qasm_output.py +64 -33
  26. cirq/circuits/qasm_output_test.py +63 -2
  27. cirq/circuits/text_diagram_drawer.py +26 -56
  28. cirq/circuits/text_diagram_drawer_test.py +5 -4
  29. cirq/contrib/__init__.py +2 -2
  30. cirq/contrib/acquaintance/__init__.py +44 -29
  31. cirq/contrib/acquaintance/bipartite.py +8 -7
  32. cirq/contrib/acquaintance/bipartite_test.py +11 -1
  33. cirq/contrib/acquaintance/devices.py +5 -4
  34. cirq/contrib/acquaintance/devices_test.py +5 -1
  35. cirq/contrib/acquaintance/executor.py +18 -21
  36. cirq/contrib/acquaintance/executor_test.py +3 -2
  37. cirq/contrib/acquaintance/gates.py +36 -27
  38. cirq/contrib/acquaintance/gates_test.py +1 -1
  39. cirq/contrib/acquaintance/inspection_utils.py +10 -9
  40. cirq/contrib/acquaintance/inspection_utils_test.py +6 -1
  41. cirq/contrib/acquaintance/mutation_utils.py +10 -10
  42. cirq/contrib/acquaintance/optimizers.py +7 -6
  43. cirq/contrib/acquaintance/optimizers_test.py +1 -1
  44. cirq/contrib/acquaintance/permutation.py +22 -21
  45. cirq/contrib/acquaintance/permutation_test.py +1 -1
  46. cirq/contrib/acquaintance/shift.py +8 -6
  47. cirq/contrib/acquaintance/shift_swap_network.py +6 -4
  48. cirq/contrib/acquaintance/strategies/__init__.py +9 -3
  49. cirq/contrib/acquaintance/strategies/complete.py +4 -3
  50. cirq/contrib/acquaintance/strategies/cubic.py +5 -3
  51. cirq/contrib/acquaintance/strategies/quartic_paired.py +8 -6
  52. cirq/contrib/acquaintance/topological_sort.py +4 -2
  53. cirq/contrib/bayesian_network/__init__.py +3 -1
  54. cirq/contrib/bayesian_network/bayesian_network_gate.py +5 -3
  55. cirq/contrib/circuitdag/__init__.py +1 -1
  56. cirq/contrib/circuitdag/circuit_dag.py +24 -24
  57. cirq/contrib/circuitdag/circuit_dag_test.py +1 -1
  58. cirq/contrib/custom_simulators/custom_state_simulator.py +10 -8
  59. cirq/contrib/custom_simulators/custom_state_simulator_test.py +15 -11
  60. cirq/contrib/graph_device/__init__.py +8 -8
  61. cirq/contrib/graph_device/graph_device.py +8 -8
  62. cirq/contrib/graph_device/graph_device_test.py +0 -1
  63. cirq/contrib/graph_device/hypergraph_test.py +1 -0
  64. cirq/contrib/json.py +1 -2
  65. cirq/contrib/json_test.py +2 -2
  66. cirq/contrib/noise_models/__init__.py +5 -6
  67. cirq/contrib/noise_models/noise_models.py +8 -6
  68. cirq/contrib/paulistring/__init__.py +22 -10
  69. cirq/contrib/paulistring/clifford_optimize.py +1 -1
  70. cirq/contrib/paulistring/clifford_optimize_test.py +0 -1
  71. cirq/contrib/paulistring/clifford_target_gateset.py +15 -12
  72. cirq/contrib/paulistring/optimize.py +2 -2
  73. cirq/contrib/paulistring/optimize_test.py +0 -1
  74. cirq/contrib/paulistring/pauli_string_dag_test.py +0 -1
  75. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +379 -0
  76. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +523 -0
  77. cirq/contrib/paulistring/pauli_string_optimize.py +3 -1
  78. cirq/contrib/paulistring/pauli_string_optimize_test.py +1 -3
  79. cirq/contrib/paulistring/recombine.py +2 -2
  80. cirq/contrib/paulistring/recombine_test.py +2 -2
  81. cirq/contrib/paulistring/separate.py +3 -4
  82. cirq/contrib/qasm_import/__init__.py +2 -2
  83. cirq/contrib/qasm_import/_lexer.py +21 -26
  84. cirq/contrib/qasm_import/_lexer_test.py +90 -6
  85. cirq/contrib/qasm_import/_parser.py +238 -47
  86. cirq/contrib/qasm_import/_parser_test.py +514 -59
  87. cirq/contrib/qasm_import/qasm_test.py +1 -1
  88. cirq/contrib/qcircuit/__init__.py +6 -4
  89. cirq/contrib/qcircuit/qcircuit_diagram.py +5 -2
  90. cirq/contrib/qcircuit/qcircuit_pdf.py +1 -2
  91. cirq/{experiments/grid_parallel_two_qubit_xeb_test.py → contrib/qcircuit/qcircuit_pdf_test.py} +13 -12
  92. cirq/contrib/qcircuit/qcircuit_test.py +1 -1
  93. cirq/contrib/quantum_volume/__init__.py +7 -7
  94. cirq/contrib/quantum_volume/quantum_volume.py +6 -11
  95. cirq/contrib/quantum_volume/quantum_volume_test.py +3 -1
  96. cirq/contrib/quimb/__init__.py +16 -13
  97. cirq/contrib/quimb/density_matrix.py +1 -1
  98. cirq/contrib/quimb/mps_simulator.py +27 -28
  99. cirq/contrib/quimb/mps_simulator_test.py +5 -0
  100. cirq/contrib/quimb/state_vector.py +3 -10
  101. cirq/contrib/quirk/__init__.py +1 -1
  102. cirq/contrib/quirk/export_to_quirk.py +3 -3
  103. cirq/contrib/routing/__init__.py +12 -9
  104. cirq/contrib/routing/device.py +1 -1
  105. cirq/contrib/routing/device_test.py +1 -2
  106. cirq/contrib/routing/greedy.py +7 -5
  107. cirq/contrib/routing/greedy_test.py +5 -3
  108. cirq/contrib/routing/initialization.py +3 -1
  109. cirq/contrib/routing/initialization_test.py +1 -1
  110. cirq/contrib/routing/swap_network.py +6 -6
  111. cirq/contrib/routing/utils.py +6 -4
  112. cirq/contrib/routing/utils_test.py +1 -2
  113. cirq/{type_workarounds.py → contrib/shuffle_circuits/__init__.py} +5 -10
  114. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +250 -0
  115. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py +363 -0
  116. cirq/contrib/svg/__init__.py +1 -1
  117. cirq/contrib/svg/svg.py +12 -10
  118. cirq/contrib/svg/svg_test.py +3 -2
  119. cirq/devices/__init__.py +34 -25
  120. cirq/devices/device.py +16 -12
  121. cirq/devices/device_test.py +1 -0
  122. cirq/devices/grid_device_metadata.py +16 -12
  123. cirq/devices/grid_device_metadata_test.py +2 -1
  124. cirq/devices/grid_qubit.py +31 -26
  125. cirq/devices/grid_qubit_test.py +30 -1
  126. cirq/devices/insertion_noise_model.py +6 -6
  127. cirq/devices/insertion_noise_model_test.py +1 -1
  128. cirq/devices/line_qubit.py +28 -20
  129. cirq/devices/line_qubit_test.py +26 -0
  130. cirq/devices/named_topologies.py +12 -10
  131. cirq/devices/named_topologies_test.py +5 -4
  132. cirq/devices/noise_model.py +29 -33
  133. cirq/devices/noise_properties.py +2 -2
  134. cirq/devices/noise_properties_test.py +2 -2
  135. cirq/devices/noise_utils.py +3 -3
  136. cirq/devices/superconducting_qubits_noise_properties.py +2 -2
  137. cirq/devices/superconducting_qubits_noise_properties_test.py +3 -3
  138. cirq/devices/thermal_noise_model.py +2 -1
  139. cirq/devices/unconstrained_device.py +1 -1
  140. cirq/devices/unconstrained_device_test.py +6 -0
  141. cirq/experiments/__init__.py +51 -34
  142. cirq/experiments/qubit_characterizations.py +17 -15
  143. cirq/experiments/qubit_characterizations_test.py +4 -6
  144. cirq/experiments/random_quantum_circuit_generation.py +10 -9
  145. cirq/experiments/random_quantum_circuit_generation_test.py +21 -4
  146. cirq/experiments/readout_confusion_matrix.py +73 -8
  147. cirq/experiments/readout_confusion_matrix_test.py +104 -1
  148. cirq/experiments/single_qubit_readout_calibration.py +8 -6
  149. cirq/experiments/single_qubit_readout_calibration_test.py +1 -1
  150. cirq/experiments/t1_decay_experiment.py +4 -5
  151. cirq/experiments/t1_decay_experiment_test.py +1 -2
  152. cirq/experiments/t2_decay_experiment.py +0 -1
  153. cirq/experiments/t2_decay_experiment_test.py +1 -2
  154. cirq/experiments/two_qubit_xeb.py +157 -33
  155. cirq/experiments/two_qubit_xeb_test.py +38 -22
  156. cirq/experiments/xeb_fitting.py +99 -19
  157. cirq/experiments/xeb_fitting_test.py +64 -25
  158. cirq/experiments/xeb_sampling.py +14 -18
  159. cirq/experiments/xeb_simulation.py +4 -3
  160. cirq/experiments/xeb_simulation_test.py +20 -14
  161. cirq/experiments/z_phase_calibration.py +368 -0
  162. cirq/experiments/z_phase_calibration_test.py +241 -0
  163. cirq/interop/__init__.py +4 -1
  164. cirq/interop/quirk/__init__.py +7 -4
  165. cirq/interop/quirk/cells/__init__.py +17 -6
  166. cirq/interop/quirk/cells/arithmetic_cells.py +8 -8
  167. cirq/interop/quirk/cells/arithmetic_cells_test.py +1 -1
  168. cirq/interop/quirk/cells/cell.py +6 -6
  169. cirq/interop/quirk/cells/composite_cell.py +5 -5
  170. cirq/interop/quirk/cells/composite_cell_test.py +1 -1
  171. cirq/interop/quirk/cells/control_cells.py +1 -1
  172. cirq/interop/quirk/cells/frequency_space_cells.py +2 -2
  173. cirq/interop/quirk/cells/ignored_cells.py +1 -1
  174. cirq/interop/quirk/cells/input_cells.py +1 -1
  175. cirq/interop/quirk/cells/input_cells_test.py +1 -1
  176. cirq/interop/quirk/cells/input_rotation_cells.py +1 -1
  177. cirq/interop/quirk/cells/input_rotation_cells_test.py +1 -1
  178. cirq/interop/quirk/cells/measurement_cells.py +1 -1
  179. cirq/interop/quirk/cells/parse.py +8 -7
  180. cirq/interop/quirk/cells/parse_test.py +2 -2
  181. cirq/interop/quirk/cells/single_qubit_rotation_cells.py +1 -1
  182. cirq/interop/quirk/cells/swap_cell_test.py +1 -1
  183. cirq/interop/quirk/cells/unsupported_cells.py +1 -1
  184. cirq/interop/quirk/url_to_circuit.py +7 -7
  185. cirq/interop/quirk/url_to_circuit_test.py +1 -1
  186. cirq/ion/__init__.py +4 -2
  187. cirq/json_resolver_cache.py +15 -7
  188. cirq/linalg/__init__.py +62 -51
  189. cirq/linalg/combinators.py +4 -4
  190. cirq/linalg/combinators_test.py +4 -1
  191. cirq/linalg/decompositions.py +15 -40
  192. cirq/linalg/decompositions_test.py +16 -22
  193. cirq/linalg/diagonalize.py +1 -1
  194. cirq/linalg/diagonalize_test.py +1 -1
  195. cirq/linalg/operator_spaces.py +20 -4
  196. cirq/linalg/operator_spaces_test.py +15 -2
  197. cirq/linalg/predicates.py +3 -3
  198. cirq/linalg/predicates_test.py +1 -0
  199. cirq/linalg/tolerance.py +2 -2
  200. cirq/linalg/transformations.py +30 -12
  201. cirq/linalg/transformations_test.py +13 -0
  202. cirq/neutral_atoms/__init__.py +2 -2
  203. cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py +0 -1
  204. cirq/ops/__init__.py +172 -132
  205. cirq/ops/arithmetic_operation.py +2 -2
  206. cirq/ops/arithmetic_operation_test.py +2 -2
  207. cirq/ops/boolean_hamiltonian.py +3 -2
  208. cirq/ops/classically_controlled_operation.py +39 -12
  209. cirq/ops/classically_controlled_operation_test.py +147 -1
  210. cirq/ops/clifford_gate.py +38 -36
  211. cirq/ops/clifford_gate_test.py +75 -1
  212. cirq/ops/common_channels.py +16 -45
  213. cirq/ops/common_channels_test.py +10 -0
  214. cirq/ops/common_gate_families.py +1 -1
  215. cirq/ops/common_gate_families_test.py +1 -0
  216. cirq/ops/common_gates.py +48 -49
  217. cirq/ops/common_gates_test.py +18 -2
  218. cirq/ops/control_values.py +3 -3
  219. cirq/ops/control_values_test.py +2 -1
  220. cirq/ops/controlled_gate.py +36 -23
  221. cirq/ops/controlled_gate_test.py +70 -3
  222. cirq/ops/controlled_operation.py +6 -5
  223. cirq/ops/controlled_operation_test.py +7 -3
  224. cirq/ops/dense_pauli_string.py +11 -11
  225. cirq/ops/diagonal_gate.py +2 -2
  226. cirq/ops/diagonal_gate_test.py +1 -0
  227. cirq/ops/eigen_gate.py +16 -36
  228. cirq/ops/eigen_gate_test.py +60 -10
  229. cirq/ops/fourier_transform.py +1 -3
  230. cirq/ops/fourier_transform_test.py +2 -1
  231. cirq/ops/fsim_gate.py +42 -3
  232. cirq/ops/fsim_gate_test.py +21 -0
  233. cirq/ops/gate_operation.py +8 -8
  234. cirq/ops/gate_operation_test.py +4 -2
  235. cirq/ops/gateset_test.py +11 -2
  236. cirq/ops/global_phase_op.py +8 -7
  237. cirq/ops/global_phase_op_test.py +1 -1
  238. cirq/ops/greedy_qubit_manager_test.py +5 -0
  239. cirq/ops/identity.py +14 -4
  240. cirq/ops/identity_test.py +24 -0
  241. cirq/ops/kraus_channel.py +1 -0
  242. cirq/ops/kraus_channel_test.py +3 -1
  243. cirq/ops/linear_combinations.py +27 -21
  244. cirq/ops/linear_combinations_test.py +23 -4
  245. cirq/ops/matrix_gates.py +24 -8
  246. cirq/ops/measure_util.py +2 -2
  247. cirq/ops/measurement_gate.py +7 -4
  248. cirq/ops/measurement_gate_test.py +2 -1
  249. cirq/ops/mixed_unitary_channel.py +1 -0
  250. cirq/ops/mixed_unitary_channel_test.py +3 -1
  251. cirq/ops/named_qubit.py +8 -1
  252. cirq/ops/op_tree.py +3 -30
  253. cirq/ops/op_tree_test.py +4 -0
  254. cirq/ops/parallel_gate.py +2 -3
  255. cirq/ops/parallel_gate_test.py +2 -1
  256. cirq/ops/parity_gates.py +7 -8
  257. cirq/ops/parity_gates_test.py +1 -0
  258. cirq/ops/pauli_gates.py +5 -11
  259. cirq/ops/pauli_gates_test.py +1 -0
  260. cirq/ops/pauli_interaction_gate.py +11 -5
  261. cirq/ops/pauli_interaction_gate_test.py +2 -3
  262. cirq/ops/pauli_measurement_gate.py +6 -5
  263. cirq/ops/pauli_measurement_gate_test.py +1 -0
  264. cirq/ops/pauli_string.py +115 -130
  265. cirq/ops/pauli_string_phasor.py +21 -20
  266. cirq/ops/pauli_string_phasor_test.py +13 -3
  267. cirq/ops/pauli_string_raw_types.py +1 -0
  268. cirq/ops/pauli_string_test.py +192 -55
  269. cirq/ops/pauli_sum_exponential.py +3 -4
  270. cirq/ops/pauli_sum_exponential_test.py +0 -1
  271. cirq/ops/permutation_gate.py +2 -2
  272. cirq/ops/permutation_gate_test.py +1 -1
  273. cirq/ops/phased_iswap_gate.py +6 -7
  274. cirq/ops/phased_iswap_gate_test.py +21 -5
  275. cirq/ops/phased_x_gate.py +11 -25
  276. cirq/ops/phased_x_gate_test.py +19 -3
  277. cirq/ops/phased_x_z_gate.py +12 -11
  278. cirq/ops/projector.py +4 -5
  279. cirq/ops/qubit_manager.py +2 -1
  280. cirq/ops/qubit_manager_test.py +2 -1
  281. cirq/ops/qubit_order.py +1 -1
  282. cirq/ops/random_gate_channel.py +1 -1
  283. cirq/ops/random_gate_channel_test.py +0 -6
  284. cirq/ops/raw_types.py +146 -50
  285. cirq/ops/raw_types_test.py +37 -3
  286. cirq/ops/state_preparation_channel.py +2 -2
  287. cirq/ops/state_preparation_channel_test.py +2 -1
  288. cirq/ops/swap_gates.py +9 -4
  289. cirq/ops/three_qubit_gates.py +8 -8
  290. cirq/ops/three_qubit_gates_test.py +1 -0
  291. cirq/ops/two_qubit_diagonal_gate.py +4 -3
  292. cirq/ops/uniform_superposition_gate.py +4 -4
  293. cirq/ops/uniform_superposition_gate_test.py +1 -0
  294. cirq/ops/wait_gate.py +6 -8
  295. cirq/protocols/__init__.py +135 -83
  296. cirq/protocols/act_on_protocol.py +1 -1
  297. cirq/protocols/act_on_protocol_test.py +1 -1
  298. cirq/protocols/apply_channel_protocol.py +3 -3
  299. cirq/protocols/apply_mixture_protocol.py +15 -9
  300. cirq/protocols/apply_mixture_protocol_test.py +11 -0
  301. cirq/protocols/apply_unitary_protocol.py +2 -2
  302. cirq/protocols/apply_unitary_protocol_test.py +2 -1
  303. cirq/protocols/approximate_equality_protocol.py +7 -8
  304. cirq/protocols/approximate_equality_protocol_test.py +3 -1
  305. cirq/protocols/circuit_diagram_info_protocol.py +8 -6
  306. cirq/protocols/circuit_diagram_info_protocol_test.py +5 -0
  307. cirq/protocols/commutes_protocol.py +6 -6
  308. cirq/protocols/control_key_protocol.py +1 -1
  309. cirq/protocols/decompose_protocol.py +4 -5
  310. cirq/protocols/decompose_protocol_test.py +2 -1
  311. cirq/protocols/equal_up_to_global_phase_protocol.py +3 -3
  312. cirq/protocols/equal_up_to_global_phase_protocol_test.py +7 -0
  313. cirq/protocols/has_stabilizer_effect_protocol.py +5 -5
  314. cirq/protocols/has_unitary_protocol.py +1 -1
  315. cirq/protocols/has_unitary_protocol_test.py +8 -7
  316. cirq/protocols/hash_from_pickle_test.py +120 -0
  317. cirq/protocols/inverse_protocol.py +1 -1
  318. cirq/protocols/json_serialization.py +14 -1
  319. cirq/protocols/json_serialization_test.py +28 -7
  320. cirq/protocols/json_test_data/BitMaskKeyCondition.json +86 -0
  321. cirq/protocols/json_test_data/BitMaskKeyCondition.repr +7 -0
  322. cirq/protocols/json_test_data/Concat.json +19 -0
  323. cirq/protocols/json_test_data/Concat.repr +1 -0
  324. cirq/protocols/json_test_data/README.md +4 -2
  325. cirq/protocols/json_test_data/SympyCondition.json +60 -15
  326. cirq/protocols/json_test_data/SympyCondition.repr +4 -1
  327. cirq/protocols/json_test_data/_InverseCompositeGate.json +10 -0
  328. cirq/protocols/json_test_data/_InverseCompositeGate.repr +1 -0
  329. cirq/protocols/json_test_data/__init__.py +1 -1
  330. cirq/protocols/json_test_data/sympy.And.json +13 -0
  331. cirq/protocols/json_test_data/sympy.And.repr +1 -0
  332. cirq/protocols/json_test_data/sympy.Indexed.json +18 -0
  333. cirq/protocols/json_test_data/sympy.Indexed.repr +1 -0
  334. cirq/protocols/json_test_data/sympy.IndexedBase.json +9 -0
  335. cirq/protocols/json_test_data/sympy.IndexedBase.repr +1 -0
  336. cirq/protocols/json_test_data/sympy.Not.json +9 -0
  337. cirq/protocols/json_test_data/sympy.Not.repr +1 -0
  338. cirq/protocols/json_test_data/sympy.Or.json +13 -0
  339. cirq/protocols/json_test_data/sympy.Or.repr +1 -0
  340. cirq/protocols/json_test_data/sympy.Xor.json +13 -0
  341. cirq/protocols/json_test_data/sympy.Xor.repr +1 -0
  342. cirq/protocols/kraus_protocol.py +8 -8
  343. cirq/protocols/kraus_protocol_test.py +0 -1
  344. cirq/protocols/measurement_key_protocol.py +1 -1
  345. cirq/protocols/measurement_key_protocol_test.py +7 -7
  346. cirq/protocols/mixture_protocol.py +6 -4
  347. cirq/protocols/mixture_protocol_test.py +21 -13
  348. cirq/protocols/pauli_expansion_protocol.py +1 -0
  349. cirq/protocols/pow_protocol.py +1 -1
  350. cirq/protocols/qasm.py +25 -6
  351. cirq/protocols/qasm_test.py +17 -0
  352. cirq/protocols/qid_shape_protocol.py +2 -2
  353. cirq/protocols/resolve_parameters.py +2 -3
  354. cirq/protocols/resolve_parameters_test.py +2 -1
  355. cirq/protocols/trace_distance_bound.py +1 -1
  356. cirq/protocols/trace_distance_bound_test.py +1 -0
  357. cirq/protocols/unitary_protocol.py +3 -3
  358. cirq/protocols/unitary_protocol_test.py +1 -1
  359. cirq/qis/__init__.py +48 -35
  360. cirq/qis/channels_test.py +0 -9
  361. cirq/qis/clifford_tableau.py +46 -26
  362. cirq/qis/clifford_tableau_test.py +2 -1
  363. cirq/qis/entropy.py +115 -0
  364. cirq/qis/entropy_test.py +43 -0
  365. cirq/qis/measures.py +5 -4
  366. cirq/qis/measures_test.py +7 -0
  367. cirq/qis/noise_utils_test.py +4 -4
  368. cirq/qis/quantum_state_representation.py +1 -1
  369. cirq/qis/states.py +7 -7
  370. cirq/sim/__init__.py +55 -37
  371. cirq/sim/classical_simulator.py +7 -6
  372. cirq/sim/classical_simulator_test.py +3 -1
  373. cirq/sim/clifford/__init__.py +17 -9
  374. cirq/sim/clifford/clifford_simulator.py +5 -4
  375. cirq/sim/clifford/clifford_simulator_test.py +32 -9
  376. cirq/sim/clifford/clifford_tableau_simulation_state.py +1 -1
  377. cirq/sim/clifford/stabilizer_simulation_state.py +1 -1
  378. cirq/sim/clifford/stabilizer_state_ch_form.py +4 -3
  379. cirq/sim/density_matrix_simulator.py +3 -2
  380. cirq/sim/density_matrix_simulator_test.py +12 -4
  381. cirq/sim/density_matrix_utils.py +1 -1
  382. cirq/sim/mux.py +2 -2
  383. cirq/sim/simulation_state.py +4 -5
  384. cirq/sim/simulation_state_base.py +2 -2
  385. cirq/sim/simulation_state_test.py +1 -1
  386. cirq/sim/simulation_utils.py +3 -1
  387. cirq/sim/simulation_utils_test.py +2 -3
  388. cirq/sim/simulator.py +7 -6
  389. cirq/sim/simulator_base.py +5 -5
  390. cirq/sim/simulator_test.py +14 -3
  391. cirq/sim/sparse_simulator.py +4 -3
  392. cirq/sim/sparse_simulator_test.py +17 -9
  393. cirq/sim/state_vector.py +2 -2
  394. cirq/sim/state_vector_simulation_state_test.py +1 -1
  395. cirq/sim/state_vector_simulator.py +4 -4
  396. cirq/sim/state_vector_test.py +27 -32
  397. cirq/study/__init__.py +27 -21
  398. cirq/study/flatten_expressions.py +5 -6
  399. cirq/study/flatten_expressions_test.py +1 -1
  400. cirq/study/resolver.py +14 -11
  401. cirq/study/resolver_test.py +10 -1
  402. cirq/study/result.py +3 -3
  403. cirq/study/sweepable.py +15 -9
  404. cirq/study/sweepable_test.py +27 -0
  405. cirq/study/sweeps.py +65 -10
  406. cirq/study/sweeps_test.py +123 -0
  407. cirq/testing/__init__.py +86 -57
  408. cirq/testing/_compat_test_data/module_a/__init__.py +2 -2
  409. cirq/testing/_compat_test_data/module_a/sub/subsub/__init__.py +1 -1
  410. cirq/testing/circuit_compare.py +3 -4
  411. cirq/testing/circuit_compare_test.py +7 -8
  412. cirq/testing/consistent_act_on.py +3 -3
  413. cirq/testing/consistent_channels_test.py +2 -1
  414. cirq/testing/consistent_controlled_gate_op.py +3 -2
  415. cirq/testing/consistent_controlled_gate_op_test.py +2 -3
  416. cirq/testing/consistent_decomposition.py +1 -1
  417. cirq/testing/consistent_decomposition_test.py +1 -2
  418. cirq/testing/consistent_pauli_expansion_test.py +1 -1
  419. cirq/testing/consistent_phase_by.py +1 -1
  420. cirq/testing/consistent_phase_by_test.py +1 -2
  421. cirq/testing/consistent_protocols.py +11 -11
  422. cirq/testing/consistent_protocols_test.py +4 -5
  423. cirq/testing/consistent_qasm.py +8 -12
  424. cirq/testing/consistent_qasm_test.py +1 -1
  425. cirq/testing/consistent_resolve_parameters.py +2 -1
  426. cirq/testing/consistent_specified_has_unitary_test.py +1 -1
  427. cirq/testing/consistent_unitary.py +3 -1
  428. cirq/testing/consistent_unitary_test.py +3 -3
  429. cirq/testing/devices.py +1 -1
  430. cirq/testing/devices_test.py +1 -0
  431. cirq/testing/equals_tester.py +2 -4
  432. cirq/testing/equals_tester_test.py +6 -5
  433. cirq/testing/equivalent_basis_map.py +1 -0
  434. cirq/testing/equivalent_basis_map_test.py +0 -1
  435. cirq/testing/gate_features_test.py +5 -0
  436. cirq/testing/json.py +4 -4
  437. cirq/testing/lin_alg_utils_test.py +1 -1
  438. cirq/testing/order_tester.py +1 -1
  439. cirq/testing/order_tester_test.py +1 -1
  440. cirq/testing/pytest_utils.py +57 -0
  441. cirq/testing/pytest_utils_test.py +35 -0
  442. cirq/testing/random_circuit.py +2 -2
  443. cirq/testing/random_circuit_test.py +2 -2
  444. cirq/testing/routing_devices_test.py +2 -1
  445. cirq/testing/sample_circuits.py +1 -1
  446. cirq/testing/sample_gates.py +5 -4
  447. cirq/testing/sample_gates_test.py +2 -2
  448. cirq/transformers/__init__.py +101 -82
  449. cirq/transformers/align.py +12 -1
  450. cirq/transformers/align_test.py +13 -0
  451. cirq/transformers/analytical_decompositions/__init__.py +27 -24
  452. cirq/transformers/analytical_decompositions/clifford_decomposition.py +2 -1
  453. cirq/transformers/analytical_decompositions/clifford_decomposition_test.py +1 -1
  454. cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +1 -1
  455. cirq/transformers/analytical_decompositions/controlled_gate_decomposition_test.py +2 -0
  456. cirq/transformers/analytical_decompositions/cphase_to_fsim.py +1 -1
  457. cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +1 -1
  458. cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +2 -2
  459. cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +4 -4
  460. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +99 -24
  461. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +105 -14
  462. cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +1 -1
  463. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry.py +1 -1
  464. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry_test.py +1 -0
  465. cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +3 -4
  466. cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +1 -1
  467. cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +2 -1
  468. cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +2 -1
  469. cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +5 -6
  470. cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +2 -2
  471. cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +1 -1
  472. cirq/transformers/analytical_decompositions/two_qubit_to_fsim_test.py +1 -2
  473. cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +2 -2
  474. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +2 -2
  475. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap_test.py +2 -1
  476. cirq/transformers/drop_empty_moments.py +1 -0
  477. cirq/transformers/drop_negligible_operations.py +1 -0
  478. cirq/transformers/dynamical_decoupling.py +255 -43
  479. cirq/transformers/dynamical_decoupling_test.py +730 -17
  480. cirq/transformers/eject_phased_paulis.py +29 -15
  481. cirq/transformers/eject_phased_paulis_test.py +3 -8
  482. cirq/transformers/eject_z.py +3 -2
  483. cirq/transformers/eject_z_test.py +3 -3
  484. cirq/transformers/gauge_compiling/__init__.py +25 -9
  485. cirq/transformers/gauge_compiling/cphase_gauge.py +146 -0
  486. cirq/transformers/gauge_compiling/cphase_gauge_test.py +42 -0
  487. cirq/transformers/gauge_compiling/cz_gauge.py +4 -4
  488. cirq/transformers/gauge_compiling/gauge_compiling.py +245 -6
  489. cirq/transformers/gauge_compiling/gauge_compiling_test.py +107 -2
  490. cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +39 -2
  491. cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +10 -1
  492. cirq/transformers/gauge_compiling/iswap_gauge.py +2 -2
  493. cirq/transformers/gauge_compiling/spin_inversion_gauge.py +2 -2
  494. cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +23 -5
  495. cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +3 -2
  496. cirq/transformers/heuristic_decompositions/__init__.py +3 -3
  497. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +2 -1
  498. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils_test.py +1 -1
  499. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +4 -4
  500. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation_test.py +4 -4
  501. cirq/transformers/insertion_sort.py +64 -0
  502. cirq/transformers/insertion_sort_test.py +34 -0
  503. cirq/transformers/measurement_transformers.py +14 -1
  504. cirq/transformers/measurement_transformers_test.py +35 -0
  505. cirq/transformers/merge_k_qubit_gates.py +2 -2
  506. cirq/transformers/merge_single_qubit_gates.py +1 -1
  507. cirq/transformers/merge_single_qubit_gates_test.py +1 -1
  508. cirq/transformers/noise_adding.py +115 -0
  509. cirq/transformers/noise_adding_test.py +54 -0
  510. cirq/transformers/optimize_for_target_gateset.py +1 -1
  511. cirq/transformers/optimize_for_target_gateset_test.py +3 -2
  512. cirq/transformers/qubit_management_transformers.py +1 -1
  513. cirq/transformers/randomized_measurements.py +171 -0
  514. cirq/transformers/randomized_measurements_test.py +68 -0
  515. cirq/transformers/routing/__init__.py +14 -5
  516. cirq/transformers/routing/initial_mapper.py +1 -1
  517. cirq/transformers/routing/initial_mapper_test.py +1 -0
  518. cirq/transformers/routing/line_initial_mapper.py +3 -2
  519. cirq/transformers/routing/mapping_manager.py +2 -2
  520. cirq/transformers/routing/mapping_manager_test.py +2 -2
  521. cirq/transformers/routing/route_circuit_cqc.py +3 -2
  522. cirq/transformers/routing/route_circuit_cqc_test.py +2 -1
  523. cirq/transformers/routing/visualize_routed_circuit.py +1 -0
  524. cirq/transformers/routing/visualize_routed_circuit_test.py +1 -0
  525. cirq/transformers/stratify.py +2 -2
  526. cirq/transformers/synchronize_terminal_measurements.py +2 -1
  527. cirq/transformers/target_gatesets/__init__.py +7 -5
  528. cirq/transformers/target_gatesets/compilation_target_gateset.py +16 -3
  529. cirq/transformers/target_gatesets/compilation_target_gateset_test.py +2 -0
  530. cirq/transformers/target_gatesets/cz_gateset.py +5 -1
  531. cirq/transformers/target_gatesets/cz_gateset_test.py +23 -2
  532. cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +1 -1
  533. cirq/transformers/target_gatesets/sqrt_iswap_gateset_test.py +3 -2
  534. cirq/transformers/transformer_api.py +5 -4
  535. cirq/transformers/transformer_api_test.py +11 -3
  536. cirq/transformers/transformer_primitives.py +9 -31
  537. cirq/transformers/transformer_primitives_test.py +6 -5
  538. cirq/value/__init__.py +51 -30
  539. cirq/value/abc_alt.py +1 -2
  540. cirq/value/angle.py +2 -0
  541. cirq/value/classical_data.py +1 -0
  542. cirq/value/condition.py +149 -3
  543. cirq/value/condition_test.py +254 -0
  544. cirq/value/digits.py +1 -1
  545. cirq/value/duration.py +4 -4
  546. cirq/value/duration_test.py +2 -1
  547. cirq/value/linear_dict.py +85 -24
  548. cirq/value/linear_dict_test.py +94 -3
  549. cirq/value/measurement_key.py +9 -2
  550. cirq/value/periodic_value.py +2 -3
  551. cirq/value/periodic_value_test.py +5 -0
  552. cirq/value/probability.py +1 -0
  553. cirq/value/random_state.py +1 -1
  554. cirq/value/timestamp.py +2 -4
  555. cirq/value/timestamp_test.py +2 -1
  556. cirq/value/type_alias.py +2 -2
  557. cirq/value/value_equality_attr.py +14 -2
  558. cirq/value/value_equality_attr_test.py +1 -1
  559. cirq/vis/__init__.py +9 -6
  560. cirq/vis/density_matrix.py +1 -1
  561. cirq/vis/density_matrix_test.py +2 -5
  562. cirq/vis/heatmap.py +49 -12
  563. cirq/vis/heatmap_test.py +168 -4
  564. cirq/vis/histogram.py +1 -1
  565. cirq/vis/histogram_test.py +1 -2
  566. cirq/vis/state_histogram.py +7 -5
  567. cirq/vis/state_histogram_test.py +2 -2
  568. cirq/work/__init__.py +19 -13
  569. cirq/work/collector.py +2 -2
  570. cirq/work/observable_grouping.py +2 -2
  571. cirq/work/observable_measurement.py +3 -3
  572. cirq/work/observable_measurement_data.py +5 -2
  573. cirq/work/observable_measurement_test.py +8 -8
  574. cirq/work/observable_readout_calibration.py +2 -2
  575. cirq/work/observable_readout_calibration_test.py +2 -1
  576. cirq/work/observable_settings.py +8 -7
  577. cirq/work/observable_settings_test.py +3 -2
  578. cirq/work/pauli_sum_collector.py +1 -1
  579. cirq/work/sampler.py +8 -20
  580. cirq/work/sampler_test.py +4 -3
  581. cirq/work/zeros_sampler.py +1 -1
  582. cirq_core-1.5.0.dist-info/METADATA +125 -0
  583. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/RECORD +586 -552
  584. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/WHEEL +1 -1
  585. cirq/experiments/grid_parallel_two_qubit_xeb.py +0 -62
  586. cirq/protocols/json_test_data/GridParallelXEBMetadata.json +0 -119
  587. cirq/protocols/json_test_data/GridParallelXEBMetadata.repr +0 -1
  588. cirq_core-1.4.0.dev20240529225110.dist-info/METADATA +0 -50
  589. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/LICENSE +0 -0
  590. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/top_level.txt +0 -0
cirq/circuits/moment.py CHANGED
@@ -14,7 +14,11 @@
14
14
 
15
15
  """A simplified time-slice of operations within a sequenced circuit."""
16
16
 
17
+ from __future__ import annotations
18
+
17
19
  import itertools
20
+ from functools import cached_property
21
+ from types import NotImplementedType
18
22
  from typing import (
19
23
  AbstractSet,
20
24
  Any,
@@ -26,35 +30,34 @@ from typing import (
26
30
  Iterator,
27
31
  List,
28
32
  Mapping,
29
- overload,
30
33
  Optional,
34
+ overload,
31
35
  Sequence,
32
36
  Tuple,
33
37
  TYPE_CHECKING,
34
38
  Union,
35
39
  )
36
- from typing_extensions import Self
37
40
 
38
41
  import numpy as np
42
+ from typing_extensions import Self
39
43
 
40
- from cirq import protocols, ops, qis, _compat
44
+ from cirq import _compat, ops, protocols, qis
41
45
  from cirq._import import LazyLoader
42
- from cirq.ops import raw_types, op_tree
46
+ from cirq.ops import op_tree, raw_types
43
47
  from cirq.protocols import circuit_diagram_info_protocol
44
- from cirq.type_workarounds import NotImplementedType
45
48
 
46
49
  if TYPE_CHECKING:
47
50
  import cirq
48
51
 
49
52
  # Lazy imports to break circular dependencies.
50
- circuits = LazyLoader("circuits", globals(), "cirq.circuits.circuit")
53
+ circuit = LazyLoader("circuit", globals(), "cirq.circuits.circuit")
51
54
  op_tree = LazyLoader("op_tree", globals(), "cirq.ops.op_tree")
52
55
  text_diagram_drawer = LazyLoader(
53
56
  "text_diagram_drawer", globals(), "cirq.circuits.text_diagram_drawer"
54
57
  )
55
58
 
56
59
 
57
- def _default_breakdown(qid: 'cirq.Qid') -> Tuple[Any, Any]:
60
+ def _default_breakdown(qid: cirq.Qid) -> Tuple[Any, Any]:
58
61
  # Attempt to convert into a position on the complex plane.
59
62
  try:
60
63
  plane_pos = complex(qid) # type: ignore
@@ -81,7 +84,7 @@ class Moment:
81
84
  are no such operations, returns an empty Moment.
82
85
  """
83
86
 
84
- def __init__(self, *contents: 'cirq.OP_TREE', _flatten_contents: bool = True) -> None:
87
+ def __init__(self, *contents: cirq.OP_TREE, _flatten_contents: bool = True) -> None:
85
88
  """Constructs a moment with the given operations.
86
89
 
87
90
  Args:
@@ -101,10 +104,10 @@ class Moment:
101
104
  if _flatten_contents
102
105
  else cast(Tuple['cirq.Operation'], contents)
103
106
  )
104
- self._sorted_operations: Optional[Tuple['cirq.Operation', ...]] = None
107
+ self._sorted_operations: Optional[Tuple[cirq.Operation, ...]] = None
105
108
 
106
109
  # An internal dictionary to support efficient operation access by qubit.
107
- self._qubit_to_op: Dict['cirq.Qid', 'cirq.Operation'] = {}
110
+ self._qubit_to_op: Dict[cirq.Qid, cirq.Operation] = {}
108
111
  for op in self.operations:
109
112
  for q in op.qubits:
110
113
  # Check that operations don't overlap.
@@ -112,12 +115,11 @@ class Moment:
112
115
  raise ValueError(f'Overlapping operations: {self.operations}')
113
116
  self._qubit_to_op[q] = op
114
117
 
115
- self._qubits = frozenset(self._qubit_to_op.keys())
116
- self._measurement_key_objs: Optional[FrozenSet['cirq.MeasurementKey']] = None
117
- self._control_keys: Optional[FrozenSet['cirq.MeasurementKey']] = None
118
+ self._measurement_key_objs: Optional[FrozenSet[cirq.MeasurementKey]] = None
119
+ self._control_keys: Optional[FrozenSet[cirq.MeasurementKey]] = None
118
120
 
119
121
  @classmethod
120
- def from_ops(cls, *ops: 'cirq.Operation') -> 'cirq.Moment':
122
+ def from_ops(cls, *ops: cirq.Operation) -> cirq.Moment:
121
123
  """Construct a Moment from the given operations.
122
124
 
123
125
  This avoids calling `flatten_to_ops` in the moment constructor, which
@@ -131,14 +133,14 @@ class Moment:
131
133
  return cls(*ops, _flatten_contents=False)
132
134
 
133
135
  @property
134
- def operations(self) -> Tuple['cirq.Operation', ...]:
136
+ def operations(self) -> Tuple[cirq.Operation, ...]:
135
137
  return self._operations
136
138
 
137
- @property
138
- def qubits(self) -> FrozenSet['cirq.Qid']:
139
- return self._qubits
139
+ @cached_property
140
+ def qubits(self) -> FrozenSet[cirq.Qid]:
141
+ return frozenset(self._qubit_to_op)
140
142
 
141
- def operates_on_single_qubit(self, qubit: 'cirq.Qid') -> bool:
143
+ def operates_on_single_qubit(self, qubit: cirq.Qid) -> bool:
142
144
  """Determines if the moment has operations touching the given qubit.
143
145
  Args:
144
146
  qubit: The qubit that may or may not be touched by operations.
@@ -147,7 +149,7 @@ class Moment:
147
149
  """
148
150
  return qubit in self._qubit_to_op
149
151
 
150
- def operates_on(self, qubits: Iterable['cirq.Qid']) -> bool:
152
+ def operates_on(self, qubits: Iterable[cirq.Qid]) -> bool:
151
153
  """Determines if the moment has operations touching the given qubits.
152
154
 
153
155
  Args:
@@ -156,9 +158,9 @@ class Moment:
156
158
  Returns:
157
159
  Whether this moment has operations involving the qubits.
158
160
  """
159
- return not self._qubits.isdisjoint(qubits)
161
+ return not self._qubit_to_op.keys().isdisjoint(qubits)
160
162
 
161
- def operation_at(self, qubit: raw_types.Qid) -> Optional['cirq.Operation']:
163
+ def operation_at(self, qubit: raw_types.Qid) -> Optional[cirq.Operation]:
162
164
  """Returns the operation on a certain qubit for the moment.
163
165
 
164
166
  Args:
@@ -172,7 +174,7 @@ class Moment:
172
174
  return self.__getitem__(qubit)
173
175
  return None
174
176
 
175
- def with_operation(self, operation: 'cirq.Operation') -> 'cirq.Moment':
177
+ def with_operation(self, operation: cirq.Operation) -> cirq.Moment:
176
178
  """Returns an equal moment, but with the given op added.
177
179
 
178
180
  Args:
@@ -184,14 +186,13 @@ class Moment:
184
186
  Raises:
185
187
  ValueError: If the operation given overlaps a current operation in the moment.
186
188
  """
187
- if any(q in self._qubits for q in operation.qubits):
189
+ if any(q in self._qubit_to_op for q in operation.qubits):
188
190
  raise ValueError(f'Overlapping operations: {operation}')
189
191
 
190
192
  # Use private variables to facilitate a quick copy.
191
193
  m = Moment(_flatten_contents=False)
192
194
  m._operations = self._operations + (operation,)
193
195
  m._sorted_operations = None
194
- m._qubits = self._qubits.union(operation.qubits)
195
196
  m._qubit_to_op = {**self._qubit_to_op, **{q: operation for q in operation.qubits}}
196
197
 
197
198
  m._measurement_key_objs = self._measurement_key_objs_().union(
@@ -201,7 +202,7 @@ class Moment:
201
202
 
202
203
  return m
203
204
 
204
- def with_operations(self, *contents: 'cirq.OP_TREE') -> 'cirq.Moment':
205
+ def with_operations(self, *contents: cirq.OP_TREE) -> cirq.Moment:
205
206
  """Returns a new moment with the given contents added.
206
207
 
207
208
  Args:
@@ -221,14 +222,11 @@ class Moment:
221
222
  m = Moment(_flatten_contents=False)
222
223
  # Use private variables to facilitate a quick copy.
223
224
  m._qubit_to_op = self._qubit_to_op.copy()
224
- qubits = set(self._qubits)
225
225
  for op in flattened_contents:
226
- if any(q in qubits for q in op.qubits):
226
+ if any(q in m._qubit_to_op for q in op.qubits):
227
227
  raise ValueError(f'Overlapping operations: {op}')
228
- qubits.update(op.qubits)
229
228
  for q in op.qubits:
230
229
  m._qubit_to_op[q] = op
231
- m._qubits = frozenset(qubits)
232
230
 
233
231
  m._operations = self._operations + flattened_contents
234
232
  m._sorted_operations = None
@@ -241,7 +239,7 @@ class Moment:
241
239
 
242
240
  return m
243
241
 
244
- def without_operations_touching(self, qubits: Iterable['cirq.Qid']) -> 'cirq.Moment':
242
+ def without_operations_touching(self, qubits: Iterable[cirq.Qid]) -> cirq.Moment:
245
243
  """Returns an equal moment, but without ops on the given qubits.
246
244
 
247
245
  Args:
@@ -267,15 +265,16 @@ class Moment:
267
265
  def _parameter_names_(self) -> AbstractSet[str]:
268
266
  return {name for op in self for name in protocols.parameter_names(op)}
269
267
 
270
- def _resolve_parameters_(
271
- self, resolver: 'cirq.ParamResolver', recursive: bool
272
- ) -> 'cirq.Moment':
268
+ def _resolve_parameters_(self, resolver: cirq.ParamResolver, recursive: bool) -> cirq.Moment:
273
269
  changed = False
274
- resolved_ops: List['cirq.Operation'] = []
270
+ resolved_ops: List[cirq.Operation] = []
275
271
  for op in self:
276
272
  resolved_op = protocols.resolve_parameters(op, resolver, recursive)
277
- if resolved_op != op:
278
- changed = True
273
+ changed = (
274
+ changed
275
+ or resolved_op != op
276
+ or (protocols.is_parameterized(op) and not protocols.is_parameterized(resolved_op))
277
+ )
279
278
  resolved_ops.append(resolved_op)
280
279
  if not changed:
281
280
  return self
@@ -295,21 +294,21 @@ class Moment:
295
294
  def _measurement_key_names_(self) -> FrozenSet[str]:
296
295
  return frozenset(str(key) for key in self._measurement_key_objs_())
297
296
 
298
- def _measurement_key_objs_(self) -> FrozenSet['cirq.MeasurementKey']:
297
+ def _measurement_key_objs_(self) -> FrozenSet[cirq.MeasurementKey]:
299
298
  if self._measurement_key_objs is None:
300
299
  self._measurement_key_objs = frozenset(
301
300
  key for op in self.operations for key in protocols.measurement_key_objs(op)
302
301
  )
303
302
  return self._measurement_key_objs
304
303
 
305
- def _control_keys_(self) -> FrozenSet['cirq.MeasurementKey']:
304
+ def _control_keys_(self) -> FrozenSet[cirq.MeasurementKey]:
306
305
  if self._control_keys is None:
307
306
  self._control_keys = frozenset(
308
307
  k for op in self.operations for k in protocols.control_keys(op)
309
308
  )
310
309
  return self._control_keys
311
310
 
312
- def _sorted_operations_(self) -> Tuple['cirq.Operation', ...]:
311
+ def _sorted_operations_(self) -> Tuple[cirq.Operation, ...]:
313
312
  if self._sorted_operations is None:
314
313
  self._sorted_operations = tuple(sorted(self._operations, key=lambda op: op.qubits))
315
314
  return self._sorted_operations
@@ -331,7 +330,7 @@ class Moment:
331
330
  )
332
331
 
333
332
  def _with_rescoped_keys_(
334
- self, path: Tuple[str, ...], bindable_keys: FrozenSet['cirq.MeasurementKey']
333
+ self, path: Tuple[str, ...], bindable_keys: FrozenSet[cirq.MeasurementKey]
335
334
  ):
336
335
  return Moment(
337
336
  protocols.with_rescoped_keys(op, path, bindable_keys) for op in self.operations
@@ -349,7 +348,7 @@ class Moment:
349
348
 
350
349
  return self is other or self._sorted_operations_() == other._sorted_operations_()
351
350
 
352
- def _approx_eq_(self, other: Any, atol: Union[int, float]) -> bool:
351
+ def _approx_eq_(self, other: Any, atol: float) -> bool:
353
352
  """See `cirq.protocols.SupportsApproximateEquality`."""
354
353
  if not isinstance(other, type(self)):
355
354
  return NotImplemented
@@ -365,7 +364,16 @@ class Moment:
365
364
  def __hash__(self):
366
365
  return hash((Moment, self._sorted_operations_()))
367
366
 
368
- def __iter__(self) -> Iterator['cirq.Operation']:
367
+ def __getstate__(self) -> Dict[str, Any]:
368
+ # clear cached hash value when pickling, see #6674
369
+ state = self.__dict__
370
+ hash_attr = _compat._method_cache_name(self.__hash__)
371
+ if hash_attr in state:
372
+ state = state.copy()
373
+ del state[hash_attr]
374
+ return state
375
+
376
+ def __iter__(self) -> Iterator[cirq.Operation]:
369
377
  return iter(self.operations)
370
378
 
371
379
  def __pow__(self, power):
@@ -394,12 +402,12 @@ class Moment:
394
402
  def __str__(self) -> str:
395
403
  return self.to_text_diagram()
396
404
 
397
- def _decompose_(self) -> 'cirq.OP_TREE':
405
+ def _decompose_(self) -> cirq.OP_TREE:
398
406
  """See `cirq.SupportsDecompose`."""
399
407
  return self._operations
400
408
 
401
409
  def transform_qubits(
402
- self, qubit_map: Union[Dict['cirq.Qid', 'cirq.Qid'], Callable[['cirq.Qid'], 'cirq.Qid']]
410
+ self, qubit_map: Union[Dict[cirq.Qid, cirq.Qid], Callable[[cirq.Qid], cirq.Qid]]
403
411
  ) -> Self:
404
412
  """Returns the same moment, but with different qubits.
405
413
 
@@ -413,7 +421,7 @@ class Moment:
413
421
  """
414
422
  return self.__class__(op.transform_qubits(qubit_map) for op in self.operations)
415
423
 
416
- def expand_to(self, qubits: Iterable['cirq.Qid']) -> 'cirq.Moment':
424
+ def expand_to(self, qubits: Iterable[cirq.Qid]) -> cirq.Moment:
417
425
  """Returns self expanded to given superset of qubits by making identities explicit.
418
426
 
419
427
  Args:
@@ -437,7 +445,9 @@ class Moment:
437
445
  @_compat.cached_method()
438
446
  def _has_kraus_(self) -> bool:
439
447
  """Returns True if self has a Kraus representation and self uses <= 10 qubits."""
440
- return all(protocols.has_kraus(op) for op in self.operations) and len(self.qubits) <= 10
448
+ return (
449
+ all(protocols.has_kraus(op) for op in self.operations) and len(self._qubit_to_op) <= 10
450
+ )
441
451
 
442
452
  def _kraus_(self) -> Sequence[np.ndarray]:
443
453
  r"""Returns Kraus representation of self.
@@ -462,7 +472,7 @@ class Moment:
462
472
  if not self._has_kraus_():
463
473
  return NotImplemented
464
474
 
465
- qubits = sorted(self.qubits)
475
+ qubits = sorted(self._qubit_to_op)
466
476
  n = len(qubits)
467
477
  if n < 1:
468
478
  return (np.array([[1 + 0j]]),)
@@ -470,13 +480,13 @@ class Moment:
470
480
  qubit_to_row_subscript = dict(zip(qubits, 'abcdefghij'))
471
481
  qubit_to_col_subscript = dict(zip(qubits, 'ABCDEFGHIJ'))
472
482
 
473
- def row_subscripts(qs: Sequence['cirq.Qid']) -> str:
483
+ def row_subscripts(qs: Sequence[cirq.Qid]) -> str:
474
484
  return ''.join(qubit_to_row_subscript[q] for q in qs)
475
485
 
476
- def col_subscripts(qs: Sequence['cirq.Qid']) -> str:
486
+ def col_subscripts(qs: Sequence[cirq.Qid]) -> str:
477
487
  return ''.join(qubit_to_col_subscript[q] for q in qs)
478
488
 
479
- def kraus_tensors(op: 'cirq.Operation') -> Sequence[np.ndarray]:
489
+ def kraus_tensors(op: cirq.Operation) -> Sequence[np.ndarray]:
480
490
  return tuple(np.reshape(k, (2, 2) * len(op.qubits)) for k in protocols.kraus(op))
481
491
 
482
492
  input_subscripts = ','.join(
@@ -513,12 +523,12 @@ class Moment:
513
523
  def _from_json_dict_(cls, operations, **kwargs):
514
524
  return cls.from_ops(*operations)
515
525
 
516
- def __add__(self, other: 'cirq.OP_TREE') -> 'cirq.Moment':
517
- if isinstance(other, circuits.AbstractCircuit):
526
+ def __add__(self, other: cirq.OP_TREE) -> cirq.Moment:
527
+ if isinstance(other, circuit.AbstractCircuit):
518
528
  return NotImplemented # Delegate to Circuit.__radd__.
519
529
  return self.with_operations(other)
520
530
 
521
- def __sub__(self, other: 'cirq.OP_TREE') -> 'cirq.Moment':
531
+ def __sub__(self, other: cirq.OP_TREE) -> cirq.Moment:
522
532
  must_remove = set(op_tree.flatten_to_ops(other))
523
533
  new_ops = []
524
534
  for op in self.operations:
@@ -536,11 +546,11 @@ class Moment:
536
546
 
537
547
  # pylint: disable=function-redefined
538
548
  @overload
539
- def __getitem__(self, key: raw_types.Qid) -> 'cirq.Operation':
549
+ def __getitem__(self, key: raw_types.Qid) -> cirq.Operation:
540
550
  pass
541
551
 
542
552
  @overload
543
- def __getitem__(self, key: Iterable[raw_types.Qid]) -> 'cirq.Moment':
553
+ def __getitem__(self, key: Iterable[raw_types.Qid]) -> cirq.Moment:
544
554
  pass
545
555
 
546
556
  def __getitem__(self, key):
@@ -557,10 +567,10 @@ class Moment:
557
567
  return Moment(frozenset(ops_to_keep))
558
568
 
559
569
  def to_text_diagram(
560
- self: 'cirq.Moment',
570
+ self: cirq.Moment,
561
571
  *,
562
- xy_breakdown_func: Callable[['cirq.Qid'], Tuple[Any, Any]] = _default_breakdown,
563
- extra_qubits: Iterable['cirq.Qid'] = (),
572
+ xy_breakdown_func: Callable[[cirq.Qid], Tuple[Any, Any]] = _default_breakdown,
573
+ extra_qubits: Iterable[cirq.Qid] = (),
564
574
  use_unicode_characters: bool = True,
565
575
  precision: Optional[int] = None,
566
576
  include_tags: bool = True,
@@ -589,7 +599,7 @@ class Moment:
589
599
  """
590
600
 
591
601
  # Figure out where to place everything.
592
- qs = set(self.qubits) | set(extra_qubits)
602
+ qs = self._qubit_to_op.keys() | set(extra_qubits)
593
603
  points = {xy_breakdown_func(q) for q in qs}
594
604
  x_keys = sorted({pt[0] for pt in points}, key=_SortByValFallbackToType)
595
605
  y_keys = sorted({pt[1] for pt in points}, key=_SortByValFallbackToType)
@@ -648,37 +658,26 @@ class Moment:
648
658
  return diagram.render()
649
659
 
650
660
  def _commutes_(self, other: Any, *, atol: float = 1e-8) -> Union[bool, NotImplementedType]:
651
- """Determines whether Moment commutes with the Operation.
661
+ """Determines whether Moment commutes with the other Moment or Operation.
652
662
 
653
663
  Args:
654
- other: An Operation object. Other types are not implemented yet.
655
- In case a different type is specified, NotImplemented is
656
- returned.
664
+ other: An Operation or Moment object to test for commutativity.
657
665
  atol: Absolute error tolerance. If all entries in v1@v2 - v2@v1
658
666
  have a magnitude less than this tolerance, v1 and v2 can be
659
667
  reported as commuting. Defaults to 1e-8.
660
668
 
661
669
  Returns:
662
- True: The Moment and Operation commute OR they don't have shared
663
- quibits.
670
+ True: The Moment commutes with Moment or Operation OR they don't
671
+ have shared qubits.
664
672
  False: The two values do not commute.
665
673
  NotImplemented: In case we don't know how to check this, e.g.
666
- the parameter type is not supported yet.
674
+ the parameter type is not supported or commutativity cannot be
675
+ determined.
667
676
  """
668
- if not isinstance(other, ops.Operation):
677
+ if not isinstance(other, (ops.Operation, Moment)):
669
678
  return NotImplemented
670
-
671
- other_qubits = set(other.qubits)
672
- for op in self.operations:
673
- if not other_qubits.intersection(set(op.qubits)):
674
- continue
675
-
676
- commutes = protocols.commutes(op, other, atol=atol, default=NotImplemented)
677
-
678
- if not commutes or commutes is NotImplemented:
679
- return commutes
680
-
681
- return True
679
+ other_operations = other.operations if isinstance(other, Moment) else (other,)
680
+ return raw_types._operations_commutes_impl(self.operations, other_operations, atol=atol)
682
681
 
683
682
 
684
683
  class _SortByValFallbackToType:
@@ -294,6 +294,14 @@ def test_resolve_parameters():
294
294
  moment = cirq.Moment(cirq.X(a) ** sympy.Symbol('v'), cirq.Y(b) ** sympy.Symbol('w'))
295
295
  resolved_moment = cirq.resolve_parameters(moment, cirq.ParamResolver({'v': 0.1, 'w': 0.2}))
296
296
  assert resolved_moment == cirq.Moment(cirq.X(a) ** 0.1, cirq.Y(b) ** 0.2)
297
+ # sympy constant is resolved to a Python number
298
+ moment = cirq.Moment(cirq.Rz(rads=sympy.pi).on(a))
299
+ resolved_moment = cirq.resolve_parameters(moment, {'pi': np.pi})
300
+ assert resolved_moment == cirq.Moment(cirq.Rz(rads=np.pi).on(a))
301
+ resolved_gate = resolved_moment.operations[0].gate
302
+ assert not isinstance(resolved_gate.exponent, sympy.Basic)
303
+ assert isinstance(resolved_gate.exponent, float)
304
+ assert not cirq.is_parameterized(resolved_moment)
297
305
 
298
306
 
299
307
  def test_resolve_parameters_no_change():
@@ -672,7 +680,7 @@ def test_text_diagram_does_not_depend_on_insertion_order():
672
680
  assert str(m1) == str(m2)
673
681
 
674
682
 
675
- def test_commutes():
683
+ def test_commutes_moment_and_operation():
676
684
  a = cirq.NamedQubit('a')
677
685
  b = cirq.NamedQubit('b')
678
686
  c = cirq.NamedQubit('c')
@@ -680,7 +688,7 @@ def test_commutes():
680
688
 
681
689
  moment = cirq.Moment([cirq.X(a), cirq.Y(b), cirq.H(c)])
682
690
 
683
- assert NotImplemented == cirq.commutes(moment, a, default=NotImplemented)
691
+ assert cirq.commutes(moment, a, default=None) is None
684
692
 
685
693
  assert cirq.commutes(moment, cirq.X(a))
686
694
  assert cirq.commutes(moment, cirq.Y(b))
@@ -692,6 +700,101 @@ def test_commutes():
692
700
  assert not cirq.commutes(moment, cirq.H(b))
693
701
  assert not cirq.commutes(moment, cirq.X(c))
694
702
 
703
+ # Empty moment commutes with everything
704
+ moment = cirq.Moment()
705
+ assert cirq.commutes(moment, cirq.X(a))
706
+ assert cirq.commutes(moment, cirq.measure(b))
707
+
708
+ # Two qubit operation
709
+ moment = cirq.Moment(cirq.Z(a), cirq.Z(b))
710
+ assert cirq.commutes(moment, cirq.XX(a, b))
711
+
712
+
713
+ def test_commutes_moment_and_moment():
714
+ a = cirq.NamedQubit('a')
715
+ b = cirq.NamedQubit('b')
716
+ c = cirq.NamedQubit('c')
717
+
718
+ # Test cases where individual operations don't commute but moments do
719
+ # Two Z gates (Z⊗Z) commutes with RXX even though individual Z's don't
720
+ assert not cirq.commutes(cirq.Moment(cirq.Z(a)), cirq.Moment(cirq.XX(a, b)))
721
+ assert cirq.commutes(cirq.Moment(cirq.Z(a), cirq.Z(b)), cirq.Moment(cirq.XX(a, b)))
722
+
723
+ # Moments that do not commute if acting on same qubits
724
+ assert cirq.commutes(cirq.Moment(cirq.X(a)), cirq.Moment(cirq.Y(b)))
725
+ assert not cirq.commutes(cirq.Moment(cirq.X(a)), cirq.Moment(cirq.Y(a)))
726
+
727
+ # Moments commute with themselves
728
+ assert cirq.commutes(
729
+ cirq.Moment([cirq.X(a), cirq.Y(b), cirq.H(c)]),
730
+ cirq.Moment([cirq.X(a), cirq.Y(b), cirq.H(c)]),
731
+ )
732
+
733
+
734
+ def test_commutes_moment_with_controls():
735
+ a, b = cirq.LineQubit.range(2)
736
+ assert cirq.commutes(
737
+ cirq.Moment(cirq.measure(a, key='k0')), cirq.Moment(cirq.X(b).with_classical_controls('k1'))
738
+ )
739
+ assert cirq.commutes(
740
+ cirq.Moment(cirq.X(b).with_classical_controls('k1')), cirq.Moment(cirq.measure(a, key='k0'))
741
+ )
742
+ assert cirq.commutes(
743
+ cirq.Moment(cirq.X(a).with_classical_controls('k0')),
744
+ cirq.Moment(cirq.H(b).with_classical_controls('k0')),
745
+ )
746
+ assert cirq.commutes(
747
+ cirq.Moment(cirq.X(a).with_classical_controls('k0')),
748
+ cirq.Moment(cirq.X(a).with_classical_controls('k0')),
749
+ )
750
+ assert not cirq.commutes(
751
+ cirq.Moment(cirq.measure(a, key='k0')), cirq.Moment(cirq.X(b).with_classical_controls('k0'))
752
+ )
753
+ assert not cirq.commutes(
754
+ cirq.Moment(cirq.X(b).with_classical_controls('k0')), cirq.Moment(cirq.measure(a, key='k0'))
755
+ )
756
+ assert not cirq.commutes(
757
+ cirq.Moment(cirq.X(a).with_classical_controls('k0')),
758
+ cirq.Moment(cirq.H(a).with_classical_controls('k0')),
759
+ )
760
+
761
+
762
+ def test_commutes_moment_and_moment_comprehensive():
763
+ a, b, c, d = cirq.LineQubit.range(4)
764
+
765
+ # Basic Z⊗Z commuting with XX at different angles
766
+ m1 = cirq.Moment([cirq.Z(a), cirq.Z(b)])
767
+ m2 = cirq.Moment([cirq.XXPowGate(exponent=0.5)(a, b)])
768
+ assert cirq.commutes(m1, m2)
769
+
770
+ # Disjoint qubit sets
771
+ m1 = cirq.Moment([cirq.X(a), cirq.Y(b)])
772
+ m2 = cirq.Moment([cirq.Z(c), cirq.H(d)])
773
+ assert cirq.commutes(m1, m2)
774
+
775
+ # Mixed case - some commute individually, some as group
776
+ m1 = cirq.Moment([cirq.Z(a), cirq.Z(b), cirq.X(c)])
777
+ m2 = cirq.Moment([cirq.XXPowGate(exponent=0.5)(a, b), cirq.X(c)])
778
+ assert cirq.commutes(m1, m2)
779
+
780
+ # Non-commuting case: X on first qubit, Z on second with XX gate
781
+ m1 = cirq.Moment([cirq.X(a), cirq.Z(b)])
782
+ m2 = cirq.Moment([cirq.XX(a, b)])
783
+ assert not cirq.commutes(m1, m2)
784
+
785
+ # Complex case requiring unitary calculation - non-commuting case
786
+ m1 = cirq.Moment([cirq.Z(a), cirq.Z(b), cirq.Z(c)])
787
+ m2 = cirq.Moment([cirq.XXPowGate(exponent=0.5)(a, b), cirq.X(c)])
788
+ assert not cirq.commutes(m1, m2) # Z⊗Z⊗Z doesn't commute with XX⊗X
789
+
790
+
791
+ def test_commutes_handles_non_unitary_operation():
792
+ a = cirq.NamedQubit('a')
793
+ op_damp_a = cirq.AmplitudeDampingChannel(gamma=0.1).on(a)
794
+ assert cirq.commutes(cirq.Moment(cirq.X(a)), op_damp_a, default=None) is None
795
+ assert cirq.commutes(cirq.Moment(cirq.X(a)), cirq.Moment(op_damp_a), default=None) is None
796
+ assert cirq.commutes(cirq.Moment(op_damp_a), cirq.Moment(op_damp_a))
797
+
695
798
 
696
799
  def test_transform_qubits():
697
800
  a, b = cirq.LineQubit.range(2)
@@ -13,15 +13,17 @@
13
13
  # limitations under the License.
14
14
 
15
15
  """Defines the OptimizationPass type."""
16
+
17
+ from __future__ import annotations
18
+
16
19
  import abc
17
20
  from collections import defaultdict
18
- from typing import Dict, Callable, Iterable, Optional, Sequence, TYPE_CHECKING, Tuple, cast
21
+ from typing import Callable, cast, Dict, Iterable, Optional, Sequence, Tuple, TYPE_CHECKING
19
22
 
20
23
  from cirq import ops
21
24
 
22
25
  if TYPE_CHECKING:
23
26
  import cirq
24
- from cirq.ops import Qid
25
27
 
26
28
 
27
29
  class PointOptimizationSummary:
@@ -30,8 +32,8 @@ class PointOptimizationSummary:
30
32
  def __init__(
31
33
  self,
32
34
  clear_span: int,
33
- clear_qubits: Iterable['cirq.Qid'],
34
- new_operations: 'cirq.OP_TREE',
35
+ clear_qubits: Iterable[cirq.Qid],
36
+ new_operations: cirq.OP_TREE,
35
37
  preserve_moments: bool = False,
36
38
  ) -> None:
37
39
  """Inits PointOptimizationSummary.
@@ -87,9 +89,7 @@ class PointOptimizer:
87
89
 
88
90
  def __init__(
89
91
  self,
90
- post_clean_up: Callable[
91
- [Sequence['cirq.Operation']], 'cirq.OP_TREE'
92
- ] = lambda op_list: op_list,
92
+ post_clean_up: Callable[[Sequence[cirq.Operation]], cirq.OP_TREE] = lambda op_list: op_list,
93
93
  ) -> None:
94
94
  """Inits PointOptimizer.
95
95
 
@@ -100,13 +100,13 @@ class PointOptimizer:
100
100
  """
101
101
  self.post_clean_up = post_clean_up
102
102
 
103
- def __call__(self, circuit: 'cirq.Circuit'):
103
+ def __call__(self, circuit: cirq.Circuit):
104
104
  return self.optimize_circuit(circuit)
105
105
 
106
106
  @abc.abstractmethod
107
107
  def optimization_at(
108
- self, circuit: 'cirq.Circuit', index: int, op: 'cirq.Operation'
109
- ) -> Optional['cirq.PointOptimizationSummary']:
108
+ self, circuit: cirq.Circuit, index: int, op: cirq.Operation
109
+ ) -> Optional[cirq.PointOptimizationSummary]:
110
110
  """Describes how to change operations near the given location.
111
111
 
112
112
  For example, this method could realize that the given operation is an
@@ -126,8 +126,8 @@ class PointOptimizer:
126
126
  change should be made.
127
127
  """
128
128
 
129
- def optimize_circuit(self, circuit: 'cirq.Circuit'):
130
- frontier: Dict['Qid', int] = defaultdict(lambda: 0)
129
+ def optimize_circuit(self, circuit: cirq.Circuit):
130
+ frontier: Dict[cirq.Qid, int] = defaultdict(lambda: 0)
131
131
  i = 0
132
132
  while i < len(circuit): # Note: circuit may mutate as we go.
133
133
  for op in circuit[i].operations:
@@ -137,14 +137,14 @@ class PointOptimizer:
137
137
 
138
138
  # Skip if an optimization removed the circuit underneath us.
139
139
  if i >= len(circuit):
140
- continue
140
+ continue # pragma: no cover
141
141
  # Skip if an optimization removed the op we're considering.
142
142
  if op not in circuit[i].operations:
143
- continue
143
+ continue # pragma: no cover
144
144
  opt = self.optimization_at(circuit, i, op)
145
145
  # Skip if the optimization did nothing.
146
146
  if opt is None:
147
- continue
147
+ continue # pragma: no cover
148
148
 
149
149
  # Clear target area, and insert new operations.
150
150
  circuit.clear_operations_touching(