cirq-core 1.5.0.dev20250409222543__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.dev20250409222543.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.dev20250409222543.dist-info → cirq_core-1.6.0.dist-info}/WHEEL +1 -1
  730. cirq_core-1.5.0.dev20250409222543.dist-info/RECORD +0 -1216
  731. {cirq_core-1.5.0.dev20250409222543.dist-info → cirq_core-1.6.0.dist-info}/licenses/LICENSE +0 -0
  732. {cirq_core-1.5.0.dev20250409222543.dist-info → cirq_core-1.6.0.dist-info}/top_level.txt +0 -0
@@ -11,10 +11,13 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
14
17
  import abc
15
18
  import itertools
16
19
  from functools import cached_property
17
- from typing import Any, Collection, Dict, Iterator, Optional, Sequence, Tuple, TYPE_CHECKING, Union
20
+ from typing import Any, Collection, Iterator, Sequence, TYPE_CHECKING
18
21
 
19
22
  from cirq import protocols, value
20
23
 
@@ -47,7 +50,7 @@ class AbstractControlValues(abc.ABC):
47
50
  """Validates that all control values for ith qubit are in range [0, qid_shaped[i])"""
48
51
 
49
52
  @abc.abstractmethod
50
- def expand(self) -> 'SumOfProducts':
53
+ def expand(self) -> SumOfProducts:
51
54
  """Returns an expanded `cirq.SumOfProduct` representation of this control values."""
52
55
 
53
56
  @property
@@ -64,17 +67,15 @@ class AbstractControlValues(abc.ABC):
64
67
  """Returns the number of qubits for which control values are stored by this object."""
65
68
 
66
69
  @abc.abstractmethod
67
- def _json_dict_(self) -> Dict[str, Any]:
70
+ def _json_dict_(self) -> dict[str, Any]:
68
71
  """Returns a dictionary used for serializing this object."""
69
72
 
70
73
  @abc.abstractmethod
71
- def _circuit_diagram_info_(
72
- self, args: 'cirq.CircuitDiagramInfoArgs'
73
- ) -> 'cirq.CircuitDiagramInfo':
74
+ def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo:
74
75
  """Returns information used to draw this object in circuit diagrams."""
75
76
 
76
77
  @abc.abstractmethod
77
- def __iter__(self) -> Iterator[Tuple[int, ...]]:
78
+ def __iter__(self) -> Iterator[tuple[int, ...]]:
78
79
  """Iterator on internal representation of control values used by the derived classes.
79
80
 
80
81
  Note: Be careful that the terms iterated upon by this iterator will have different
@@ -88,7 +89,7 @@ class AbstractControlValues(abc.ABC):
88
89
  def _value_equality_values_(self) -> Any:
89
90
  return tuple(v for v in self.expand())
90
91
 
91
- def __and__(self, other: 'AbstractControlValues') -> 'AbstractControlValues':
92
+ def __and__(self, other: AbstractControlValues) -> AbstractControlValues:
92
93
  """Returns a cartesian product of all control values predicates in `self` x `other`.
93
94
 
94
95
  The `and` of two control values `cv1` and `cv2` represents a control value object
@@ -109,7 +110,7 @@ class AbstractControlValues(abc.ABC):
109
110
  tuple(x + y for (x, y) in itertools.product(self.expand(), other.expand()))
110
111
  )
111
112
 
112
- def __or__(self, other: 'AbstractControlValues') -> 'AbstractControlValues':
113
+ def __or__(self, other: AbstractControlValues) -> AbstractControlValues:
113
114
  """Returns a union of all control values predicates in `self` + `other`.
114
115
 
115
116
  Both `self` and `other` must represent control values for the same set of qubits and
@@ -140,8 +141,8 @@ class AbstractControlValues(abc.ABC):
140
141
  class ProductOfSums(AbstractControlValues):
141
142
  """Represents control values as N OR (sum) clauses, each of which applies to one qubit."""
142
143
 
143
- def __init__(self, data: Sequence[Union[int, Collection[int]]]):
144
- self._qubit_sums: Tuple[Tuple[int, ...], ...] = tuple(
144
+ def __init__(self, data: Sequence[int | Collection[int]]):
145
+ self._qubit_sums: tuple[tuple[int, ...], ...] = tuple(
145
146
  (cv,) if isinstance(cv, int) else tuple(sorted(set(cv))) for cv in data
146
147
  )
147
148
 
@@ -149,10 +150,10 @@ class ProductOfSums(AbstractControlValues):
149
150
  def is_trivial(self) -> bool:
150
151
  return self._qubit_sums == ((1,),) * self._num_qubits_()
151
152
 
152
- def __iter__(self) -> Iterator[Tuple[int, ...]]:
153
+ def __iter__(self) -> Iterator[tuple[int, ...]]:
153
154
  return iter(self._qubit_sums)
154
155
 
155
- def expand(self) -> 'SumOfProducts':
156
+ def expand(self) -> SumOfProducts:
156
157
  return SumOfProducts(tuple(itertools.product(*self._qubit_sums)))
157
158
 
158
159
  def __repr__(self) -> str:
@@ -161,7 +162,7 @@ class ProductOfSums(AbstractControlValues):
161
162
  def _num_qubits_(self) -> int:
162
163
  return len(self._qubit_sums)
163
164
 
164
- def __getitem__(self, key: Union[int, slice]) -> Union['ProductOfSums', Tuple[int, ...]]:
165
+ def __getitem__(self, key: int | slice) -> ProductOfSums | tuple[int, ...]:
165
166
  if isinstance(key, slice):
166
167
  return ProductOfSums(self._qubit_sums[key])
167
168
  return self._qubit_sums[key]
@@ -175,9 +176,7 @@ class ProductOfSums(AbstractControlValues):
175
176
  )
176
177
  raise ValueError(message)
177
178
 
178
- def _circuit_diagram_info_(
179
- self, args: 'cirq.CircuitDiagramInfoArgs'
180
- ) -> 'cirq.CircuitDiagramInfo':
179
+ def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo:
181
180
  """Returns a string representation to be used in circuit diagrams."""
182
181
 
183
182
  def get_symbol(vals):
@@ -195,7 +194,7 @@ class ProductOfSums(AbstractControlValues):
195
194
 
196
195
  return ''.join(get_prefix(t) for t in self._qubit_sums)
197
196
 
198
- def _json_dict_(self) -> Dict[str, Any]:
197
+ def _json_dict_(self) -> dict[str, Any]:
199
198
  return {"data": self._qubit_sums}
200
199
 
201
200
  def __and__(self, other: AbstractControlValues) -> AbstractControlValues:
@@ -242,8 +241,8 @@ class SumOfProducts(AbstractControlValues):
242
241
  >>> nand_cop = cirq.X(q2).controlled_by(q0, q1, control_values=nand_control_values)
243
242
  """
244
243
 
245
- def __init__(self, data: Collection[Sequence[int]], *, name: Optional[str] = None):
246
- self._conjunctions: Tuple[Tuple[int, ...], ...] = tuple(
244
+ def __init__(self, data: Collection[Sequence[int]], *, name: str | None = None):
245
+ self._conjunctions: tuple[tuple[int, ...], ...] = tuple(
247
246
  sorted(set(tuple(cv) for cv in data))
248
247
  )
249
248
  self._name = name
@@ -257,16 +256,14 @@ class SumOfProducts(AbstractControlValues):
257
256
  def is_trivial(self) -> bool:
258
257
  return self._conjunctions == ((1,) * self._num_qubits_(),)
259
258
 
260
- def expand(self) -> 'SumOfProducts':
259
+ def expand(self) -> SumOfProducts:
261
260
  return self
262
261
 
263
- def __iter__(self) -> Iterator[Tuple[int, ...]]:
262
+ def __iter__(self) -> Iterator[tuple[int, ...]]:
264
263
  """Returns the combinations tracked by the object."""
265
264
  return iter(self._conjunctions)
266
265
 
267
- def _circuit_diagram_info_(
268
- self, args: 'cirq.CircuitDiagramInfoArgs'
269
- ) -> 'cirq.CircuitDiagramInfo':
266
+ def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo:
270
267
  """Returns a string representation to be used in circuit diagrams."""
271
268
  if self._name is not None:
272
269
  wire_symbols = ['@'] * self._num_qubits_()
@@ -316,5 +313,5 @@ class SumOfProducts(AbstractControlValues):
316
313
  f' of range [0, {qid_shapes[q_i]}) for control qubit number <{q_i}>.'
317
314
  )
318
315
 
319
- def _json_dict_(self) -> Dict[str, Any]:
316
+ def _json_dict_(self) -> dict[str, Any]:
320
317
  return {'data': self._conjunctions, 'name': self._name}
@@ -12,12 +12,14 @@
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 pytest
16
18
 
17
19
  import cirq
18
20
 
19
21
 
20
- def test_init_sum_of_products_raises():
22
+ def test_init_sum_of_products_raises() -> None:
21
23
  # data shouldn't be empty.
22
24
  with pytest.raises(ValueError):
23
25
  _ = cirq.SumOfProducts([])
@@ -27,7 +29,7 @@ def test_init_sum_of_products_raises():
27
29
  _ = cirq.SumOfProducts([[1], [1, 0]])
28
30
 
29
31
 
30
- def test_init_product_of_sums():
32
+ def test_init_product_of_sums() -> None:
31
33
  eq = cirq.testing.EqualsTester()
32
34
  # 0. Trivial case of 1 control and 1 qubit.
33
35
  eq.add_equality_group(cirq.ProductOfSums([1]), cirq.ProductOfSums(((1,),)))
@@ -57,7 +59,7 @@ def test_init_product_of_sums():
57
59
  eq.add_equality_group([(1, 2), (0, 1)])
58
60
 
59
61
 
60
- def test_init_sum_of_products():
62
+ def test_init_sum_of_products() -> None:
61
63
  eq = cirq.testing.EqualsTester()
62
64
  # 0. Trivial case of 1 control and 1 qubit
63
65
  eq.add_equality_group(cirq.SumOfProducts([[1]]), cirq.SumOfProducts(((1,),)))
@@ -88,7 +90,7 @@ def test_init_sum_of_products():
88
90
  eq.add_equality_group(cirq.SumOfProducts([(1, 0), (2, 0), (1, 1), (2, 1)]))
89
91
 
90
92
 
91
- def test_equality_across_types():
93
+ def test_equality_across_types() -> None:
92
94
  eq = cirq.testing.EqualsTester()
93
95
  # Trivial case of 1 control and 1 qubit
94
96
  eq.add_equality_group(
@@ -122,7 +124,7 @@ def test_equality_across_types():
122
124
  eq.add_equality_group(cirq.ProductOfSums([(0, 1), (1, 0)])) # or control
123
125
 
124
126
 
125
- def test_and_operation():
127
+ def test_and_operation() -> None:
126
128
  eq = cirq.testing.EqualsTester()
127
129
 
128
130
  eq.add_equality_group(
@@ -169,12 +171,12 @@ def test_and_operation():
169
171
  [cirq.SumOfProducts([(0, 0), (1, 1)]), cirq.ProductOfSums([0, 1, 2]), cirq.SumOfProducts],
170
172
  ],
171
173
  )
172
- def test_and_operation_adds_qubits(cv1, cv2, expected_type):
174
+ def test_and_operation_adds_qubits(cv1, cv2, expected_type) -> None:
173
175
  assert isinstance(cv1 & cv2, expected_type)
174
176
  assert cirq.num_qubits(cv1 & cv2) == cirq.num_qubits(cv1) + cirq.num_qubits(cv2)
175
177
 
176
178
 
177
- def test_or_operation():
179
+ def test_or_operation() -> None:
178
180
  eq = cirq.testing.EqualsTester()
179
181
 
180
182
  eq.add_equality_group(
@@ -212,7 +214,7 @@ def test_or_operation():
212
214
  [cirq.SumOfProducts([[0], [1], [2]]), cirq.SumOfProducts([[1, 0]]), None],
213
215
  ],
214
216
  )
215
- def test_or_operation_acts_on_same_qubits(cv1, cv2, expected_type):
217
+ def test_or_operation_acts_on_same_qubits(cv1, cv2, expected_type) -> None:
216
218
  if cirq.num_qubits(cv1) == cirq.num_qubits(cv2):
217
219
  assert cirq.num_qubits(cv1 | cv2) == cirq.num_qubits(cv1)
218
220
  assert expected_type is not None
@@ -224,31 +226,31 @@ def test_or_operation_acts_on_same_qubits(cv1, cv2, expected_type):
224
226
 
225
227
 
226
228
  @pytest.mark.parametrize('data', [((1,),), ((0, 1), (1,)), [(0, 1), (1, 0)]])
227
- def test_product_of_sums_repr(data):
229
+ def test_product_of_sums_repr(data) -> None:
228
230
  cirq.testing.assert_equivalent_repr(cirq.ProductOfSums(data))
229
231
 
230
232
 
231
233
  @pytest.mark.parametrize('data', [((1,),), ((0, 1),), ((0, 0), (0, 1), (1, 0))])
232
- def test_sum_of_products_repr(data):
234
+ def test_sum_of_products_repr(data) -> None:
233
235
  cirq.testing.assert_equivalent_repr(cirq.SumOfProducts(data))
234
236
  cirq.testing.assert_equivalent_repr(cirq.SumOfProducts(data, name="CustomName"))
235
237
 
236
238
 
237
- def test_sum_of_products_validate():
239
+ def test_sum_of_products_validate() -> None:
238
240
  control_val = cirq.SumOfProducts(((1, 2), (0, 1)))
239
241
 
240
- _ = control_val.validate([2, 3])
242
+ control_val.validate([2, 3])
241
243
 
242
244
  with pytest.raises(ValueError):
243
- _ = control_val.validate([2, 2])
245
+ control_val.validate([2, 2])
244
246
 
245
247
  # number of qubits != number of control values.
246
248
  with pytest.raises(ValueError):
247
- _ = control_val.validate([2])
249
+ control_val.validate([2])
248
250
 
249
251
 
250
252
  @pytest.mark.parametrize('data', [((1,),), ((0, 1),), ((0, 0), (0, 1), (1, 0))])
251
- def test_sum_of_products_num_qubits(data):
253
+ def test_sum_of_products_num_qubits(data) -> None:
252
254
  assert cirq.num_qubits(cirq.SumOfProducts(data)) == len(data[0])
253
255
 
254
256
 
@@ -261,7 +263,7 @@ def test_sum_of_products_num_qubits(data):
261
263
  [((1, 1, 1, 1),), True],
262
264
  ],
263
265
  )
264
- def test_sum_of_products_is_trivial(data, is_trivial):
266
+ def test_sum_of_products_is_trivial(data, is_trivial) -> None:
265
267
  assert cirq.SumOfProducts(data).is_trivial == is_trivial
266
268
 
267
269
 
@@ -269,16 +271,16 @@ def test_sum_of_products_is_trivial(data, is_trivial):
269
271
  'data, is_trivial',
270
272
  [[((1,),), True], [((0, 1),), False], [([2], [1], [2]), False], [([1], [1], [1], [1]), True]],
271
273
  )
272
- def test_product_of_sum_is_trivial(data, is_trivial):
274
+ def test_product_of_sum_is_trivial(data, is_trivial) -> None:
273
275
  assert cirq.ProductOfSums(data).is_trivial == is_trivial
274
276
 
275
277
 
276
- def test_product_of_sums_str():
278
+ def test_product_of_sums_str() -> None:
277
279
  c = cirq.ProductOfSums([(0, 1), 1, 0, (0, 2)])
278
280
  assert str(c) == 'C01C1C0C02'
279
281
 
280
282
 
281
- def test_sum_of_products_str():
283
+ def test_sum_of_products_str() -> None:
282
284
  c = cirq.SumOfProducts(((1, 0), (0, 1)))
283
285
  assert str(c) == 'C_01_10'
284
286
 
@@ -286,7 +288,7 @@ def test_sum_of_products_str():
286
288
  assert str(c) == 'C_xor'
287
289
 
288
290
 
289
- def test_control_values_diagrams():
291
+ def test_control_values_diagrams() -> None:
290
292
  q = cirq.LineQubit.range(3)
291
293
  ccx = cirq.X(q[0]).controlled_by(*q[1:])
292
294
  ccx_sop = cirq.X(q[0]).controlled_by(*q[1:], control_values=cirq.SumOfProducts([[1, 1]]))
@@ -12,19 +12,10 @@
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
  from types import NotImplementedType
16
- from typing import (
17
- AbstractSet,
18
- Any,
19
- Collection,
20
- Dict,
21
- List,
22
- Optional,
23
- Sequence,
24
- Tuple,
25
- TYPE_CHECKING,
26
- Union,
27
- )
18
+ from typing import AbstractSet, Any, Collection, Sequence, TYPE_CHECKING
28
19
 
29
20
  import numpy as np
30
21
 
@@ -33,7 +24,6 @@ from cirq.ops import (
33
24
  control_values as cv,
34
25
  controlled_operation as cop,
35
26
  diagonal_gate as dg,
36
- global_phase_op as gp,
37
27
  op_tree,
38
28
  raw_types,
39
29
  )
@@ -57,12 +47,10 @@ class ControlledGate(raw_types.Gate):
57
47
 
58
48
  def __init__(
59
49
  self,
60
- sub_gate: 'cirq.Gate',
61
- num_controls: Optional[int] = None,
62
- control_values: Optional[
63
- Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
64
- ] = None,
65
- control_qid_shape: Optional[Sequence[int]] = None,
50
+ sub_gate: cirq.Gate,
51
+ num_controls: int | None = None,
52
+ control_values: cv.AbstractControlValues | Sequence[int | Collection[int]] | None = None,
53
+ control_qid_shape: Sequence[int] | None = None,
66
54
  ) -> None:
67
55
  """Initializes the controlled gate. If no arguments are specified for
68
56
  the controls, defaults to a single qubit control.
@@ -133,7 +121,7 @@ class ControlledGate(raw_types.Gate):
133
121
  self._sub_gate = sub_gate
134
122
 
135
123
  @property
136
- def control_qid_shape(self) -> Tuple[int, ...]:
124
+ def control_qid_shape(self) -> tuple[int, ...]:
137
125
  return self._control_qid_shape
138
126
 
139
127
  @property
@@ -141,102 +129,70 @@ class ControlledGate(raw_types.Gate):
141
129
  return self._control_values
142
130
 
143
131
  @property
144
- def sub_gate(self) -> 'cirq.Gate':
132
+ def sub_gate(self) -> cirq.Gate:
145
133
  return self._sub_gate
146
134
 
147
135
  def num_controls(self) -> int:
148
136
  return len(self.control_qid_shape)
149
137
 
150
- def _qid_shape_(self) -> Tuple[int, ...]:
138
+ def _qid_shape_(self) -> tuple[int, ...]:
151
139
  return self.control_qid_shape + protocols.qid_shape(self.sub_gate)
152
140
 
153
- def _decompose_(
154
- self, qubits: Tuple['cirq.Qid', ...]
155
- ) -> Union[None, NotImplementedType, 'cirq.OP_TREE']:
156
- return self._decompose_with_context_(qubits)
157
-
158
141
  def _decompose_with_context_(
159
- self, qubits: Tuple['cirq.Qid', ...], context: Optional['cirq.DecompositionContext'] = None
160
- ) -> Union[None, NotImplementedType, 'cirq.OP_TREE']:
142
+ self, qubits: tuple[cirq.Qid, ...], context: cirq.DecompositionContext
143
+ ) -> NotImplementedType | cirq.OP_TREE:
161
144
  control_qubits = list(qubits[: self.num_controls()])
162
- if (
163
- protocols.has_unitary(self.sub_gate)
164
- and protocols.num_qubits(self.sub_gate) == 1
165
- and self._qid_shape_() == (2,) * len(self._qid_shape_())
166
- and isinstance(self.control_values, cv.ProductOfSums)
167
- ):
168
- invert_ops: List['cirq.Operation'] = []
169
- for cvals, cqbit in zip(self.control_values, qubits[: self.num_controls()]):
170
- if set(cvals) == {0}:
171
- invert_ops.append(common_gates.X(cqbit))
172
- elif set(cvals) == {0, 1}:
173
- control_qubits.remove(cqbit)
174
- decomposed_ops = controlled_gate_decomposition.decompose_multi_controlled_rotation(
175
- protocols.unitary(self.sub_gate), control_qubits, qubits[-1]
176
- )
177
- return invert_ops + decomposed_ops + invert_ops
178
- if isinstance(self.sub_gate, gp.GlobalPhaseGate):
179
- # A controlled global phase is a diagonal gate, where each active control value index
180
- # is set equal to the phase angle.
181
- shape = self.control_qid_shape
182
- if protocols.is_parameterized(self.sub_gate) or set(shape) != {2}:
183
- # Could work in theory, but DiagonalGate decompose does not support them.
184
- return NotImplemented
185
- angle = np.angle(complex(self.sub_gate.coefficient))
186
- rads = np.zeros(shape=shape)
187
- for hot in self.control_values.expand():
188
- rads[hot] = angle
189
- return dg.DiagonalGate(diag_angles_radians=[*rads.flatten()]).on(*qubits)
190
- if isinstance(self.sub_gate, common_gates.CZPowGate):
191
- z_sub_gate = common_gates.ZPowGate(exponent=self.sub_gate.exponent)
192
- num_controls = self.num_controls() + 1
193
- control_values = self.control_values & cv.ProductOfSums(((1,),))
194
- control_qid_shape = self.control_qid_shape + (2,)
195
- controlled_z = (
196
- z_sub_gate.controlled(
197
- num_controls=num_controls,
198
- control_values=control_values,
199
- control_qid_shape=control_qid_shape,
200
- )
201
- if protocols.is_parameterized(self)
202
- else ControlledGate(
203
- z_sub_gate,
204
- num_controls=num_controls,
205
- control_values=control_values,
206
- control_qid_shape=control_qid_shape,
207
- )
208
- )
209
- if self != controlled_z:
210
- result = controlled_z.on(*qubits)
211
- if self.sub_gate.global_shift == 0:
212
- return result
213
- # Reconstruct the controlled global shift of the subgate.
214
- total_shift = self.sub_gate.exponent * self.sub_gate.global_shift
215
- phase_gate = gp.GlobalPhaseGate(1j ** (2 * total_shift))
216
- controlled_phase_op = phase_gate.controlled(
217
- num_controls=self.num_controls(),
218
- control_values=self.control_values,
219
- control_qid_shape=self.control_qid_shape,
220
- ).on(*control_qubits)
221
- return [result, controlled_phase_op]
145
+ controlled_sub_gate = self.sub_gate.controlled(
146
+ self.num_controls(), self.control_values, self.control_qid_shape
147
+ )
148
+ # Prefer the subgate controlled version if available
149
+ if self != controlled_sub_gate:
150
+ return controlled_sub_gate.on(*qubits)
151
+
152
+ # Try decomposing the subgate next.
222
153
  result = protocols.decompose_once_with_qubits(
223
154
  self.sub_gate,
224
155
  qubits[self.num_controls() :],
225
156
  NotImplemented,
226
157
  flatten=False,
227
- context=context,
158
+ # Extract global phases from decomposition, as controlled phases decompose easily.
159
+ context=context.extracting_global_phases(),
228
160
  )
229
- if result is NotImplemented:
230
- return NotImplemented
161
+ if result is not NotImplemented:
162
+ return op_tree.transform_op_tree(
163
+ result,
164
+ lambda op: op.controlled_by(
165
+ *qubits[: self.num_controls()], control_values=self.control_values
166
+ ),
167
+ )
231
168
 
232
- return op_tree.transform_op_tree(
233
- result,
234
- lambda op: op.controlled_by(
235
- *qubits[: self.num_controls()], control_values=self.control_values
236
- ),
237
- )
169
+ # Finally try brute-force on the unitary.
170
+ if protocols.has_unitary(self.sub_gate) and all(q.dimension == 2 for q in qubits):
171
+ n_qubits = protocols.num_qubits(self.sub_gate)
172
+ # Case 1: Global Phase (1x1 Matrix)
173
+ if n_qubits == 0:
174
+ angle = np.angle(protocols.unitary(self.sub_gate)[0, 0])
175
+ rads = np.zeros(shape=self.control_qid_shape)
176
+ for hot in self.control_values.expand():
177
+ rads[hot] = angle
178
+ return dg.DiagonalGate(diag_angles_radians=[*rads.flatten()]).on(*qubits)
179
+ # Case 2: Multi-controlled single-qubit gate decomposition
180
+ if n_qubits == 1 and isinstance(self.control_values, cv.ProductOfSums):
181
+ invert_ops: list[cirq.Operation] = []
182
+ for cvals, cqbit in zip(self.control_values, qubits[: self.num_controls()]):
183
+ if set(cvals) == {0}:
184
+ invert_ops.append(common_gates.X(cqbit))
185
+ elif set(cvals) == {0, 1}:
186
+ control_qubits.remove(cqbit)
187
+ decomposed_ops = controlled_gate_decomposition.decompose_multi_controlled_rotation(
188
+ protocols.unitary(self.sub_gate), control_qubits, qubits[-1]
189
+ )
190
+ return invert_ops + decomposed_ops + invert_ops
191
+
192
+ # If nothing works, return `NotImplemented`.
193
+ return NotImplemented
238
194
 
239
- def on(self, *qubits: 'cirq.Qid') -> cop.ControlledOperation:
195
+ def on(self, *qubits: cirq.Qid) -> cop.ControlledOperation:
240
196
  if len(qubits) == 0:
241
197
  raise ValueError(f"Applied a gate to an empty set of qubits. Gate: {self!r}")
242
198
  self.validate_args(qubits)
@@ -249,7 +205,7 @@ class ControlledGate(raw_types.Gate):
249
205
  def _value_equality_values_(self):
250
206
  return (self.sub_gate, self.num_controls(), self.control_values, self.control_qid_shape)
251
207
 
252
- def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> np.ndarray:
208
+ def _apply_unitary_(self, args: protocols.ApplyUnitaryArgs) -> np.ndarray:
253
209
  qubits = line_qubit.LineQid.for_gate(self)
254
210
  op = self.sub_gate.on(*qubits[self.num_controls() :])
255
211
  c_op = cop.ControlledOperation(qubits[: self.num_controls()], op, self.control_values)
@@ -258,7 +214,7 @@ class ControlledGate(raw_types.Gate):
258
214
  def _has_unitary_(self) -> bool:
259
215
  return protocols.has_unitary(self.sub_gate)
260
216
 
261
- def _unitary_(self) -> Union[np.ndarray, NotImplementedType]:
217
+ def _unitary_(self) -> np.ndarray | NotImplementedType:
262
218
  qubits = line_qubit.LineQid.for_gate(self)
263
219
  op = self.sub_gate.on(*qubits[self.num_controls() :])
264
220
  c_op = cop.ControlledOperation(qubits[: self.num_controls()], op, self.control_values)
@@ -268,13 +224,13 @@ class ControlledGate(raw_types.Gate):
268
224
  def _has_mixture_(self) -> bool:
269
225
  return protocols.has_mixture(self.sub_gate)
270
226
 
271
- def _mixture_(self) -> Union[Sequence[tuple[float, np.ndarray]], NotImplementedType]:
227
+ def _mixture_(self) -> Sequence[tuple[float, np.ndarray]] | NotImplementedType:
272
228
  qubits = line_qubit.LineQid.for_gate(self)
273
229
  op = self.sub_gate.on(*qubits[self.num_controls() :])
274
230
  c_op = cop.ControlledOperation(qubits[: self.num_controls()], op, self.control_values)
275
231
  return protocols.mixture(c_op, default=NotImplemented)
276
232
 
277
- def __pow__(self, exponent: Any) -> 'ControlledGate':
233
+ def __pow__(self, exponent: Any) -> ControlledGate:
278
234
  new_sub_gate = protocols.pow(self.sub_gate, exponent, NotImplemented)
279
235
  if new_sub_gate is NotImplemented:
280
236
  return NotImplemented
@@ -291,9 +247,7 @@ class ControlledGate(raw_types.Gate):
291
247
  def _parameter_names_(self) -> AbstractSet[str]:
292
248
  return protocols.parameter_names(self.sub_gate)
293
249
 
294
- def _resolve_parameters_(
295
- self, resolver: 'cirq.ParamResolver', recursive: bool
296
- ) -> 'ControlledGate':
250
+ def _resolve_parameters_(self, resolver: cirq.ParamResolver, recursive: bool) -> ControlledGate:
297
251
  new_sub_gate = protocols.resolve_parameters(self.sub_gate, resolver, recursive)
298
252
  return ControlledGate(
299
253
  new_sub_gate,
@@ -302,7 +256,7 @@ class ControlledGate(raw_types.Gate):
302
256
  control_qid_shape=self.control_qid_shape,
303
257
  )
304
258
 
305
- def _trace_distance_bound_(self) -> Optional[float]:
259
+ def _trace_distance_bound_(self) -> float | None:
306
260
  if self._is_parameterized_():
307
261
  return None
308
262
  u = protocols.unitary(self.sub_gate, default=None)
@@ -311,9 +265,7 @@ class ControlledGate(raw_types.Gate):
311
265
  angle_list = np.append(np.angle(np.linalg.eigvals(u)), 0)
312
266
  return protocols.trace_distance_from_angle_list(angle_list)
313
267
 
314
- def _circuit_diagram_info_(
315
- self, args: 'cirq.CircuitDiagramInfoArgs'
316
- ) -> 'cirq.CircuitDiagramInfo':
268
+ def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo:
317
269
  sub_args = protocols.CircuitDiagramInfoArgs(
318
270
  known_qubit_count=(
319
271
  args.known_qubit_count - self.num_controls()
@@ -355,7 +307,7 @@ class ControlledGate(raw_types.Gate):
355
307
  f'control_qid_shape={self.control_qid_shape!r})'
356
308
  )
357
309
 
358
- def _json_dict_(self) -> Dict[str, Any]:
310
+ def _json_dict_(self) -> dict[str, Any]:
359
311
  return {
360
312
  'control_values': self.control_values,
361
313
  'control_qid_shape': self.control_qid_shape,
@@ -363,7 +315,7 @@ class ControlledGate(raw_types.Gate):
363
315
  }
364
316
 
365
317
 
366
- def _validate_sub_object(sub_object: Union['cirq.Gate', 'cirq.Operation']):
318
+ def _validate_sub_object(sub_object: cirq.Gate | cirq.Operation):
367
319
  if protocols.is_measurement(sub_object):
368
320
  raise ValueError(f'Cannot control measurement {sub_object}')
369
321
  if not protocols.has_mixture(sub_object) and not protocols.is_parameterized(sub_object):