cirq-core 1.5.0.dev20250409225226__py3-none-any.whl → 1.6.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 (732) hide show
  1. cirq/__init__.py +16 -17
  2. cirq/_compat.py +21 -20
  3. cirq/_compat_test.py +14 -34
  4. cirq/_doc.py +4 -2
  5. cirq/_import.py +8 -6
  6. cirq/_import_test.py +4 -2
  7. cirq/_version.py +6 -6
  8. cirq/_version_test.py +2 -2
  9. cirq/circuits/_block_diagram_drawer.py +11 -10
  10. cirq/circuits/_block_diagram_drawer_test.py +8 -6
  11. cirq/circuits/_box_drawing_character_data.py +8 -8
  12. cirq/circuits/_box_drawing_character_data_test.py +3 -1
  13. cirq/circuits/_bucket_priority_queue.py +9 -7
  14. cirq/circuits/_bucket_priority_queue_test.py +22 -20
  15. cirq/circuits/circuit.py +248 -172
  16. cirq/circuits/circuit_operation.py +73 -83
  17. cirq/circuits/circuit_operation_test.py +128 -90
  18. cirq/circuits/circuit_test.py +211 -151
  19. cirq/circuits/frozen_circuit.py +23 -60
  20. cirq/circuits/frozen_circuit_test.py +31 -8
  21. cirq/circuits/insert_strategy.py +7 -5
  22. cirq/circuits/insert_strategy_test.py +4 -2
  23. cirq/circuits/moment.py +88 -40
  24. cirq/circuits/moment_test.py +128 -51
  25. cirq/circuits/optimization_pass.py +5 -5
  26. cirq/circuits/optimization_pass_test.py +10 -10
  27. cirq/circuits/qasm_output.py +11 -11
  28. cirq/circuits/qasm_output_test.py +25 -22
  29. cirq/circuits/text_diagram_drawer.py +23 -38
  30. cirq/circuits/text_diagram_drawer_test.py +19 -17
  31. cirq/conftest.py +4 -3
  32. cirq/contrib/__init__.py +4 -4
  33. cirq/contrib/acquaintance/__init__.py +1 -1
  34. cirq/contrib/acquaintance/bipartite.py +5 -8
  35. cirq/contrib/acquaintance/bipartite_test.py +18 -13
  36. cirq/contrib/acquaintance/devices.py +2 -2
  37. cirq/contrib/acquaintance/devices_test.py +5 -3
  38. cirq/contrib/acquaintance/executor.py +5 -5
  39. cirq/contrib/acquaintance/executor_test.py +13 -9
  40. cirq/contrib/acquaintance/gates.py +18 -28
  41. cirq/contrib/acquaintance/gates_test.py +24 -20
  42. cirq/contrib/acquaintance/inspection_utils.py +8 -4
  43. cirq/contrib/acquaintance/inspection_utils_test.py +4 -2
  44. cirq/contrib/acquaintance/mutation_utils.py +4 -4
  45. cirq/contrib/acquaintance/mutation_utils_test.py +4 -2
  46. cirq/contrib/acquaintance/optimizers.py +4 -4
  47. cirq/contrib/acquaintance/optimizers_test.py +4 -1
  48. cirq/contrib/acquaintance/permutation.py +15 -27
  49. cirq/contrib/acquaintance/permutation_test.py +26 -17
  50. cirq/contrib/acquaintance/shift.py +4 -4
  51. cirq/contrib/acquaintance/shift_swap_network.py +4 -4
  52. cirq/contrib/acquaintance/shift_swap_network_test.py +9 -6
  53. cirq/contrib/acquaintance/shift_test.py +8 -6
  54. cirq/contrib/acquaintance/strategies/cubic.py +2 -2
  55. cirq/contrib/acquaintance/strategies/cubic_test.py +4 -2
  56. cirq/contrib/acquaintance/strategies/quartic_paired.py +6 -6
  57. cirq/contrib/acquaintance/strategies/quartic_paired_test.py +10 -6
  58. cirq/contrib/acquaintance/testing.py +2 -0
  59. cirq/contrib/acquaintance/topological_sort.py +2 -2
  60. cirq/contrib/acquaintance/topological_sort_test.py +3 -1
  61. cirq/contrib/bayesian_network/bayesian_network_gate.py +9 -10
  62. cirq/contrib/bayesian_network/bayesian_network_gate_test.py +14 -9
  63. cirq/contrib/circuitdag/circuit_dag.py +4 -4
  64. cirq/contrib/circuitdag/circuit_dag_test.py +17 -15
  65. cirq/contrib/custom_simulators/custom_state_simulator.py +5 -5
  66. cirq/contrib/custom_simulators/custom_state_simulator_test.py +22 -17
  67. cirq/contrib/graph_device/graph_device.py +12 -11
  68. cirq/contrib/graph_device/graph_device_test.py +18 -14
  69. cirq/contrib/graph_device/hypergraph.py +16 -14
  70. cirq/contrib/graph_device/hypergraph_test.py +13 -11
  71. cirq/contrib/graph_device/uniform_graph_device.py +6 -4
  72. cirq/contrib/graph_device/uniform_graph_device_test.py +11 -3
  73. cirq/contrib/hacks/disable_validation.py +6 -1
  74. cirq/contrib/hacks/disable_validation_test.py +3 -1
  75. cirq/contrib/json.py +31 -5
  76. cirq/contrib/json_test.py +6 -3
  77. cirq/contrib/json_test_data/DampedReadoutNoiseModel.json +12 -0
  78. cirq/contrib/json_test_data/DampedReadoutNoiseModel.repr +4 -0
  79. cirq/contrib/json_test_data/DepolarizingNoiseModel.json +12 -0
  80. cirq/contrib/json_test_data/DepolarizingNoiseModel.repr +4 -0
  81. cirq/contrib/json_test_data/DepolarizingWithDampedReadoutNoiseModel.json +6 -0
  82. cirq/contrib/json_test_data/DepolarizingWithDampedReadoutNoiseModel.repr +1 -0
  83. cirq/contrib/json_test_data/DepolarizingWithReadoutNoiseModel.json +5 -0
  84. cirq/contrib/json_test_data/DepolarizingWithReadoutNoiseModel.repr +1 -0
  85. cirq/contrib/json_test_data/ReadoutNoiseModel.json +12 -0
  86. cirq/contrib/json_test_data/ReadoutNoiseModel.repr +4 -0
  87. cirq/contrib/json_test_data/__init__.py +17 -0
  88. cirq/contrib/json_test_data/spec.py +32 -0
  89. cirq/contrib/noise_models/noise_models.py +119 -5
  90. cirq/contrib/noise_models/noise_models_test.py +37 -9
  91. cirq/contrib/paulistring/clifford_optimize.py +6 -4
  92. cirq/contrib/paulistring/clifford_optimize_test.py +6 -5
  93. cirq/contrib/paulistring/clifford_target_gateset.py +10 -10
  94. cirq/contrib/paulistring/clifford_target_gateset_test.py +13 -11
  95. cirq/contrib/paulistring/optimize.py +2 -0
  96. cirq/contrib/paulistring/optimize_test.py +4 -3
  97. cirq/contrib/paulistring/pauli_string_dag.py +2 -0
  98. cirq/contrib/paulistring/pauli_string_dag_test.py +3 -1
  99. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +255 -120
  100. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +398 -19
  101. cirq/contrib/paulistring/pauli_string_optimize.py +7 -1
  102. cirq/contrib/paulistring/pauli_string_optimize_test.py +5 -3
  103. cirq/contrib/paulistring/recombine.py +6 -4
  104. cirq/contrib/paulistring/recombine_test.py +3 -1
  105. cirq/contrib/paulistring/separate.py +9 -6
  106. cirq/contrib/paulistring/separate_test.py +3 -1
  107. cirq/contrib/qasm_import/_lexer.py +3 -2
  108. cirq/contrib/qasm_import/_lexer_test.py +49 -13
  109. cirq/contrib/qasm_import/_parser.py +547 -83
  110. cirq/contrib/qasm_import/_parser_test.py +988 -97
  111. cirq/contrib/qasm_import/exception.py +2 -0
  112. cirq/contrib/qasm_import/qasm.py +8 -2
  113. cirq/contrib/qasm_import/qasm_test.py +7 -4
  114. cirq/contrib/qcircuit/qcircuit_diagram_info.py +5 -5
  115. cirq/contrib/qcircuit/qcircuit_diagram_info_test.py +4 -1
  116. cirq/contrib/qcircuit/qcircuit_pdf.py +7 -3
  117. cirq/contrib/qcircuit/qcircuit_pdf_test.py +3 -1
  118. cirq/contrib/qcircuit/qcircuit_test.py +10 -8
  119. cirq/contrib/quantum_volume/quantum_volume.py +31 -27
  120. cirq/contrib/quantum_volume/quantum_volume_test.py +19 -16
  121. cirq/contrib/quimb/density_matrix.py +15 -14
  122. cirq/contrib/quimb/density_matrix_test.py +10 -7
  123. cirq/contrib/quimb/grid_circuits.py +5 -2
  124. cirq/contrib/quimb/grid_circuits_test.py +3 -0
  125. cirq/contrib/quimb/mps_simulator.py +20 -20
  126. cirq/contrib/quimb/mps_simulator_test.py +3 -0
  127. cirq/contrib/quimb/state_vector.py +12 -11
  128. cirq/contrib/quimb/state_vector_test.py +3 -0
  129. cirq/contrib/quirk/export_to_quirk.py +5 -3
  130. cirq/contrib/quirk/export_to_quirk_test.py +18 -16
  131. cirq/contrib/quirk/linearize_circuit.py +2 -0
  132. cirq/contrib/quirk/quirk_gate.py +18 -17
  133. cirq/contrib/routing/device.py +5 -3
  134. cirq/contrib/routing/device_test.py +2 -0
  135. cirq/contrib/routing/greedy.py +10 -21
  136. cirq/contrib/routing/greedy_test.py +4 -2
  137. cirq/contrib/routing/initialization.py +2 -2
  138. cirq/contrib/routing/initialization_test.py +5 -3
  139. cirq/contrib/routing/router.py +9 -5
  140. cirq/contrib/routing/router_test.py +2 -0
  141. cirq/contrib/routing/swap_network.py +3 -3
  142. cirq/contrib/routing/swap_network_test.py +3 -1
  143. cirq/contrib/routing/utils.py +2 -2
  144. cirq/contrib/routing/utils_test.py +3 -0
  145. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +15 -9
  146. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py +3 -0
  147. cirq/contrib/svg/svg.py +3 -3
  148. cirq/contrib/svg/svg_test.py +8 -5
  149. cirq/devices/device.py +4 -4
  150. cirq/devices/device_test.py +7 -4
  151. cirq/devices/grid_device_metadata.py +10 -10
  152. cirq/devices/grid_device_metadata_test.py +3 -0
  153. cirq/devices/grid_qubit.py +29 -21
  154. cirq/devices/grid_qubit_test.py +3 -0
  155. cirq/devices/insertion_noise_model.py +7 -7
  156. cirq/devices/insertion_noise_model_test.py +7 -5
  157. cirq/devices/line_qubit.py +13 -13
  158. cirq/devices/line_qubit_test.py +2 -0
  159. cirq/devices/named_topologies.py +18 -29
  160. cirq/devices/named_topologies_test.py +13 -10
  161. cirq/devices/noise_model.py +3 -3
  162. cirq/devices/noise_model_test.py +19 -15
  163. cirq/devices/noise_properties.py +15 -6
  164. cirq/devices/noise_properties_test.py +34 -3
  165. cirq/devices/noise_utils.py +11 -9
  166. cirq/devices/noise_utils_test.py +2 -0
  167. cirq/devices/superconducting_qubits_noise_properties.py +23 -22
  168. cirq/devices/superconducting_qubits_noise_properties_test.py +6 -6
  169. cirq/devices/thermal_noise_model.py +107 -37
  170. cirq/devices/thermal_noise_model_test.py +21 -0
  171. cirq/devices/unconstrained_device.py +5 -3
  172. cirq/devices/unconstrained_device_test.py +2 -0
  173. cirq/experiments/__init__.py +4 -2
  174. cirq/experiments/benchmarking/__init__.py +17 -0
  175. cirq/experiments/benchmarking/parallel_xeb.py +677 -0
  176. cirq/experiments/benchmarking/parallel_xeb_test.py +447 -0
  177. cirq/experiments/fidelity_estimation.py +14 -8
  178. cirq/experiments/fidelity_estimation_test.py +3 -0
  179. cirq/experiments/n_qubit_tomography.py +17 -16
  180. cirq/experiments/n_qubit_tomography_test.py +8 -5
  181. cirq/experiments/purity_estimation.py +2 -0
  182. cirq/experiments/purity_estimation_test.py +2 -0
  183. cirq/experiments/qubit_characterizations.py +207 -103
  184. cirq/experiments/qubit_characterizations_test.py +40 -12
  185. cirq/experiments/random_quantum_circuit_generation.py +56 -70
  186. cirq/experiments/random_quantum_circuit_generation_test.py +11 -8
  187. cirq/experiments/readout_confusion_matrix.py +24 -22
  188. cirq/experiments/readout_confusion_matrix_test.py +2 -0
  189. cirq/experiments/single_qubit_readout_calibration.py +30 -15
  190. cirq/experiments/single_qubit_readout_calibration_test.py +5 -2
  191. cirq/experiments/t1_decay_experiment.py +9 -7
  192. cirq/experiments/t1_decay_experiment_test.py +13 -11
  193. cirq/experiments/t2_decay_experiment.py +16 -13
  194. cirq/experiments/t2_decay_experiment_test.py +2 -0
  195. cirq/experiments/two_qubit_xeb.py +64 -57
  196. cirq/experiments/two_qubit_xeb_test.py +10 -6
  197. cirq/experiments/xeb_fitting.py +39 -35
  198. cirq/experiments/xeb_sampling.py +37 -44
  199. cirq/experiments/xeb_sampling_test.py +3 -0
  200. cirq/experiments/xeb_simulation.py +14 -10
  201. cirq/experiments/xeb_simulation_test.py +5 -5
  202. cirq/experiments/z_phase_calibration.py +32 -29
  203. cirq/experiments/z_phase_calibration_test.py +3 -4
  204. cirq/interop/quirk/cells/__init__.py +1 -1
  205. cirq/interop/quirk/cells/all_cells.py +7 -2
  206. cirq/interop/quirk/cells/arithmetic_cells.py +29 -41
  207. cirq/interop/quirk/cells/arithmetic_cells_test.py +17 -14
  208. cirq/interop/quirk/cells/cell.py +19 -28
  209. cirq/interop/quirk/cells/cell_test.py +3 -0
  210. cirq/interop/quirk/cells/composite_cell.py +13 -28
  211. cirq/interop/quirk/cells/composite_cell_test.py +2 -0
  212. cirq/interop/quirk/cells/control_cells.py +15 -15
  213. cirq/interop/quirk/cells/control_cells_test.py +7 -5
  214. cirq/interop/quirk/cells/frequency_space_cells.py +4 -3
  215. cirq/interop/quirk/cells/frequency_space_cells_test.py +3 -1
  216. cirq/interop/quirk/cells/ignored_cells.py +3 -0
  217. cirq/interop/quirk/cells/ignored_cells_test.py +3 -1
  218. cirq/interop/quirk/cells/input_cells.py +7 -5
  219. cirq/interop/quirk/cells/input_cells_test.py +7 -5
  220. cirq/interop/quirk/cells/input_rotation_cells.py +15 -13
  221. cirq/interop/quirk/cells/input_rotation_cells_test.py +9 -7
  222. cirq/interop/quirk/cells/measurement_cells.py +5 -2
  223. cirq/interop/quirk/cells/measurement_cells_test.py +3 -1
  224. cirq/interop/quirk/cells/parse.py +22 -23
  225. cirq/interop/quirk/cells/parse_test.py +12 -10
  226. cirq/interop/quirk/cells/qubit_permutation_cells.py +5 -3
  227. cirq/interop/quirk/cells/qubit_permutation_cells_test.py +9 -7
  228. cirq/interop/quirk/cells/scalar_cells.py +4 -1
  229. cirq/interop/quirk/cells/scalar_cells_test.py +3 -1
  230. cirq/interop/quirk/cells/single_qubit_rotation_cells.py +5 -2
  231. cirq/interop/quirk/cells/single_qubit_rotation_cells_test.py +5 -3
  232. cirq/interop/quirk/cells/swap_cell.py +8 -6
  233. cirq/interop/quirk/cells/swap_cell_test.py +6 -4
  234. cirq/interop/quirk/cells/testing.py +6 -6
  235. cirq/interop/quirk/cells/testing_test.py +8 -6
  236. cirq/interop/quirk/cells/unsupported_cells.py +3 -0
  237. cirq/interop/quirk/cells/unsupported_cells_test.py +4 -2
  238. cirq/interop/quirk/url_to_circuit.py +23 -36
  239. cirq/interop/quirk/url_to_circuit_test.py +4 -1
  240. cirq/json_resolver_cache.py +14 -12
  241. cirq/linalg/__init__.py +4 -6
  242. cirq/linalg/combinators.py +7 -5
  243. cirq/linalg/combinators_test.py +10 -7
  244. cirq/linalg/decompositions.py +24 -35
  245. cirq/linalg/decompositions_test.py +3 -1
  246. cirq/linalg/diagonalize.py +6 -4
  247. cirq/linalg/diagonalize_test.py +15 -14
  248. cirq/linalg/operator_spaces.py +14 -14
  249. cirq/linalg/operator_spaces_test.py +13 -11
  250. cirq/linalg/predicates.py +18 -9
  251. cirq/linalg/predicates_test.py +5 -0
  252. cirq/linalg/tolerance.py +6 -3
  253. cirq/linalg/tolerance_test.py +6 -4
  254. cirq/linalg/transformations.py +23 -20
  255. cirq/linalg/transformations_test.py +73 -43
  256. cirq/neutral_atoms/convert_to_neutral_atom_gates.py +9 -3
  257. cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py +3 -1
  258. cirq/neutral_atoms/neutral_atom_devices.py +2 -0
  259. cirq/ops/__init__.py +2 -0
  260. cirq/ops/arithmetic_operation.py +21 -21
  261. cirq/ops/arithmetic_operation_test.py +7 -8
  262. cirq/ops/boolean_hamiltonian.py +23 -22
  263. cirq/ops/boolean_hamiltonian_test.py +12 -9
  264. cirq/ops/classically_controlled_operation.py +31 -36
  265. cirq/ops/classically_controlled_operation_test.py +121 -117
  266. cirq/ops/clifford_gate.py +98 -81
  267. cirq/ops/clifford_gate_test.py +72 -57
  268. cirq/ops/common_channels.py +44 -44
  269. cirq/ops/common_channels_test.py +83 -81
  270. cirq/ops/common_gate_families.py +9 -7
  271. cirq/ops/common_gate_families_test.py +11 -7
  272. cirq/ops/common_gates.py +164 -183
  273. cirq/ops/common_gates_test.py +135 -95
  274. cirq/ops/control_values.py +23 -26
  275. cirq/ops/control_values_test.py +22 -20
  276. cirq/ops/controlled_gate.py +64 -112
  277. cirq/ops/controlled_gate_test.py +130 -35
  278. cirq/ops/controlled_operation.py +24 -35
  279. cirq/ops/controlled_operation_test.py +8 -6
  280. cirq/ops/dense_pauli_string.py +38 -49
  281. cirq/ops/dense_pauli_string_test.py +4 -2
  282. cirq/ops/diagonal_gate.py +18 -31
  283. cirq/ops/diagonal_gate_test.py +13 -13
  284. cirq/ops/eigen_gate.py +29 -29
  285. cirq/ops/eigen_gate_test.py +45 -28
  286. cirq/ops/fourier_transform.py +14 -20
  287. cirq/ops/fourier_transform_test.py +15 -12
  288. cirq/ops/fsim_gate.py +43 -42
  289. cirq/ops/fsim_gate_test.py +29 -29
  290. cirq/ops/gate_features.py +2 -0
  291. cirq/ops/gate_features_test.py +5 -3
  292. cirq/ops/gate_operation.py +43 -65
  293. cirq/ops/gate_operation_test.py +46 -42
  294. cirq/ops/gateset.py +28 -40
  295. cirq/ops/gateset_test.py +4 -2
  296. cirq/ops/global_phase_op.py +45 -20
  297. cirq/ops/global_phase_op_test.py +44 -20
  298. cirq/ops/greedy_qubit_manager.py +10 -8
  299. cirq/ops/greedy_qubit_manager_test.py +5 -3
  300. cirq/ops/identity.py +14 -12
  301. cirq/ops/identity_test.py +24 -20
  302. cirq/ops/kraus_channel.py +11 -8
  303. cirq/ops/kraus_channel_test.py +14 -11
  304. cirq/ops/linear_combinations.py +65 -77
  305. cirq/ops/linear_combinations_test.py +14 -9
  306. cirq/ops/matrix_gates.py +21 -18
  307. cirq/ops/matrix_gates_test.py +16 -0
  308. cirq/ops/measure_util.py +15 -20
  309. cirq/ops/measure_util_test.py +2 -0
  310. cirq/ops/measurement_gate.py +26 -37
  311. cirq/ops/measurement_gate_test.py +2 -0
  312. cirq/ops/mixed_unitary_channel.py +12 -9
  313. cirq/ops/mixed_unitary_channel_test.py +14 -11
  314. cirq/ops/named_qubit.py +16 -13
  315. cirq/ops/named_qubit_test.py +15 -13
  316. cirq/ops/op_tree.py +9 -7
  317. cirq/ops/op_tree_test.py +22 -19
  318. cirq/ops/parallel_gate.py +15 -17
  319. cirq/ops/parallel_gate_test.py +18 -16
  320. cirq/ops/parity_gates.py +23 -25
  321. cirq/ops/parity_gates_test.py +36 -32
  322. cirq/ops/pauli_gates.py +22 -21
  323. cirq/ops/pauli_gates_test.py +29 -20
  324. cirq/ops/pauli_interaction_gate.py +15 -19
  325. cirq/ops/pauli_interaction_gate_test.py +10 -8
  326. cirq/ops/pauli_measurement_gate.py +23 -35
  327. cirq/ops/pauli_measurement_gate_test.py +2 -0
  328. cirq/ops/pauli_string.py +92 -120
  329. cirq/ops/pauli_string_phasor.py +52 -45
  330. cirq/ops/pauli_string_phasor_test.py +4 -5
  331. cirq/ops/pauli_string_raw_types.py +9 -7
  332. cirq/ops/pauli_string_raw_types_test.py +2 -0
  333. cirq/ops/pauli_string_test.py +31 -154
  334. cirq/ops/pauli_sum_exponential.py +12 -12
  335. cirq/ops/pauli_sum_exponential_test.py +12 -10
  336. cirq/ops/permutation_gate.py +8 -6
  337. cirq/ops/permutation_gate_test.py +10 -8
  338. cirq/ops/phased_iswap_gate.py +16 -16
  339. cirq/ops/phased_iswap_gate_test.py +17 -15
  340. cirq/ops/phased_x_gate.py +16 -17
  341. cirq/ops/phased_x_gate_test.py +18 -16
  342. cirq/ops/phased_x_z_gate.py +24 -22
  343. cirq/ops/phased_x_z_gate_test.py +17 -11
  344. cirq/ops/projector.py +16 -11
  345. cirq/ops/projector_test.py +19 -16
  346. cirq/ops/qid_util.py +7 -5
  347. cirq/ops/qid_util_test.py +2 -0
  348. cirq/ops/qubit_manager.py +11 -9
  349. cirq/ops/qubit_manager_test.py +6 -4
  350. cirq/ops/qubit_order.py +11 -14
  351. cirq/ops/qubit_order_or_list.py +4 -2
  352. cirq/ops/qubit_order_test.py +12 -10
  353. cirq/ops/random_gate_channel.py +12 -10
  354. cirq/ops/random_gate_channel_test.py +14 -11
  355. cirq/ops/raw_types.py +109 -129
  356. cirq/ops/raw_types_test.py +63 -57
  357. cirq/ops/state_preparation_channel.py +7 -7
  358. cirq/ops/state_preparation_channel_test.py +11 -9
  359. cirq/ops/swap_gates.py +13 -15
  360. cirq/ops/swap_gates_test.py +19 -17
  361. cirq/ops/tags.py +5 -3
  362. cirq/ops/tags_test.py +4 -2
  363. cirq/ops/three_qubit_gates.py +43 -76
  364. cirq/ops/three_qubit_gates_test.py +19 -17
  365. cirq/ops/two_qubit_diagonal_gate.py +13 -13
  366. cirq/ops/two_qubit_diagonal_gate_test.py +10 -8
  367. cirq/ops/uniform_superposition_gate.py +5 -3
  368. cirq/ops/uniform_superposition_gate_test.py +5 -3
  369. cirq/ops/wait_gate.py +17 -14
  370. cirq/ops/wait_gate_test.py +9 -6
  371. cirq/protocols/__init__.py +0 -3
  372. cirq/protocols/act_on_protocol.py +8 -6
  373. cirq/protocols/act_on_protocol_test.py +15 -12
  374. cirq/protocols/apply_channel_protocol.py +10 -14
  375. cirq/protocols/apply_channel_protocol_test.py +2 -0
  376. cirq/protocols/apply_mixture_protocol.py +13 -42
  377. cirq/protocols/apply_mixture_protocol_test.py +7 -5
  378. cirq/protocols/apply_unitary_protocol.py +39 -34
  379. cirq/protocols/apply_unitary_protocol_test.py +4 -1
  380. cirq/protocols/approximate_equality_protocol.py +2 -0
  381. cirq/protocols/approximate_equality_protocol_test.py +2 -0
  382. cirq/protocols/circuit_diagram_info_protocol.py +58 -42
  383. cirq/protocols/circuit_diagram_info_protocol_test.py +70 -12
  384. cirq/protocols/commutes_protocol.py +8 -7
  385. cirq/protocols/commutes_protocol_test.py +2 -0
  386. cirq/protocols/control_key_protocol.py +6 -4
  387. cirq/protocols/control_key_protocol_test.py +3 -1
  388. cirq/protocols/decompose_protocol.py +49 -48
  389. cirq/protocols/decompose_protocol_test.py +27 -16
  390. cirq/protocols/equal_up_to_global_phase_protocol.py +2 -0
  391. cirq/protocols/equal_up_to_global_phase_protocol_test.py +9 -6
  392. cirq/protocols/has_stabilizer_effect_protocol.py +7 -5
  393. cirq/protocols/has_stabilizer_effect_protocol_test.py +7 -5
  394. cirq/protocols/has_unitary_protocol.py +10 -6
  395. cirq/protocols/has_unitary_protocol_test.py +13 -8
  396. cirq/protocols/hash_from_pickle_test.py +2 -11
  397. cirq/protocols/inverse_protocol.py +13 -16
  398. cirq/protocols/inverse_protocol_test.py +5 -3
  399. cirq/protocols/json_serialization.py +35 -54
  400. cirq/protocols/json_serialization_test.py +14 -21
  401. cirq/protocols/json_test_data/CXSWAP.json +46 -0
  402. cirq/protocols/json_test_data/CXSWAP.repr +13 -0
  403. cirq/protocols/json_test_data/CZSWAP.json +46 -0
  404. cirq/protocols/json_test_data/CZSWAP.repr +13 -0
  405. cirq/protocols/json_test_data/CircuitOperation.json +6 -3
  406. cirq/protocols/json_test_data/CircuitOperation.repr_inward +4 -2
  407. cirq/protocols/json_test_data/Moment.json +24 -1
  408. cirq/protocols/json_test_data/Moment.repr +6 -1
  409. cirq/protocols/json_test_data/ThermalNoiseModel.json +32 -0
  410. cirq/protocols/json_test_data/ThermalNoiseModel.repr +1 -0
  411. cirq/protocols/json_test_data/spec.py +6 -2
  412. cirq/protocols/kraus_protocol.py +47 -7
  413. cirq/protocols/kraus_protocol_test.py +86 -12
  414. cirq/protocols/measurement_key_protocol.py +15 -16
  415. cirq/protocols/measurement_key_protocol_test.py +13 -11
  416. cirq/protocols/mixture_protocol.py +7 -5
  417. cirq/protocols/mixture_protocol_test.py +4 -2
  418. cirq/protocols/mul_protocol.py +2 -3
  419. cirq/protocols/mul_protocol_test.py +2 -0
  420. cirq/protocols/pauli_expansion_protocol.py +6 -3
  421. cirq/protocols/pauli_expansion_protocol_test.py +5 -3
  422. cirq/protocols/phase_protocol.py +2 -0
  423. cirq/protocols/phase_protocol_test.py +3 -1
  424. cirq/protocols/pow_protocol.py +11 -16
  425. cirq/protocols/pow_protocol_test.py +2 -0
  426. cirq/protocols/qasm.py +14 -20
  427. cirq/protocols/qasm_test.py +6 -3
  428. cirq/protocols/qid_shape_protocol.py +8 -8
  429. cirq/protocols/qid_shape_protocol_test.py +3 -1
  430. cirq/protocols/resolve_parameters.py +5 -3
  431. cirq/protocols/resolve_parameters_test.py +8 -7
  432. cirq/protocols/trace_distance_bound.py +6 -4
  433. cirq/protocols/trace_distance_bound_test.py +3 -1
  434. cirq/protocols/unitary_protocol.py +17 -7
  435. cirq/protocols/unitary_protocol_test.py +12 -2
  436. cirq/qis/channels.py +6 -2
  437. cirq/qis/channels_test.py +20 -16
  438. cirq/qis/clifford_tableau.py +21 -19
  439. cirq/qis/clifford_tableau_test.py +2 -2
  440. cirq/qis/entropy.py +14 -3
  441. cirq/qis/entropy_test.py +3 -1
  442. cirq/qis/measures.py +13 -13
  443. cirq/qis/measures_test.py +20 -14
  444. cirq/qis/noise_utils.py +2 -0
  445. cirq/qis/noise_utils_test.py +9 -7
  446. cirq/qis/quantum_state_representation.py +7 -8
  447. cirq/qis/states.py +58 -56
  448. cirq/qis/states_test.py +2 -0
  449. cirq/sim/classical_simulator.py +23 -22
  450. cirq/sim/classical_simulator_test.py +2 -0
  451. cirq/sim/clifford/clifford_simulator.py +23 -21
  452. cirq/sim/clifford/clifford_simulator_test.py +7 -4
  453. cirq/sim/clifford/clifford_tableau_simulation_state.py +10 -7
  454. cirq/sim/clifford/clifford_tableau_simulation_state_test.py +5 -5
  455. cirq/sim/clifford/stabilizer_ch_form_simulation_state.py +8 -6
  456. cirq/sim/clifford/stabilizer_ch_form_simulation_state_test.py +8 -6
  457. cirq/sim/clifford/stabilizer_sampler.py +9 -7
  458. cirq/sim/clifford/stabilizer_sampler_test.py +4 -2
  459. cirq/sim/clifford/stabilizer_simulation_state.py +14 -13
  460. cirq/sim/clifford/stabilizer_simulation_state_test.py +6 -4
  461. cirq/sim/clifford/stabilizer_state_ch_form.py +13 -11
  462. cirq/sim/clifford/stabilizer_state_ch_form_test.py +4 -2
  463. cirq/sim/density_matrix_simulation_state.py +26 -27
  464. cirq/sim/density_matrix_simulation_state_test.py +10 -8
  465. cirq/sim/density_matrix_simulator.py +30 -28
  466. cirq/sim/density_matrix_simulator_test.py +48 -48
  467. cirq/sim/density_matrix_utils.py +13 -11
  468. cirq/sim/density_matrix_utils_test.py +38 -36
  469. cirq/sim/mux.py +33 -31
  470. cirq/sim/mux_test.py +3 -0
  471. cirq/sim/simulation_product_state.py +15 -15
  472. cirq/sim/simulation_product_state_test.py +29 -26
  473. cirq/sim/simulation_state.py +29 -38
  474. cirq/sim/simulation_state_base.py +21 -32
  475. cirq/sim/simulation_state_test.py +15 -13
  476. cirq/sim/simulation_utils.py +5 -2
  477. cirq/sim/simulation_utils_test.py +5 -2
  478. cirq/sim/simulator.py +90 -106
  479. cirq/sim/simulator_base.py +33 -45
  480. cirq/sim/simulator_base_test.py +20 -15
  481. cirq/sim/simulator_test.py +23 -14
  482. cirq/sim/sparse_simulator.py +19 -17
  483. cirq/sim/sparse_simulator_test.py +41 -40
  484. cirq/sim/state_vector.py +15 -12
  485. cirq/sim/state_vector_simulation_state.py +31 -31
  486. cirq/sim/state_vector_simulation_state_test.py +16 -14
  487. cirq/sim/state_vector_simulator.py +17 -14
  488. cirq/sim/state_vector_simulator_test.py +2 -0
  489. cirq/sim/state_vector_test.py +6 -3
  490. cirq/study/flatten_expressions.py +16 -15
  491. cirq/study/flatten_expressions_test.py +13 -11
  492. cirq/study/resolver.py +18 -17
  493. cirq/study/resolver_test.py +22 -20
  494. cirq/study/result.py +17 -27
  495. cirq/study/result_test.py +2 -0
  496. cirq/study/sweepable.py +12 -10
  497. cirq/study/sweepable_test.py +3 -0
  498. cirq/study/sweeps.py +42 -61
  499. cirq/study/sweeps_test.py +33 -0
  500. cirq/testing/__init__.py +7 -11
  501. cirq/testing/_compat_test_data/module_a/__init__.py +1 -0
  502. cirq/testing/_compat_test_data/module_a/module_b/__init__.py +1 -0
  503. cirq/testing/_compat_test_data/module_a/sub/__init__.py +1 -0
  504. cirq/testing/circuit_compare.py +8 -17
  505. cirq/testing/circuit_compare_test.py +2 -0
  506. cirq/testing/consistent_act_on.py +13 -11
  507. cirq/testing/consistent_act_on_test.py +5 -3
  508. cirq/testing/consistent_channels.py +2 -0
  509. cirq/testing/consistent_channels_test.py +10 -8
  510. cirq/testing/consistent_controlled_gate_op.py +5 -5
  511. cirq/testing/consistent_controlled_gate_op_test.py +18 -18
  512. cirq/testing/consistent_decomposition.py +2 -2
  513. cirq/testing/consistent_decomposition_test.py +4 -2
  514. cirq/testing/consistent_pauli_expansion.py +2 -0
  515. cirq/testing/consistent_pauli_expansion_test.py +3 -1
  516. cirq/testing/consistent_phase_by.py +2 -0
  517. cirq/testing/consistent_phase_by_test.py +3 -1
  518. cirq/testing/consistent_protocols.py +14 -20
  519. cirq/testing/consistent_protocols_test.py +13 -11
  520. cirq/testing/consistent_qasm.py +6 -4
  521. cirq/testing/consistent_qasm_test.py +7 -7
  522. cirq/testing/consistent_resolve_parameters.py +2 -0
  523. cirq/testing/consistent_specified_has_unitary.py +2 -2
  524. cirq/testing/consistent_specified_has_unitary_test.py +6 -4
  525. cirq/testing/consistent_unitary.py +1 -0
  526. cirq/testing/consistent_unitary_test.py +4 -2
  527. cirq/testing/deprecation.py +5 -2
  528. cirq/testing/deprecation_test.py +5 -2
  529. cirq/testing/devices.py +7 -4
  530. cirq/testing/devices_test.py +7 -4
  531. cirq/testing/equals_tester.py +4 -2
  532. cirq/testing/equals_tester_test.py +21 -17
  533. cirq/testing/equivalent_basis_map.py +6 -4
  534. cirq/testing/equivalent_basis_map_test.py +6 -4
  535. cirq/testing/equivalent_repr_eval.py +6 -4
  536. cirq/testing/equivalent_repr_eval_test.py +5 -3
  537. cirq/testing/gate_features.py +2 -0
  538. cirq/testing/gate_features_test.py +7 -5
  539. cirq/testing/json.py +19 -15
  540. cirq/testing/json_test.py +5 -3
  541. cirq/testing/lin_alg_utils.py +10 -11
  542. cirq/testing/lin_alg_utils_test.py +14 -12
  543. cirq/testing/logs.py +7 -6
  544. cirq/testing/logs_test.py +9 -7
  545. cirq/testing/no_identifier_qubit.py +4 -2
  546. cirq/testing/no_identifier_qubit_test.py +5 -3
  547. cirq/testing/op_tree.py +2 -0
  548. cirq/testing/op_tree_test.py +4 -1
  549. cirq/testing/order_tester.py +2 -0
  550. cirq/testing/order_tester_test.py +8 -6
  551. cirq/testing/pytest_utils.py +2 -0
  552. cirq/testing/pytest_utils_test.py +4 -2
  553. cirq/testing/random_circuit.py +21 -20
  554. cirq/testing/random_circuit_test.py +12 -9
  555. cirq/testing/repr_pretty_tester.py +1 -0
  556. cirq/testing/repr_pretty_tester_test.py +5 -3
  557. cirq/testing/routing_devices.py +4 -1
  558. cirq/testing/routing_devices_test.py +9 -6
  559. cirq/testing/sample_circuits.py +4 -1
  560. cirq/testing/sample_circuits_test.py +3 -1
  561. cirq/testing/sample_gates.py +3 -0
  562. cirq/testing/sample_gates_test.py +5 -2
  563. cirq/transformers/__init__.py +11 -4
  564. cirq/transformers/align.py +9 -7
  565. cirq/transformers/align_test.py +2 -0
  566. cirq/transformers/analytical_decompositions/__init__.py +3 -6
  567. cirq/transformers/analytical_decompositions/clifford_decomposition.py +18 -16
  568. cirq/transformers/analytical_decompositions/clifford_decomposition_test.py +2 -0
  569. cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +19 -16
  570. cirq/transformers/analytical_decompositions/controlled_gate_decomposition_test.py +2 -0
  571. cirq/transformers/analytical_decompositions/cphase_to_fsim.py +11 -9
  572. cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +5 -3
  573. cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +5 -3
  574. cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +5 -3
  575. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +141 -44
  576. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +35 -1
  577. cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +8 -7
  578. cirq/transformers/analytical_decompositions/single_qubit_decompositions_test.py +2 -0
  579. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry.py +7 -4
  580. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry_test.py +3 -0
  581. cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +11 -19
  582. cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +8 -33
  583. cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +9 -11
  584. cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +2 -0
  585. cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +91 -27
  586. cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +36 -7
  587. cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +20 -21
  588. cirq/transformers/analytical_decompositions/two_qubit_to_fsim_test.py +8 -6
  589. cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +13 -15
  590. cirq/transformers/analytical_decompositions/two_qubit_to_ms_test.py +3 -1
  591. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +39 -41
  592. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap_test.py +2 -0
  593. cirq/transformers/drop_empty_moments.py +5 -3
  594. cirq/transformers/drop_empty_moments_test.py +4 -2
  595. cirq/transformers/drop_negligible_operations.py +7 -5
  596. cirq/transformers/drop_negligible_operations_test.py +2 -0
  597. cirq/transformers/dynamical_decoupling.py +49 -42
  598. cirq/transformers/dynamical_decoupling_test.py +223 -205
  599. cirq/transformers/eject_phased_paulis.py +28 -26
  600. cirq/transformers/eject_phased_paulis_test.py +12 -9
  601. cirq/transformers/eject_z.py +12 -12
  602. cirq/transformers/eject_z_test.py +2 -2
  603. cirq/transformers/expand_composite.py +6 -4
  604. cirq/transformers/expand_composite_test.py +3 -1
  605. cirq/transformers/gauge_compiling/__init__.py +3 -1
  606. cirq/transformers/gauge_compiling/cphase_gauge.py +2 -0
  607. cirq/transformers/gauge_compiling/cphase_gauge_test.py +2 -0
  608. cirq/transformers/gauge_compiling/cz_gauge.py +2 -0
  609. cirq/transformers/gauge_compiling/cz_gauge_test.py +1 -0
  610. cirq/transformers/gauge_compiling/gauge_compiling.py +45 -41
  611. cirq/transformers/gauge_compiling/gauge_compiling_test.py +2 -0
  612. cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +1 -0
  613. cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +5 -1
  614. cirq/transformers/gauge_compiling/iswap_gauge.py +2 -0
  615. cirq/transformers/gauge_compiling/iswap_gauge_test.py +1 -0
  616. cirq/transformers/gauge_compiling/spin_inversion_gauge.py +2 -0
  617. cirq/transformers/gauge_compiling/spin_inversion_gauge_test.py +2 -0
  618. cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +7 -6
  619. cirq/transformers/gauge_compiling/sqrt_cz_gauge_test.py +2 -0
  620. cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +2 -0
  621. cirq/transformers/gauge_compiling/sqrt_iswap_gauge_test.py +2 -0
  622. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +6 -3
  623. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils_test.py +3 -0
  624. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +12 -9
  625. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation_test.py +9 -7
  626. cirq/transformers/insertion_sort.py +8 -6
  627. cirq/transformers/insertion_sort_test.py +3 -1
  628. cirq/transformers/measurement_transformers.py +29 -29
  629. cirq/transformers/measurement_transformers_test.py +2 -0
  630. cirq/transformers/merge_k_qubit_gates.py +12 -10
  631. cirq/transformers/merge_k_qubit_gates_test.py +18 -18
  632. cirq/transformers/merge_single_qubit_gates.py +197 -20
  633. cirq/transformers/merge_single_qubit_gates_test.py +177 -5
  634. cirq/transformers/noise_adding.py +5 -3
  635. cirq/transformers/noise_adding_test.py +2 -0
  636. cirq/transformers/optimize_for_target_gateset.py +19 -17
  637. cirq/transformers/optimize_for_target_gateset_test.py +11 -8
  638. cirq/transformers/qubit_management_transformers.py +13 -11
  639. cirq/transformers/qubit_management_transformers_test.py +5 -3
  640. cirq/transformers/randomized_measurements.py +16 -14
  641. cirq/transformers/randomized_measurements_test.py +10 -4
  642. cirq/transformers/routing/initial_mapper.py +6 -4
  643. cirq/transformers/routing/initial_mapper_test.py +2 -0
  644. cirq/transformers/routing/line_initial_mapper.py +16 -14
  645. cirq/transformers/routing/line_initial_mapper_test.py +9 -7
  646. cirq/transformers/routing/mapping_manager.py +10 -10
  647. cirq/transformers/routing/mapping_manager_test.py +2 -0
  648. cirq/transformers/routing/route_circuit_cqc.py +33 -31
  649. cirq/transformers/routing/route_circuit_cqc_test.py +15 -13
  650. cirq/transformers/routing/visualize_routed_circuit.py +8 -7
  651. cirq/transformers/routing/visualize_routed_circuit_test.py +4 -2
  652. cirq/transformers/stratify.py +17 -15
  653. cirq/transformers/stratify_test.py +3 -0
  654. cirq/transformers/symbolize.py +103 -0
  655. cirq/transformers/symbolize_test.py +62 -0
  656. cirq/transformers/synchronize_terminal_measurements.py +10 -10
  657. cirq/transformers/synchronize_terminal_measurements_test.py +12 -10
  658. cirq/transformers/tag_transformers.py +97 -0
  659. cirq/transformers/tag_transformers_test.py +103 -0
  660. cirq/transformers/target_gatesets/compilation_target_gateset.py +21 -19
  661. cirq/transformers/target_gatesets/compilation_target_gateset_test.py +20 -16
  662. cirq/transformers/target_gatesets/cz_gateset.py +7 -5
  663. cirq/transformers/target_gatesets/cz_gateset_test.py +21 -19
  664. cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +9 -7
  665. cirq/transformers/target_gatesets/sqrt_iswap_gateset_test.py +25 -25
  666. cirq/transformers/transformer_api.py +34 -47
  667. cirq/transformers/transformer_api_test.py +9 -8
  668. cirq/transformers/transformer_primitives.py +39 -49
  669. cirq/transformers/transformer_primitives_test.py +10 -17
  670. cirq/value/abc_alt.py +6 -4
  671. cirq/value/abc_alt_test.py +5 -3
  672. cirq/value/angle.py +11 -12
  673. cirq/value/angle_test.py +5 -3
  674. cirq/value/classical_data.py +27 -27
  675. cirq/value/classical_data_test.py +11 -8
  676. cirq/value/condition.py +26 -24
  677. cirq/value/condition_test.py +2 -0
  678. cirq/value/digits.py +14 -11
  679. cirq/value/digits_test.py +2 -0
  680. cirq/value/duration.py +23 -20
  681. cirq/value/duration_test.py +2 -0
  682. cirq/value/linear_dict.py +25 -30
  683. cirq/value/linear_dict_test.py +10 -8
  684. cirq/value/measurement_key.py +12 -12
  685. cirq/value/measurement_key_test.py +2 -0
  686. cirq/value/periodic_value.py +4 -4
  687. cirq/value/periodic_value_test.py +11 -7
  688. cirq/value/probability.py +3 -1
  689. cirq/value/probability_test.py +4 -2
  690. cirq/value/product_state.py +15 -13
  691. cirq/value/product_state_test.py +4 -1
  692. cirq/value/random_state.py +2 -0
  693. cirq/value/random_state_test.py +5 -3
  694. cirq/value/timestamp.py +11 -7
  695. cirq/value/timestamp_test.py +14 -12
  696. cirq/value/type_alias.py +4 -4
  697. cirq/value/value_equality_attr.py +8 -9
  698. cirq/value/value_equality_attr_test.py +14 -11
  699. cirq/vis/density_matrix.py +3 -3
  700. cirq/vis/density_matrix_test.py +20 -17
  701. cirq/vis/heatmap.py +24 -37
  702. cirq/vis/heatmap_test.py +3 -0
  703. cirq/vis/histogram.py +9 -6
  704. cirq/vis/histogram_test.py +5 -2
  705. cirq/vis/state_histogram.py +10 -8
  706. cirq/vis/state_histogram_test.py +7 -5
  707. cirq/vis/vis_utils.py +4 -1
  708. cirq/vis/vis_utils_test.py +4 -1
  709. cirq/work/collector.py +12 -18
  710. cirq/work/collector_test.py +15 -10
  711. cirq/work/observable_grouping.py +6 -7
  712. cirq/work/observable_grouping_test.py +10 -9
  713. cirq/work/observable_measurement.py +47 -45
  714. cirq/work/observable_measurement_data.py +22 -17
  715. cirq/work/observable_measurement_data_test.py +4 -1
  716. cirq/work/observable_measurement_test.py +48 -29
  717. cirq/work/observable_readout_calibration.py +5 -2
  718. cirq/work/observable_readout_calibration_test.py +5 -2
  719. cirq/work/observable_settings.py +13 -22
  720. cirq/work/observable_settings_test.py +9 -7
  721. cirq/work/pauli_sum_collector.py +12 -10
  722. cirq/work/pauli_sum_collector_test.py +9 -9
  723. cirq/work/sampler.py +42 -43
  724. cirq/work/sampler_test.py +31 -24
  725. cirq/work/zeros_sampler.py +6 -4
  726. cirq/work/zeros_sampler_test.py +7 -5
  727. {cirq_core-1.5.0.dev20250409225226.dist-info → cirq_core-1.6.0.dist-info}/METADATA +7 -8
  728. cirq_core-1.6.0.dist-info/RECORD +1241 -0
  729. {cirq_core-1.5.0.dev20250409225226.dist-info → cirq_core-1.6.0.dist-info}/WHEEL +1 -1
  730. cirq_core-1.5.0.dev20250409225226.dist-info/RECORD +0 -1216
  731. {cirq_core-1.5.0.dev20250409225226.dist-info → cirq_core-1.6.0.dist-info}/licenses/LICENSE +0 -0
  732. {cirq_core-1.5.0.dev20250409225226.dist-info → cirq_core-1.6.0.dist-info}/top_level.txt +0 -0
@@ -12,9 +12,11 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  import itertools
16
18
  from collections import defaultdict
17
- from typing import Any, cast, Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union
19
+ from typing import Any, cast, Iterable, Sequence, TYPE_CHECKING
18
20
 
19
21
  import numpy as np
20
22
 
@@ -33,7 +35,7 @@ class _MeasurementQid(ops.Qid):
33
35
  Exactly one qubit will be created per qubit in the measurement gate.
34
36
  """
35
37
 
36
- def __init__(self, key: Union[str, 'cirq.MeasurementKey'], qid: 'cirq.Qid', index: int = 0):
38
+ def __init__(self, key: str | cirq.MeasurementKey, qid: cirq.Qid, index: int = 0):
37
39
  """Initializes the qubit.
38
40
 
39
41
  Args:
@@ -63,8 +65,8 @@ class _MeasurementQid(ops.Qid):
63
65
 
64
66
  @transformer_api.transformer
65
67
  def defer_measurements(
66
- circuit: 'cirq.AbstractCircuit', *, context: Optional['cirq.TransformerContext'] = None
67
- ) -> 'cirq.Circuit':
68
+ circuit: cirq.AbstractCircuit, *, context: cirq.TransformerContext | None = None
69
+ ) -> cirq.Circuit:
68
70
  """Implements the Deferred Measurement Principle.
69
71
 
70
72
  Uses the Deferred Measurement Principle to move all measurements to the
@@ -94,11 +96,9 @@ def defer_measurements(
94
96
 
95
97
  circuit = transformer_primitives.unroll_circuit_op(circuit, deep=True, tags_to_check=None)
96
98
  terminal_measurements = {op for _, op in find_terminal_measurements(circuit)}
97
- measurement_qubits: Dict['cirq.MeasurementKey', List[Tuple['cirq.Qid', ...]]] = defaultdict(
98
- list
99
- )
99
+ measurement_qubits: dict[cirq.MeasurementKey, list[tuple[cirq.Qid, ...]]] = defaultdict(list)
100
100
 
101
- def defer(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
101
+ def defer(op: cirq.Operation, _) -> cirq.OP_TREE:
102
102
  if op in terminal_measurements:
103
103
  return op
104
104
  gate = op.gate
@@ -169,10 +169,10 @@ def defer_measurements(
169
169
 
170
170
 
171
171
  def _all_possible_datastore_states(
172
- keys: Iterable[Tuple['cirq.MeasurementKey', int]],
173
- measurement_qubits: Dict['cirq.MeasurementKey', List[Tuple['cirq.Qid', ...]]],
174
- ) -> Iterable['cirq.ClassicalDataStoreReader']:
175
- """The cartesian product of all possible DataStore states for the given keys."""
172
+ keys: Iterable[tuple[cirq.MeasurementKey, int]],
173
+ measurement_qubits: dict[cirq.MeasurementKey, list[tuple[cirq.Qid, ...]]],
174
+ ) -> Iterable[cirq.ClassicalDataStoreReader]:
175
+ """The Cartesian product of all possible DataStore states for the given keys."""
176
176
  # First we get the list of all possible values. So if we have a key mapped to qubits of shape
177
177
  # (2, 2) and a key mapped to a qutrit, the possible measurement values are:
178
178
  # [((0, 0), (0,)),
@@ -214,10 +214,10 @@ def _all_possible_datastore_states(
214
214
 
215
215
  @transformer_api.transformer
216
216
  def dephase_measurements(
217
- circuit: 'cirq.AbstractCircuit',
217
+ circuit: cirq.AbstractCircuit,
218
218
  *,
219
- context: Optional['cirq.TransformerContext'] = transformer_api.TransformerContext(deep=True),
220
- ) -> 'cirq.Circuit':
219
+ context: cirq.TransformerContext | None = transformer_api.TransformerContext(deep=True),
220
+ ) -> cirq.Circuit:
221
221
  """Changes all measurements to a dephase operation.
222
222
 
223
223
  This transformer is useful when using a density matrix simulator, when
@@ -240,7 +240,7 @@ def dephase_measurements(
240
240
  surprises.
241
241
  """
242
242
 
243
- def dephase(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
243
+ def dephase(op: cirq.Operation, _) -> cirq.OP_TREE:
244
244
  gate = op.gate
245
245
  if isinstance(gate, ops.MeasurementGate):
246
246
  key = value.MeasurementKey.parse_serialized(gate.key)
@@ -257,10 +257,10 @@ def dephase_measurements(
257
257
 
258
258
  @transformer_api.transformer
259
259
  def drop_terminal_measurements(
260
- circuit: 'cirq.AbstractCircuit',
260
+ circuit: cirq.AbstractCircuit,
261
261
  *,
262
- context: Optional['cirq.TransformerContext'] = transformer_api.TransformerContext(deep=True),
263
- ) -> 'cirq.Circuit':
262
+ context: cirq.TransformerContext | None = transformer_api.TransformerContext(deep=True),
263
+ ) -> cirq.Circuit:
264
264
  """Removes terminal measurements from a circuit.
265
265
 
266
266
  This transformer is helpful when trying to capture the final state vector
@@ -289,7 +289,7 @@ def drop_terminal_measurements(
289
289
  if not circuit.are_all_measurements_terminal():
290
290
  raise ValueError('Circuit contains a non-terminal measurement.')
291
291
 
292
- def flip_inversion(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
292
+ def flip_inversion(op: cirq.Operation, _) -> cirq.OP_TREE:
293
293
  if isinstance(op.gate, ops.MeasurementGate):
294
294
  return [
295
295
  (
@@ -426,20 +426,20 @@ class _ConfusionChannel(ops.Gate):
426
426
  self._confusion_map = confusion_map.copy()
427
427
  self._kraus = tuple(kraus)
428
428
 
429
- def _qid_shape_(self) -> Tuple[int, ...]:
429
+ def _qid_shape_(self) -> tuple[int, ...]:
430
430
  return self._shape
431
431
 
432
- def _kraus_(self) -> Tuple[np.ndarray, ...]:
432
+ def _kraus_(self) -> tuple[np.ndarray, ...]:
433
433
  return self._kraus
434
434
 
435
- def _apply_channel_(self, args: 'cirq.ApplyChannelArgs'):
436
- configs: List[transformations._BuildFromSlicesArgs] = []
435
+ def _apply_channel_(self, args: cirq.ApplyChannelArgs):
436
+ configs: list[transformations._BuildFromSlicesArgs] = []
437
437
  for i in range(np.prod(self._shape) ** 2):
438
438
  scale = cast(complex, self._confusion_map.flat[i])
439
439
  if scale == 0:
440
440
  continue
441
441
  index: Any = np.unravel_index(i, self._shape * 2)
442
- slices: List[transformations._SliceConfig] = []
442
+ slices: list[transformations._SliceConfig] = []
443
443
  axis_count = len(args.left_axes)
444
444
  for j in range(axis_count):
445
445
  s1 = transformations._SliceConfig(
@@ -469,20 +469,20 @@ class _ModAdd(ops.ArithmeticGate):
469
469
  def __init__(self, dimension: int):
470
470
  self._dimension = dimension
471
471
 
472
- def registers(self) -> Tuple[Tuple[int], Tuple[int]]:
472
+ def registers(self) -> tuple[tuple[int], tuple[int]]:
473
473
  return (self._dimension,), (self._dimension,)
474
474
 
475
- def with_registers(self, *new_registers) -> '_ModAdd':
475
+ def with_registers(self, *new_registers) -> _ModAdd:
476
476
  raise NotImplementedError()
477
477
 
478
- def apply(self, *register_values: int) -> Tuple[int, int]:
478
+ def apply(self, *register_values: int) -> tuple[int, int]:
479
479
  return register_values[0], sum(register_values)
480
480
 
481
481
  def _value_equality_values_(self) -> int:
482
482
  return self._dimension
483
483
 
484
484
 
485
- def _mod_add(source: 'cirq.Qid', target: 'cirq.Qid') -> 'cirq.Operation':
485
+ def _mod_add(source: cirq.Qid, target: cirq.Qid) -> cirq.Operation:
486
486
  assert source.dimension == target.dimension
487
487
  if source.dimension == 2:
488
488
  # Use a CX gate in 2D case for simplicity.
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  import numpy as np
16
18
  import pytest
17
19
  import sympy
@@ -14,7 +14,9 @@
14
14
 
15
15
  """Transformer pass to merge connected components of k-qubit unitary operations."""
16
16
 
17
- from typing import Callable, cast, Optional, TYPE_CHECKING
17
+ from __future__ import annotations
18
+
19
+ from typing import Callable, cast, TYPE_CHECKING
18
20
 
19
21
  from cirq import circuits, ops, protocols
20
22
  from cirq.transformers import transformer_api, transformer_primitives
@@ -24,16 +26,16 @@ if TYPE_CHECKING:
24
26
 
25
27
 
26
28
  def _rewrite_merged_k_qubit_unitaries(
27
- circuit: 'cirq.AbstractCircuit',
29
+ circuit: cirq.AbstractCircuit,
28
30
  *,
29
- context: Optional['cirq.TransformerContext'] = None,
31
+ context: cirq.TransformerContext | None = None,
30
32
  k: int = 0,
31
- rewriter: Optional[Callable[['cirq.CircuitOperation'], 'cirq.OP_TREE']] = None,
33
+ rewriter: Callable[[cirq.CircuitOperation], cirq.OP_TREE] | None = None,
32
34
  merged_circuit_op_tag: str = "_merged_k_qubit_unitaries_component",
33
- ) -> 'cirq.Circuit':
35
+ ) -> cirq.Circuit:
34
36
  deep = context.deep if context else False
35
37
 
36
- def map_func(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
38
+ def map_func(op: cirq.Operation, _) -> cirq.OP_TREE:
37
39
  op_untagged = op.untagged
38
40
  if (
39
41
  deep
@@ -66,12 +68,12 @@ def _rewrite_merged_k_qubit_unitaries(
66
68
 
67
69
  @transformer_api.transformer
68
70
  def merge_k_qubit_unitaries(
69
- circuit: 'cirq.AbstractCircuit',
71
+ circuit: cirq.AbstractCircuit,
70
72
  *,
71
- context: Optional['cirq.TransformerContext'] = None,
73
+ context: cirq.TransformerContext | None = None,
72
74
  k: int = 0,
73
- rewriter: Optional[Callable[['cirq.CircuitOperation'], 'cirq.OP_TREE']] = None,
74
- ) -> 'cirq.Circuit':
75
+ rewriter: Callable[[cirq.CircuitOperation], cirq.OP_TREE] | None = None,
76
+ ) -> cirq.Circuit:
75
77
  """Merges connected components of unitary operations, acting on <= k qubits.
76
78
 
77
79
  Uses rewriter to convert a connected component of unitary operations acting on <= k-qubits
@@ -12,9 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- # pylint: skip-file
16
-
17
- from typing import List
15
+ from __future__ import annotations
18
16
 
19
17
  import numpy as np
20
18
  import pytest
@@ -24,7 +22,7 @@ import cirq
24
22
 
25
23
  def assert_optimizes(optimized: cirq.AbstractCircuit, expected: cirq.AbstractCircuit):
26
24
  # Ignore differences that would be caught by follow-up optimizations.
27
- followup_transformers: List[cirq.TRANSFORMER] = [
25
+ followup_transformers: list[cirq.TRANSFORMER] = [
28
26
  cirq.drop_negligible_operations,
29
27
  cirq.drop_empty_moments,
30
28
  ]
@@ -35,7 +33,7 @@ def assert_optimizes(optimized: cirq.AbstractCircuit, expected: cirq.AbstractCir
35
33
  cirq.testing.assert_same_circuits(optimized, expected)
36
34
 
37
35
 
38
- def test_merge_1q_unitaries():
36
+ def test_merge_1q_unitaries() -> None:
39
37
  q, q2 = cirq.LineQubit.range(2)
40
38
  # 1. Combines trivial 1q sequence.
41
39
  c = cirq.Circuit(cirq.X(q) ** 0.5, cirq.Z(q) ** 0.5, cirq.X(q) ** -0.5)
@@ -55,7 +53,7 @@ def test_merge_1q_unitaries():
55
53
  assert isinstance(c[-1][q].gate, cirq.MatrixGate)
56
54
 
57
55
 
58
- def test_respects_nocompile_tags():
56
+ def test_respects_nocompile_tags() -> None:
59
57
  q = cirq.NamedQubit("q")
60
58
  c = cirq.Circuit(
61
59
  [cirq.Z(q), cirq.H(q), cirq.X(q), cirq.H(q), cirq.X(q).with_tags("nocompile"), cirq.H(q)]
@@ -68,12 +66,12 @@ def test_respects_nocompile_tags():
68
66
  assert isinstance(c[-1][q].gate, cirq.MatrixGate)
69
67
 
70
68
 
71
- def test_ignores_2qubit_target():
69
+ def test_ignores_2qubit_target() -> None:
72
70
  c = cirq.Circuit(cirq.CZ(*cirq.LineQubit.range(2)))
73
71
  assert_optimizes(optimized=cirq.merge_k_qubit_unitaries(c, k=1), expected=c)
74
72
 
75
73
 
76
- def test_ignore_unsupported_gate():
74
+ def test_ignore_unsupported_gate() -> None:
77
75
  class UnsupportedExample(cirq.testing.SingleQubitGate):
78
76
  pass
79
77
 
@@ -81,7 +79,7 @@ def test_ignore_unsupported_gate():
81
79
  assert_optimizes(optimized=cirq.merge_k_qubit_unitaries(c, k=1), expected=c)
82
80
 
83
81
 
84
- def test_1q_rewrite():
82
+ def test_1q_rewrite() -> None:
85
83
  q0, q1 = cirq.LineQubit.range(2)
86
84
  circuit = cirq.Circuit(
87
85
  cirq.X(q0), cirq.Y(q0), cirq.X(q1), cirq.CZ(q0, q1), cirq.Y(q1), cirq.measure(q0, q1)
@@ -96,12 +94,12 @@ def test_1q_rewrite():
96
94
  )
97
95
 
98
96
 
99
- def test_merge_k_qubit_unitaries_raises():
97
+ def test_merge_k_qubit_unitaries_raises() -> None:
100
98
  with pytest.raises(ValueError, match="k should be greater than or equal to 1"):
101
99
  _ = cirq.merge_k_qubit_unitaries(cirq.Circuit())
102
100
 
103
101
 
104
- def test_merge_complex_circuit_preserving_moment_structure():
102
+ def test_merge_complex_circuit_preserving_moment_structure() -> None:
105
103
  q = cirq.LineQubit.range(3)
106
104
  c_orig = cirq.Circuit(
107
105
  cirq.Moment(cirq.H.on_each(*q)),
@@ -133,7 +131,7 @@ a: ═════════════════════════
133
131
  )
134
132
  component_id = 0
135
133
 
136
- def rewriter_merge_to_circuit_op(op: 'cirq.CircuitOperation') -> 'cirq.OP_TREE':
134
+ def rewriter_merge_to_circuit_op(op: cirq.CircuitOperation) -> cirq.OP_TREE:
137
135
  nonlocal component_id
138
136
  component_id = component_id + 1
139
137
  return op.with_tags(f'{component_id}')
@@ -155,12 +153,13 @@ a: ═════════════════════════
155
153
  │ │ ║
156
154
  2: ───#2──────────────────────────────────────────────────────────────────X───────────[ 2: ───Z─── ][3]───M───────────────────────╫───
157
155
  ║ ║
158
- a: ═══════════════════════════════════════════════════════════════════════════════════════════════════════@═══════════════════════^═══''',
156
+ a: ═══════════════════════════════════════════════════════════════════════════════════════════════════════@═══════════════════════^═══
157
+ ''', # noqa: E501
159
158
  )
160
159
 
161
160
  component_id = 0
162
161
 
163
- def rewriter_replace_with_decomp(op: 'cirq.CircuitOperation') -> 'cirq.OP_TREE':
162
+ def rewriter_replace_with_decomp(op: cirq.CircuitOperation) -> cirq.OP_TREE:
164
163
  nonlocal component_id
165
164
  component_id = component_id + 1
166
165
  tag = f'{component_id}'
@@ -185,11 +184,12 @@ a: ═════════════════════════
185
184
  │ │ ║
186
185
  2: ───T[1]───iSwap^0.5───T[1]─────────────────────────────X───────────T[3]────────M─────────────────────────╫───
187
186
  ║ ║
188
- a: ═══════════════════════════════════════════════════════════════════════════════@═════════════════════════^═══''',
187
+ a: ═══════════════════════════════════════════════════════════════════════════════@═════════════════════════^═══
188
+ ''', # noqa: E501
189
189
  )
190
190
 
191
191
 
192
- def test_merge_k_qubit_unitaries_deep():
192
+ def test_merge_k_qubit_unitaries_deep() -> None:
193
193
  q = cirq.LineQubit.range(2)
194
194
  h_cz_y = [cirq.H(q[0]), cirq.CZ(*q), cirq.Y(q[1])]
195
195
  c_orig = cirq.Circuit(
@@ -220,7 +220,7 @@ def test_merge_k_qubit_unitaries_deep():
220
220
 
221
221
  component_id = 0
222
222
 
223
- def rewriter_merge_to_circuit_op(op: 'cirq.CircuitOperation') -> 'cirq.OP_TREE':
223
+ def rewriter_merge_to_circuit_op(op: cirq.CircuitOperation) -> cirq.OP_TREE:
224
224
  nonlocal component_id
225
225
  component_id = component_id + 1
226
226
  return op.with_tags(f'{component_id}')
@@ -251,7 +251,7 @@ def test_merge_k_qubit_unitaries_deep():
251
251
  cirq.testing.assert_same_circuits(c_new_matrix, c_expected_matrix)
252
252
 
253
253
 
254
- def test_merge_k_qubit_unitaries_deep_recurses_on_large_circuit_op():
254
+ def test_merge_k_qubit_unitaries_deep_recurses_on_large_circuit_op() -> None:
255
255
  q = cirq.LineQubit.range(2)
256
256
  c_orig = cirq.Circuit(
257
257
  cirq.CircuitOperation(cirq.FrozenCircuit(cirq.X(q[0]), cirq.H(q[0]), cirq.CNOT(*q)))
@@ -14,23 +14,36 @@
14
14
 
15
15
  """Transformer passes to combine adjacent single-qubit rotations."""
16
16
 
17
- from typing import Optional, TYPE_CHECKING
17
+ from __future__ import annotations
18
+
19
+ from typing import Callable, cast, Hashable, TYPE_CHECKING
18
20
 
19
21
  from cirq import circuits, ops, protocols
20
- from cirq.transformers import merge_k_qubit_gates, transformer_api, transformer_primitives
22
+ from cirq.study.resolver import ParamResolver
23
+ from cirq.study.sweeps import dict_to_zip_sweep, ListSweep, ProductOrZipSweepLike, Sweep, Zip
24
+ from cirq.transformers import (
25
+ align,
26
+ merge_k_qubit_gates,
27
+ symbolize,
28
+ tag_transformers,
29
+ transformer_api,
30
+ transformer_primitives,
31
+ )
21
32
  from cirq.transformers.analytical_decompositions import single_qubit_decompositions
22
33
 
23
34
  if TYPE_CHECKING:
35
+ import sympy
36
+
24
37
  import cirq
25
38
 
26
39
 
27
40
  @transformer_api.transformer
28
41
  def merge_single_qubit_gates_to_phased_x_and_z(
29
- circuit: 'cirq.AbstractCircuit',
42
+ circuit: cirq.AbstractCircuit,
30
43
  *,
31
- context: Optional['cirq.TransformerContext'] = None,
44
+ context: cirq.TransformerContext | None = None,
32
45
  atol: float = 1e-8,
33
- ) -> 'cirq.Circuit':
46
+ ) -> cirq.Circuit:
34
47
  """Replaces runs of single qubit rotations with `cirq.PhasedXPowGate` and `cirq.ZPowGate`.
35
48
 
36
49
  Specifically, any run of non-parameterized single-qubit unitaries will be replaced by an
@@ -46,7 +59,7 @@ def merge_single_qubit_gates_to_phased_x_and_z(
46
59
  Copy of the transformed input circuit.
47
60
  """
48
61
 
49
- def rewriter(op: 'cirq.CircuitOperation') -> 'cirq.OP_TREE':
62
+ def rewriter(op: cirq.CircuitOperation) -> cirq.OP_TREE:
50
63
  u = protocols.unitary(op)
51
64
  if protocols.num_qubits(op) == 0:
52
65
  return ops.GlobalPhaseGate(u[0, 0]).on()
@@ -62,11 +75,12 @@ def merge_single_qubit_gates_to_phased_x_and_z(
62
75
 
63
76
  @transformer_api.transformer
64
77
  def merge_single_qubit_gates_to_phxz(
65
- circuit: 'cirq.AbstractCircuit',
78
+ circuit: cirq.AbstractCircuit,
66
79
  *,
67
- context: Optional['cirq.TransformerContext'] = None,
80
+ context: cirq.TransformerContext | None = None,
81
+ merge_tags_fn: Callable[[cirq.CircuitOperation], list[Hashable]] | None = None,
68
82
  atol: float = 1e-8,
69
- ) -> 'cirq.Circuit':
83
+ ) -> cirq.Circuit:
70
84
  """Replaces runs of single qubit rotations with a single optional `cirq.PhasedXZGate`.
71
85
 
72
86
  Specifically, any run of non-parameterized single-qubit unitaries will be replaced by an
@@ -75,6 +89,7 @@ def merge_single_qubit_gates_to_phxz(
75
89
  Args:
76
90
  circuit: Input circuit to transform. It will not be modified.
77
91
  context: `cirq.TransformerContext` storing common configurable options for transformers.
92
+ merge_tags_fn: A callable returns the tags to be added to the merged operation.
78
93
  atol: Absolute tolerance to angle error. Larger values allow more negligible gates to be
79
94
  dropped, smaller values increase accuracy.
80
95
 
@@ -82,12 +97,13 @@ def merge_single_qubit_gates_to_phxz(
82
97
  Copy of the transformed input circuit.
83
98
  """
84
99
 
85
- def rewriter(op: 'cirq.CircuitOperation') -> 'cirq.OP_TREE':
86
- u = protocols.unitary(op)
87
- if protocols.num_qubits(op) == 0:
100
+ def rewriter(circuit_op: cirq.CircuitOperation) -> cirq.OP_TREE:
101
+ u = protocols.unitary(circuit_op)
102
+ if protocols.num_qubits(circuit_op) == 0:
88
103
  return ops.GlobalPhaseGate(u[0, 0]).on()
89
- gate = single_qubit_decompositions.single_qubit_matrix_to_phxz(u, atol)
90
- return gate(op.qubits[0]) if gate else []
104
+ gate = single_qubit_decompositions.single_qubit_matrix_to_phxz(u, atol) or ops.I
105
+ phxz_op = gate.on(circuit_op.qubits[0])
106
+ return phxz_op.with_tags(*merge_tags_fn(circuit_op)) if merge_tags_fn else phxz_op
91
107
 
92
108
  return merge_k_qubit_gates.merge_k_qubit_unitaries(
93
109
  circuit, k=1, context=context, rewriter=rewriter
@@ -96,11 +112,11 @@ def merge_single_qubit_gates_to_phxz(
96
112
 
97
113
  @transformer_api.transformer
98
114
  def merge_single_qubit_moments_to_phxz(
99
- circuit: 'cirq.AbstractCircuit',
115
+ circuit: cirq.AbstractCircuit,
100
116
  *,
101
- context: Optional['cirq.TransformerContext'] = None,
117
+ context: cirq.TransformerContext | None = None,
102
118
  atol: float = 1e-8,
103
- ) -> 'cirq.Circuit':
119
+ ) -> cirq.Circuit:
104
120
  """Merges adjacent moments with only 1-qubit rotations to a single moment with PhasedXZ gates.
105
121
 
106
122
  Args:
@@ -114,15 +130,15 @@ def merge_single_qubit_moments_to_phxz(
114
130
  """
115
131
  tags_to_ignore = set(context.tags_to_ignore) if context else set()
116
132
 
117
- def can_merge_moment(m: 'cirq.Moment'):
133
+ def can_merge_moment(m: cirq.Moment):
118
134
  return all(
119
- protocols.num_qubits(op) == 1
135
+ protocols.num_qubits(op) <= 1
120
136
  and protocols.has_unitary(op)
121
137
  and tags_to_ignore.isdisjoint(op.tags)
122
138
  for op in m
123
139
  )
124
140
 
125
- def merge_func(m1: 'cirq.Moment', m2: 'cirq.Moment') -> Optional['cirq.Moment']:
141
+ def merge_func(m1: cirq.Moment, m2: cirq.Moment) -> cirq.Moment | None:
126
142
  if not (can_merge_moment(m1) and can_merge_moment(m2)):
127
143
  return None
128
144
  ret_ops = []
@@ -144,6 +160,10 @@ def merge_single_qubit_moments_to_phxz(
144
160
  )
145
161
  if gate:
146
162
  ret_ops.append(gate(q))
163
+ # Transfer global phase
164
+ for op in m1.operations + m2.operations:
165
+ if protocols.num_qubits(op) == 0:
166
+ ret_ops.append(op)
147
167
  return circuits.Moment(ret_ops)
148
168
 
149
169
  return transformer_primitives.merge_moments(
@@ -152,3 +172,160 @@ def merge_single_qubit_moments_to_phxz(
152
172
  deep=context.deep if context else False,
153
173
  tags_to_ignore=tuple(tags_to_ignore),
154
174
  ).unfreeze(copy=False)
175
+
176
+
177
+ def _sweep_on_symbols(sweep: Sweep, symbols: set[sympy.Symbol]) -> Sweep:
178
+ new_resolvers: list[cirq.ParamResolver] = []
179
+ for resolver in sweep:
180
+ param_dict: cirq.ParamMappingType = {s: resolver.value_of(s) for s in symbols}
181
+ new_resolvers.append(ParamResolver(param_dict))
182
+ return ListSweep(new_resolvers)
183
+
184
+
185
+ def _calc_phxz_sweeps(
186
+ symbolized_circuit: cirq.Circuit, resolved_circuits: list[cirq.Circuit]
187
+ ) -> Sweep:
188
+ """Returns the phxz sweep of the symbolized_circuit on resolved_circuits.
189
+
190
+ Raises:
191
+ ValueError: Structural mismatch: A `resolved_circuit` contains an unexpected gate type.
192
+ Expected a `PhasedXZGate` or `IdentityGate` at a position corresponding to a
193
+ symbolic `PhasedXZGate` in the `symbolized_circuit`.
194
+ """
195
+
196
+ def _extract_axz(op: ops.Operation | None) -> tuple[float, float, float]:
197
+ if not op or not op.gate or not isinstance(op.gate, ops.IdentityGate | ops.PhasedXZGate):
198
+ raise ValueError(f"Expect a PhasedXZGate or IdentityGate on op {op}.")
199
+ if isinstance(op.gate, ops.IdentityGate):
200
+ return 0.0, 0.0, 0.0 # Identity gate's a, x, z in PhasedXZ
201
+ return op.gate.axis_phase_exponent, op.gate.x_exponent, op.gate.z_exponent
202
+
203
+ values_by_params: dict[sympy.Symbol, tuple[float, ...]] = {}
204
+ for mid, moment in enumerate(symbolized_circuit):
205
+ for op in moment.operations:
206
+ if op.gate and isinstance(op.gate, ops.PhasedXZGate) and protocols.is_parameterized(op):
207
+ sa, sx, sz = op.gate.axis_phase_exponent, op.gate.x_exponent, op.gate.z_exponent
208
+ values_by_params[sa], values_by_params[sx], values_by_params[sz] = zip(
209
+ *[_extract_axz(c[mid].operation_at(op.qubits[0])) for c in resolved_circuits]
210
+ )
211
+
212
+ return dict_to_zip_sweep(cast(ProductOrZipSweepLike, values_by_params))
213
+
214
+
215
+ def merge_single_qubit_gates_to_phxz_symbolized(
216
+ circuit: cirq.AbstractCircuit,
217
+ *,
218
+ context: cirq.TransformerContext | None = None,
219
+ sweep: Sweep,
220
+ atol: float = 1e-8,
221
+ ) -> tuple[cirq.Circuit, Sweep]:
222
+ """Merges consecutive single qubit gates as PhasedXZ Gates. Symbolizes if any of
223
+ the consecutive gates is symbolized.
224
+
225
+ Example:
226
+ >>> q0, q1 = cirq.LineQubit.range(2)
227
+ >>> c = cirq.Circuit(\
228
+ cirq.X(q0),\
229
+ cirq.CZ(q0,q1)**sympy.Symbol("cz_exp"),\
230
+ cirq.Y(q0)**sympy.Symbol("y_exp"),\
231
+ cirq.X(q0))
232
+ >>> print(c)
233
+ 0: ───X───@──────────Y^y_exp───X───
234
+
235
+ 1: ───────@^cz_exp─────────────────
236
+ >>> new_circuit, new_sweep = cirq.merge_single_qubit_gates_to_phxz_symbolized(\
237
+ c, sweep=cirq.Zip(cirq.Points(key="cz_exp", points=[0, 1]),\
238
+ cirq.Points(key="y_exp", points=[0, 1])))
239
+ >>> print(new_circuit)
240
+ 0: ───PhXZ(a=-1,x=1,z=0)───@──────────PhXZ(a=a0,x=x0,z=z0)───
241
+
242
+ 1: ────────────────────────@^cz_exp──────────────────────────
243
+ >>> assert new_sweep[0] == cirq.ParamResolver({'a0': -1, 'x0': 1, 'z0': 0, 'cz_exp': 0})
244
+ >>> assert new_sweep[1] == cirq.ParamResolver({'a0': -0.5, 'x0': 0, 'z0': -1, 'cz_exp': 1})
245
+
246
+ Args:
247
+ circuit: Input circuit to transform. It will not be modified.
248
+ context: `cirq.TransformerContext` storing common configurable options for transformers.
249
+ sweep: Sweep of the symbols in the input circuit. An updated Sweep will be returned
250
+ based on the transformation.
251
+ atol: Absolute tolerance to angle error. Larger values allow more negligible gates to be
252
+ dropped, smaller values increase accuracy.
253
+
254
+ Returns:
255
+ Copy of the transformed input circuit.
256
+ """
257
+ deep = context.deep if context else False
258
+
259
+ # Tag symbolized single-qubit op.
260
+ symbolized_single_tag = "_tmp_symbolize_tag"
261
+
262
+ circuit_tagged = transformer_primitives.map_operations(
263
+ circuit,
264
+ lambda op, _: (
265
+ op.with_tags(symbolized_single_tag)
266
+ if protocols.is_parameterized(op) and len(op.qubits) == 1
267
+ else op
268
+ ),
269
+ deep=deep,
270
+ )
271
+
272
+ # Step 0, isolate single qubit symbols and resolve the circuit on them.
273
+ single_qubit_gate_symbols: set[sympy.Symbol] = set().union(
274
+ *[
275
+ protocols.parameter_symbols(op) if symbolized_single_tag in op.tags else set()
276
+ for op in circuit_tagged.all_operations()
277
+ ]
278
+ )
279
+ # Remaining symbols, e.g., 2 qubit gates' symbols. Sweep of those symbols keeps unchanged.
280
+ remaining_symbols: set[sympy.Symbol] = set(
281
+ protocols.parameter_symbols(circuit) - single_qubit_gate_symbols
282
+ )
283
+ # If all single qubit gates are not parameterized, call the non-parameterized version of
284
+ # the transformer.
285
+ if not single_qubit_gate_symbols:
286
+ return (merge_single_qubit_gates_to_phxz(circuit, context=context, atol=atol), sweep)
287
+ sweep_of_single: Sweep = _sweep_on_symbols(sweep, single_qubit_gate_symbols)
288
+ # Get all resolved circuits from all sets of resolvers in sweep_of_single.
289
+ resolved_circuits = [
290
+ protocols.resolve_parameters(circuit_tagged, resolver) for resolver in sweep_of_single
291
+ ]
292
+
293
+ # Step 1, merge single qubit gates per resolved circuit, preserving
294
+ # the symbolized_single_tag to indicate the operator is a merged one.
295
+ merged_circuits: list[cirq.Circuit] = [
296
+ merge_single_qubit_gates_to_phxz(
297
+ c,
298
+ context=context,
299
+ merge_tags_fn=lambda circuit_op: (
300
+ [symbolized_single_tag]
301
+ if any(
302
+ symbolized_single_tag in set(op.tags)
303
+ for op in circuit_op.circuit.all_operations()
304
+ )
305
+ else []
306
+ ),
307
+ atol=atol,
308
+ )
309
+ for c in resolved_circuits
310
+ ]
311
+
312
+ # Step 2, get the new symbolized circuit by symbolizing on indexed symbolized_single_tag.
313
+ new_circuit = tag_transformers.remove_tags( # remove the temp tags used to track merges
314
+ symbolize.symbolize_single_qubit_gates_by_indexed_tags(
315
+ tag_transformers.index_tags( # index all 1-qubit-ops merged from ops with symbols
316
+ merged_circuits[0],
317
+ context=transformer_api.TransformerContext(deep=deep),
318
+ target_tags={symbolized_single_tag},
319
+ ),
320
+ symbolize_tag=symbolize.SymbolizeTag(prefix=symbolized_single_tag),
321
+ ),
322
+ remove_if=lambda tag: str(tag).startswith(symbolized_single_tag),
323
+ )
324
+
325
+ # Step 3, get N sets of parameterizations as new_sweep.
326
+ new_sweep = Zip(
327
+ _calc_phxz_sweeps(new_circuit, merged_circuits), # phxz sweeps
328
+ _sweep_on_symbols(sweep, remaining_symbols), # remaining sweeps
329
+ )
330
+
331
+ return align.align_right(new_circuit), new_sweep