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
@@ -12,27 +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 numbers
16
18
  from collections import defaultdict
17
- from typing import (
18
- AbstractSet,
19
- Any,
20
- DefaultDict,
21
- Dict,
22
- FrozenSet,
23
- Iterable,
24
- List,
25
- Mapping,
26
- Optional,
27
- Tuple,
28
- TYPE_CHECKING,
29
- Union,
30
- )
19
+ from typing import AbstractSet, Any, Iterable, Mapping, TYPE_CHECKING, Union
31
20
 
32
21
  import numpy as np
33
- from scipy.sparse import csr_matrix
34
- from sympy.core.expr import Expr
35
- from sympy.core.symbol import Symbol
22
+ import sympy
36
23
  from sympy.logic.boolalg import And, Not, Or, Xor
37
24
 
38
25
  from cirq import linalg, protocols, qis, value
@@ -44,9 +31,11 @@ from cirq.ops.projector import ProjectorString
44
31
  from cirq.value.linear_dict import _format_terms
45
32
 
46
33
  if TYPE_CHECKING:
34
+ from scipy.sparse import csr_matrix
35
+
47
36
  import cirq
48
37
 
49
- UnitPauliStringT = FrozenSet[Tuple[raw_types.Qid, pauli_gates.Pauli]]
38
+ UnitPauliStringT = frozenset[tuple[raw_types.Qid, pauli_gates.Pauli]]
50
39
  PauliSumLike = Union[
51
40
  complex, PauliString, 'PauliSum', pauli_string.SingleQubitPauliStringGateOperation
52
41
  ]
@@ -81,7 +70,7 @@ class LinearCombinationOfGates(value.LinearDict[raw_types.Gate]):
81
70
  2 * cirq.X - 2 * cirq.Z
82
71
  """
83
72
 
84
- def __init__(self, terms: Mapping[raw_types.Gate, 'cirq.TParamValComplex']) -> None:
73
+ def __init__(self, terms: Mapping[raw_types.Gate, cirq.TParamValComplex]) -> None:
85
74
  """Initializes linear combination from a collection of terms.
86
75
 
87
76
  Args:
@@ -90,45 +79,41 @@ class LinearCombinationOfGates(value.LinearDict[raw_types.Gate]):
90
79
  """
91
80
  super().__init__(terms, validator=self._is_compatible)
92
81
 
93
- def num_qubits(self) -> Optional[int]:
82
+ def num_qubits(self) -> int | None:
94
83
  """Returns number of qubits in the domain if known, None if unknown."""
95
84
  if not self:
96
85
  return None
97
86
  any_gate = next(iter(self))
98
87
  return any_gate.num_qubits()
99
88
 
100
- def _is_compatible(self, gate: 'cirq.Gate') -> bool:
89
+ def _is_compatible(self, gate: cirq.Gate) -> bool:
101
90
  return self.num_qubits() is None or self.num_qubits() == gate.num_qubits()
102
91
 
103
- def __add__(
104
- self, other: Union[raw_types.Gate, 'LinearCombinationOfGates']
105
- ) -> 'LinearCombinationOfGates':
92
+ def __add__(self, other: raw_types.Gate | LinearCombinationOfGates) -> LinearCombinationOfGates:
106
93
  if not isinstance(other, LinearCombinationOfGates):
107
94
  other = other.wrap_in_linear_combination()
108
95
  return super().__add__(other)
109
96
 
110
97
  def __iadd__(
111
- self, other: Union[raw_types.Gate, 'LinearCombinationOfGates']
112
- ) -> 'LinearCombinationOfGates':
98
+ self, other: raw_types.Gate | LinearCombinationOfGates
99
+ ) -> LinearCombinationOfGates:
113
100
  if not isinstance(other, LinearCombinationOfGates):
114
101
  other = other.wrap_in_linear_combination()
115
102
  return super().__iadd__(other)
116
103
 
117
- def __sub__(
118
- self, other: Union[raw_types.Gate, 'LinearCombinationOfGates']
119
- ) -> 'LinearCombinationOfGates':
104
+ def __sub__(self, other: raw_types.Gate | LinearCombinationOfGates) -> LinearCombinationOfGates:
120
105
  if not isinstance(other, LinearCombinationOfGates):
121
106
  other = other.wrap_in_linear_combination()
122
107
  return super().__sub__(other)
123
108
 
124
109
  def __isub__(
125
- self, other: Union[raw_types.Gate, 'LinearCombinationOfGates']
126
- ) -> 'LinearCombinationOfGates':
110
+ self, other: raw_types.Gate | LinearCombinationOfGates
111
+ ) -> LinearCombinationOfGates:
127
112
  if not isinstance(other, LinearCombinationOfGates):
128
113
  other = other.wrap_in_linear_combination()
129
114
  return super().__isub__(other)
130
115
 
131
- def __pow__(self, exponent: int) -> 'LinearCombinationOfGates':
116
+ def __pow__(self, exponent: int) -> LinearCombinationOfGates:
132
117
  if not isinstance(exponent, int):
133
118
  return NotImplemented
134
119
  if exponent < 0:
@@ -155,8 +140,8 @@ class LinearCombinationOfGates(value.LinearDict[raw_types.Gate]):
155
140
  return {name for item in self.items() for name in protocols.parameter_names(item)}
156
141
 
157
142
  def _resolve_parameters_(
158
- self, resolver: 'cirq.ParamResolver', recursive: bool
159
- ) -> 'LinearCombinationOfGates':
143
+ self, resolver: cirq.ParamResolver, recursive: bool
144
+ ) -> LinearCombinationOfGates:
160
145
  return self.__class__(
161
146
  {
162
147
  protocols.resolve_parameters(
@@ -224,7 +209,7 @@ class LinearCombinationOfOperations(value.LinearDict[raw_types.Operation]):
224
209
  by the identity operator. Note that A may not be unitary or even normal.
225
210
  """
226
211
 
227
- def __init__(self, terms: Mapping[raw_types.Operation, 'cirq.TParamValComplex']) -> None:
212
+ def __init__(self, terms: Mapping[raw_types.Operation, cirq.TParamValComplex]) -> None:
228
213
  """Initializes linear combination from a collection of terms.
229
214
 
230
215
  Args:
@@ -233,11 +218,11 @@ class LinearCombinationOfOperations(value.LinearDict[raw_types.Operation]):
233
218
  """
234
219
  super().__init__(terms, validator=self._is_compatible)
235
220
 
236
- def _is_compatible(self, operation: 'cirq.Operation') -> bool:
221
+ def _is_compatible(self, operation: cirq.Operation) -> bool:
237
222
  return isinstance(operation, raw_types.Operation)
238
223
 
239
224
  @property
240
- def qubits(self) -> Tuple[raw_types.Qid, ...]:
225
+ def qubits(self) -> tuple[raw_types.Qid, ...]:
241
226
  """Returns qubits acted on self."""
242
227
  if not self:
243
228
  return ()
@@ -245,7 +230,7 @@ class LinearCombinationOfOperations(value.LinearDict[raw_types.Operation]):
245
230
  all_qubits = set.union(*qubit_sets)
246
231
  return tuple(sorted(all_qubits))
247
232
 
248
- def __pow__(self, exponent: int) -> 'LinearCombinationOfOperations':
233
+ def __pow__(self, exponent: int) -> LinearCombinationOfOperations:
249
234
  if not isinstance(exponent, int):
250
235
  return NotImplemented
251
236
  if exponent < 0:
@@ -272,8 +257,8 @@ class LinearCombinationOfOperations(value.LinearDict[raw_types.Operation]):
272
257
  return {name for item in self.items() for name in protocols.parameter_names(item)}
273
258
 
274
259
  def _resolve_parameters_(
275
- self, resolver: 'cirq.ParamResolver', recursive: bool
276
- ) -> 'LinearCombinationOfOperations':
260
+ self, resolver: cirq.ParamResolver, recursive: bool
261
+ ) -> LinearCombinationOfOperations:
277
262
  return self.__class__(
278
263
  {
279
264
  protocols.resolve_parameters(op, resolver, recursive): protocols.resolve_parameters(
@@ -300,7 +285,7 @@ class LinearCombinationOfOperations(value.LinearDict[raw_types.Operation]):
300
285
  workspace = np.empty_like(identity)
301
286
  axes = tuple(qubit_to_axis[q] for q in op.qubits)
302
287
  u = protocols.apply_unitary(op, protocols.ApplyUnitaryArgs(identity, workspace, axes))
303
- result += coefficient * u
288
+ result += complex(coefficient) * u
304
289
  return result.reshape((num_dim, num_dim))
305
290
 
306
291
  def _has_unitary_(self) -> bool:
@@ -317,7 +302,7 @@ class LinearCombinationOfOperations(value.LinearDict[raw_types.Operation]):
317
302
  """Computes Pauli expansion of self from Pauli expansions of terms."""
318
303
 
319
304
  def extend_term(
320
- pauli_names: str, qubits: Tuple['cirq.Qid', ...], all_qubits: Tuple['cirq.Qid', ...]
305
+ pauli_names: str, qubits: tuple[cirq.Qid, ...], all_qubits: tuple[cirq.Qid, ...]
321
306
  ) -> str:
322
307
  """Extends Pauli product on qubits to product on all_qubits."""
323
308
  assert len(pauli_names) == len(qubits)
@@ -326,8 +311,8 @@ class LinearCombinationOfOperations(value.LinearDict[raw_types.Operation]):
326
311
 
327
312
  def extend(
328
313
  expansion: value.LinearDict[str],
329
- qubits: Tuple['cirq.Qid', ...],
330
- all_qubits: Tuple['cirq.Qid', ...],
314
+ qubits: tuple[cirq.Qid, ...],
315
+ all_qubits: tuple[cirq.Qid, ...],
331
316
  ) -> value.LinearDict[str]:
332
317
  """Extends Pauli expansion on qubits to expansion on all_qubits."""
333
318
  return value.LinearDict(
@@ -358,7 +343,7 @@ def _is_linear_dict_of_unit_pauli_string(linear_dict: value.LinearDict[UnitPauli
358
343
 
359
344
 
360
345
  def _pauli_string_from_unit(
361
- unit: UnitPauliStringT, coefficient: Union[int, float, 'cirq.TParamValComplex'] = 1
346
+ unit: UnitPauliStringT, coefficient: int | float | cirq.TParamValComplex = 1
362
347
  ):
363
348
  return PauliString(qubit_pauli_map=dict(unit), coefficient=coefficient)
364
349
 
@@ -416,7 +401,7 @@ class PauliSum:
416
401
  4.0+0.0j
417
402
  """
418
403
 
419
- def __init__(self, linear_dict: Optional[value.LinearDict[UnitPauliStringT]] = None):
404
+ def __init__(self, linear_dict: value.LinearDict[UnitPauliStringT] | None = None):
420
405
  """Construct a PauliSum from a linear dictionary.
421
406
 
422
407
  Note, the preferred method of constructing PauliSum objects is either implicitly
@@ -444,7 +429,7 @@ class PauliSum:
444
429
  return self._linear_dict
445
430
 
446
431
  @staticmethod
447
- def wrap(val: PauliSumLike) -> 'PauliSum':
432
+ def wrap(val: PauliSumLike) -> PauliSum:
448
433
  """Convert a `cirq.PauliSumLike` object to a PauliSum
449
434
 
450
435
  Attempts to convert an existing int, float, complex, `cirq.PauliString`,
@@ -468,7 +453,7 @@ class PauliSum:
468
453
  return PauliSum() + val
469
454
 
470
455
  @classmethod
471
- def from_pauli_strings(cls, terms: Union[PauliString, List[PauliString]]) -> 'PauliSum':
456
+ def from_pauli_strings(cls, terms: PauliString | list[PauliString]) -> PauliSum:
472
457
  """Returns a PauliSum by combining `cirq.PauliString` terms.
473
458
 
474
459
  Args:
@@ -480,7 +465,7 @@ class PauliSum:
480
465
  """
481
466
  if isinstance(terms, PauliString):
482
467
  terms = [terms]
483
- termdict: DefaultDict[UnitPauliStringT, value.Scalar] = defaultdict(lambda: 0)
468
+ termdict: defaultdict[UnitPauliStringT, value.Scalar] = defaultdict(lambda: 0)
484
469
  for pstring in terms:
485
470
  key = frozenset(pstring._qubit_pauli_map.items())
486
471
  termdict[key] += pstring.coefficient
@@ -488,8 +473,8 @@ class PauliSum:
488
473
 
489
474
  @classmethod
490
475
  def from_boolean_expression(
491
- cls, boolean_expr: Expr, qubit_map: Dict[str, 'cirq.Qid']
492
- ) -> 'PauliSum':
476
+ cls, boolean_expr: sympy.Expr, qubit_map: dict[str, cirq.Qid]
477
+ ) -> PauliSum:
493
478
  """Builds the Hamiltonian representation of a Boolean expression.
494
479
 
495
480
  This is based on "On the representation of Boolean and real functions as Hamiltonians for
@@ -505,7 +490,7 @@ class PauliSum:
505
490
  Raises:
506
491
  ValueError: If `boolean_expr` is of an unsupported type.
507
492
  """
508
- if isinstance(boolean_expr, Symbol):
493
+ if isinstance(boolean_expr, sympy.Symbol):
509
494
  # In table 1, the entry for 'x' is '1/2.I - 1/2.Z'
510
495
  return cls.from_pauli_strings(
511
496
  [
@@ -540,12 +525,12 @@ class PauliSum:
540
525
  raise ValueError(f'Unsupported type: {type(boolean_expr)}')
541
526
 
542
527
  @property
543
- def qubits(self) -> Tuple[raw_types.Qid, ...]:
528
+ def qubits(self) -> tuple[raw_types.Qid, ...]:
544
529
  """The sorted list of qubits used in this PauliSum."""
545
530
  qs = {q for k in self._linear_dict.keys() for q, _ in k}
546
531
  return tuple(sorted(qs))
547
532
 
548
- def with_qubits(self, *new_qubits: 'cirq.Qid') -> 'PauliSum':
533
+ def with_qubits(self, *new_qubits: cirq.Qid) -> PauliSum:
549
534
  """Return a new PauliSum on `new_qubits`.
550
535
 
551
536
  Args:
@@ -569,7 +554,7 @@ class PauliSum:
569
554
  new_pauli_strings.append(pauli_string.map_qubits(qubit_map))
570
555
  return PauliSum.from_pauli_strings(new_pauli_strings)
571
556
 
572
- def copy(self) -> 'PauliSum':
557
+ def copy(self) -> PauliSum:
573
558
  """Return a copy of this PauliSum.
574
559
 
575
560
  Returns: A copy of this PauliSum.
@@ -577,7 +562,7 @@ class PauliSum:
577
562
  factory = type(self)
578
563
  return factory(self._linear_dict.copy())
579
564
 
580
- def matrix(self, qubits: Optional[Iterable[raw_types.Qid]] = None) -> np.ndarray:
565
+ def matrix(self, qubits: Iterable[raw_types.Qid] | None = None) -> np.ndarray:
581
566
  """Returns the matrix of this PauliSum in computational basis of qubits.
582
567
 
583
568
  Args:
@@ -761,6 +746,10 @@ class PauliSum:
761
746
  other = PauliSum.from_pauli_strings([PauliString(coefficient=other)])
762
747
  elif isinstance(other, PauliString):
763
748
  other = PauliSum.from_pauli_strings([other])
749
+ elif isinstance(other, raw_types.Operation) and isinstance(
750
+ other.gate, identity.IdentityGate
751
+ ):
752
+ other = PauliSum.from_pauli_strings([PauliString()])
764
753
 
765
754
  if not isinstance(other, PauliSum):
766
755
  return NotImplemented
@@ -769,11 +758,8 @@ class PauliSum:
769
758
  return self
770
759
 
771
760
  def __add__(self, other):
772
- if not isinstance(other, (numbers.Complex, PauliString, PauliSum)):
773
- if hasattr(other, 'gate') and isinstance(other.gate, identity.IdentityGate):
774
- other = PauliString(other)
775
- else:
776
- return NotImplemented
761
+ if not isinstance(other, (numbers.Complex, PauliString, PauliSum, raw_types.Operation)):
762
+ return NotImplemented
777
763
  result = self.copy()
778
764
  result += other
779
765
  return result
@@ -787,8 +773,12 @@ class PauliSum:
787
773
  def __isub__(self, other):
788
774
  if isinstance(other, numbers.Complex):
789
775
  other = PauliSum.from_pauli_strings([PauliString(coefficient=other)])
790
- if isinstance(other, PauliString):
776
+ elif isinstance(other, PauliString):
791
777
  other = PauliSum.from_pauli_strings([other])
778
+ elif isinstance(other, raw_types.Operation) and isinstance(
779
+ other.gate, identity.IdentityGate
780
+ ):
781
+ other = PauliSum.from_pauli_strings([PauliString()])
792
782
 
793
783
  if not isinstance(other, PauliSum):
794
784
  return NotImplemented
@@ -797,7 +787,7 @@ class PauliSum:
797
787
  return self
798
788
 
799
789
  def __sub__(self, other):
800
- if not isinstance(other, (numbers.Complex, PauliString, PauliSum)):
790
+ if not isinstance(other, (numbers.Complex, PauliString, PauliSum, raw_types.Operation)):
801
791
  return NotImplemented
802
792
  result = self.copy()
803
793
  result -= other
@@ -881,7 +871,7 @@ class ProjectorSum:
881
871
  """List of mappings representing a sum of projector operators."""
882
872
 
883
873
  def __init__(
884
- self, linear_dict: Optional[value.LinearDict[FrozenSet[Tuple[raw_types.Qid, int]]]] = None
874
+ self, linear_dict: value.LinearDict[frozenset[tuple[raw_types.Qid, int]]] | None = None
885
875
  ):
886
876
  """Constructor for ProjectorSum
887
877
 
@@ -890,7 +880,7 @@ class ProjectorSum:
890
880
  number. The tuple is a projector onto the qubit and the complex number is the
891
881
  weight of these projections.
892
882
  """
893
- self._linear_dict: value.LinearDict[FrozenSet[Tuple[raw_types.Qid, int]]] = (
883
+ self._linear_dict: value.LinearDict[frozenset[tuple[raw_types.Qid, int]]] = (
894
884
  linear_dict if linear_dict is not None else value.LinearDict({})
895
885
  )
896
886
 
@@ -898,11 +888,11 @@ class ProjectorSum:
898
888
  return self._linear_dict
899
889
 
900
890
  @property
901
- def qubits(self) -> Tuple[raw_types.Qid, ...]:
891
+ def qubits(self) -> tuple[raw_types.Qid, ...]:
902
892
  qs = {q for k in self._linear_dict.keys() for q, _ in k}
903
893
  return tuple(sorted(qs))
904
894
 
905
- def _json_dict_(self) -> Dict[str, Any]:
895
+ def _json_dict_(self) -> dict[str, Any]:
906
896
  linear_dict = []
907
897
  for projector_dict, scalar in dict(self._linear_dict).items():
908
898
  key = [[k, v] for k, v in dict(projector_dict).items()]
@@ -920,9 +910,7 @@ class ProjectorSum:
920
910
  return cls(linear_dict=value.LinearDict(converted_dict))
921
911
 
922
912
  @classmethod
923
- def from_projector_strings(
924
- cls, terms: Union[ProjectorString, List[ProjectorString]]
925
- ) -> 'ProjectorSum':
913
+ def from_projector_strings(cls, terms: ProjectorString | list[ProjectorString]) -> ProjectorSum:
926
914
  """Builds a ProjectorSum from one or more ProjectorString(s).
927
915
 
928
916
  Args:
@@ -933,7 +921,7 @@ class ProjectorSum:
933
921
  """
934
922
  if isinstance(terms, ProjectorString):
935
923
  terms = [terms]
936
- termdict: DefaultDict[FrozenSet[Tuple[raw_types.Qid, int]], value.Scalar] = defaultdict(
924
+ termdict: defaultdict[frozenset[tuple[raw_types.Qid, int]], value.Scalar] = defaultdict(
937
925
  lambda: 0.0
938
926
  )
939
927
  for pstring in terms:
@@ -941,10 +929,10 @@ class ProjectorSum:
941
929
  termdict[key] += pstring.coefficient
942
930
  return cls(linear_dict=value.LinearDict(termdict))
943
931
 
944
- def copy(self) -> 'ProjectorSum':
932
+ def copy(self) -> ProjectorSum:
945
933
  return ProjectorSum(self._linear_dict.copy())
946
934
 
947
- def matrix(self, projector_qids: Optional[Iterable[raw_types.Qid]] = None) -> csr_matrix:
935
+ def matrix(self, projector_qids: Iterable[raw_types.Qid] | None = None) -> csr_matrix:
948
936
  """Returns the matrix of self in computational basis of qubits.
949
937
 
950
938
  Args:
@@ -1022,7 +1010,7 @@ class ProjectorSum:
1022
1010
  def __bool__(self) -> bool:
1023
1011
  return bool(self._linear_dict)
1024
1012
 
1025
- def __iadd__(self, other: Union['ProjectorString', 'ProjectorSum']):
1013
+ def __iadd__(self, other: ProjectorString | ProjectorSum):
1026
1014
  if isinstance(other, ProjectorString):
1027
1015
  other = ProjectorSum.from_projector_strings(other)
1028
1016
  elif not isinstance(other, ProjectorSum):
@@ -1030,7 +1018,7 @@ class ProjectorSum:
1030
1018
  self._linear_dict += other._linear_dict
1031
1019
  return self
1032
1020
 
1033
- def __add__(self, other: Union['ProjectorString', 'ProjectorSum']):
1021
+ def __add__(self, other: ProjectorString | ProjectorSum):
1034
1022
  if isinstance(other, ProjectorString):
1035
1023
  other = ProjectorSum.from_projector_strings(other)
1036
1024
  elif not isinstance(other, ProjectorSum):
@@ -1039,7 +1027,7 @@ class ProjectorSum:
1039
1027
  result += other
1040
1028
  return result
1041
1029
 
1042
- def __isub__(self, other: Union['ProjectorString', 'ProjectorSum']):
1030
+ def __isub__(self, other: ProjectorString | ProjectorSum):
1043
1031
  if isinstance(other, ProjectorString):
1044
1032
  other = ProjectorSum.from_projector_strings(other)
1045
1033
  elif not isinstance(other, ProjectorSum):
@@ -1047,7 +1035,7 @@ class ProjectorSum:
1047
1035
  self._linear_dict -= other._linear_dict
1048
1036
  return self
1049
1037
 
1050
- def __sub__(self, other: Union['ProjectorString', 'ProjectorSum']):
1038
+ def __sub__(self, other: ProjectorString | ProjectorSum):
1051
1039
  if isinstance(other, ProjectorString):
1052
1040
  other = ProjectorSum.from_projector_strings(other)
1053
1041
  elif not isinstance(other, ProjectorSum):
@@ -12,8 +12,9 @@
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 collections
16
- from typing import Union
17
18
 
18
19
  import numpy as np
19
20
  import pytest
@@ -228,12 +229,12 @@ def test_parameterized_linear_combination_of_gates(
228
229
 
229
230
 
230
231
  def get_matrix(
231
- operator: Union[
232
- cirq.Gate,
233
- cirq.GateOperation,
234
- cirq.LinearCombinationOfGates,
235
- cirq.LinearCombinationOfOperations,
236
- ],
232
+ operator: (
233
+ cirq.Gate
234
+ | cirq.GateOperation
235
+ | cirq.LinearCombinationOfGates
236
+ | cirq.LinearCombinationOfOperations
237
+ ),
237
238
  ) -> np.ndarray:
238
239
  if isinstance(operator, (cirq.LinearCombinationOfGates, cirq.LinearCombinationOfOperations)):
239
240
  return operator.matrix()
@@ -241,8 +242,8 @@ def get_matrix(
241
242
 
242
243
 
243
244
  def assert_linear_combinations_are_equal(
244
- actual: Union[cirq.LinearCombinationOfGates, cirq.LinearCombinationOfOperations],
245
- expected: Union[cirq.LinearCombinationOfGates, cirq.LinearCombinationOfOperations],
245
+ actual: cirq.LinearCombinationOfGates | cirq.LinearCombinationOfOperations,
246
+ expected: cirq.LinearCombinationOfGates | cirq.LinearCombinationOfOperations,
246
247
  ) -> None:
247
248
  if not actual and not expected:
248
249
  assert len(actual) == 0
@@ -970,6 +971,10 @@ def test_paulisum_validation():
970
971
  ps += cirq.I(cirq.LineQubit(0))
971
972
  assert ps == cirq.PauliSum(cirq.LinearDict({frozenset(): complex(1)}))
972
973
 
974
+ ps = cirq.PauliSum()
975
+ ps -= cirq.I(cirq.LineQubit(0))
976
+ assert ps == cirq.PauliSum(cirq.LinearDict({frozenset(): complex(-1)}))
977
+
973
978
 
974
979
  def test_add_number_paulisum():
975
980
  q = cirq.LineQubit.range(2)
cirq/ops/matrix_gates.py CHANGED
@@ -14,13 +14,15 @@
14
14
 
15
15
  """Quantum gates defined by a matrix."""
16
16
 
17
- from typing import Any, Dict, Iterable, List, Optional, Tuple, TYPE_CHECKING
17
+ from __future__ import annotations
18
+
19
+ from typing import Any, Iterable, TYPE_CHECKING
18
20
 
19
21
  import numpy as np
20
22
 
21
23
  from cirq import _import, linalg, protocols
22
24
  from cirq._compat import proper_repr
23
- from cirq.ops import global_phase_op, identity, phased_x_z_gate, raw_types
25
+ from cirq.ops import global_phase_op, phased_x_z_gate, raw_types
24
26
 
25
27
  if TYPE_CHECKING:
26
28
  import cirq
@@ -53,8 +55,8 @@ class MatrixGate(raw_types.Gate):
53
55
  self,
54
56
  matrix: np.ndarray,
55
57
  *,
56
- name: Optional[str] = None,
57
- qid_shape: Optional[Iterable[int]] = None,
58
+ name: str | None = None,
59
+ qid_shape: Iterable[int] | None = None,
58
60
  unitary_check: bool = True,
59
61
  unitary_check_rtol: float = 1e-5,
60
62
  unitary_check_atol: float = 1e-8,
@@ -109,11 +111,11 @@ class MatrixGate(raw_types.Gate):
109
111
  ):
110
112
  raise ValueError(f'Not a unitary matrix: {matrix}')
111
113
 
112
- def with_name(self, name: str) -> 'MatrixGate':
114
+ def with_name(self, name: str) -> MatrixGate:
113
115
  """Creates a new MatrixGate with the same matrix and a new name."""
114
116
  return MatrixGate(self._matrix, name=name, qid_shape=self._qid_shape, unitary_check=False)
115
117
 
116
- def _json_dict_(self) -> Dict[str, Any]:
118
+ def _json_dict_(self) -> dict[str, Any]:
117
119
  return {
118
120
  'matrix': self._matrix.tolist(),
119
121
  'qid_shape': self._qid_shape,
@@ -124,16 +126,16 @@ class MatrixGate(raw_types.Gate):
124
126
  def _from_json_dict_(cls, matrix, qid_shape, name=None, **kwargs):
125
127
  return cls(matrix=np.array(matrix), qid_shape=qid_shape, name=name)
126
128
 
127
- def _qid_shape_(self) -> Tuple[int, ...]:
129
+ def _qid_shape_(self) -> tuple[int, ...]:
128
130
  return self._qid_shape
129
131
 
130
- def __pow__(self, exponent: Any) -> 'MatrixGate':
132
+ def __pow__(self, exponent: Any) -> MatrixGate:
131
133
  if not isinstance(exponent, (int, float)):
132
134
  return NotImplemented
133
135
  new_mat = linalg.map_eigenvalues(self._matrix, lambda b: b**exponent)
134
136
  return MatrixGate(new_mat, qid_shape=self._qid_shape)
135
137
 
136
- def _phase_by_(self, phase_turns: float, qubit_index: int) -> 'MatrixGate':
138
+ def _phase_by_(self, phase_turns: float, qubit_index: int) -> MatrixGate:
137
139
  if not isinstance(phase_turns, (int, float)):
138
140
  return NotImplemented
139
141
  if self._qid_shape[qubit_index] != 2:
@@ -147,10 +149,10 @@ class MatrixGate(raw_types.Gate):
147
149
  result[linalg.slice_for_qubits_equal_to([j], 1)] *= np.conj(p)
148
150
  return MatrixGate(matrix=result.reshape(self._matrix.shape), qid_shape=self._qid_shape)
149
151
 
150
- def _decompose_(self, qubits: Tuple['cirq.Qid', ...]) -> 'cirq.OP_TREE':
152
+ def _decompose_(self, qubits: tuple[cirq.Qid, ...]) -> cirq.OP_TREE:
151
153
  from cirq.circuits import Circuit
152
154
 
153
- decomposed: List['cirq.Operation'] = NotImplemented
155
+ decomposed: list[cirq.Operation] = NotImplemented
154
156
  if self._qid_shape == (2,):
155
157
  decomposed = [
156
158
  g.on(qubits[0])
@@ -168,8 +170,8 @@ class MatrixGate(raw_types.Gate):
168
170
  return NotImplemented
169
171
  # The above algorithms ignore phase, but phase is important to maintain if the gate is
170
172
  # controlled. Here, we add it back in with a global phase op.
171
- ident = identity.IdentityGate(qid_shape=self._qid_shape).on(*qubits) # Preserve qid order
172
- u = protocols.unitary(Circuit(ident, *decomposed)).reshape(self._matrix.shape)
173
+ circuit = Circuit(*decomposed)
174
+ u = circuit.unitary(qubit_order=qubits, qubits_that_should_be_present=qubits)
173
175
  phase_delta = linalg.phase_delta(u, self._matrix)
174
176
  # Phase delta is on the complex unit circle, so if real(phase_delta) >= 1, that means
175
177
  # no phase delta. (>1 is rounding error).
@@ -183,10 +185,11 @@ class MatrixGate(raw_types.Gate):
183
185
  def _unitary_(self) -> np.ndarray:
184
186
  return np.copy(self._matrix)
185
187
 
186
- def _circuit_diagram_info_(
187
- self, args: 'cirq.CircuitDiagramInfoArgs'
188
- ) -> 'cirq.CircuitDiagramInfo':
188
+ def _circuit_diagram_info_(self, args: cirq.CircuitDiagramInfoArgs) -> cirq.CircuitDiagramInfo:
189
189
  n_qubits = len(self._qid_shape)
190
+ # No diagram for zero-qubit gates; let fallback handle it
191
+ if n_qubits == 0:
192
+ return NotImplemented
190
193
  if self._name is not None:
191
194
  symbols = (
192
195
  [self._name] if n_qubits == 1 else [f'{self._name}[{i+1}]' for i in range(n_qubits)]
@@ -196,7 +199,7 @@ class MatrixGate(raw_types.Gate):
196
199
  rest = [f'#{i+1}' for i in range(1, n_qubits)]
197
200
  return protocols.CircuitDiagramInfo(wire_symbols=[main, *rest])
198
201
 
199
- def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
202
+ def _qasm_(self, args: cirq.QasmArgs, qubits: tuple[cirq.Qid, ...]) -> str | None:
200
203
  args.validate_version('2.0', '3.0')
201
204
  if self._qid_shape == (2,):
202
205
  return protocols.qasm(
@@ -230,7 +233,7 @@ class MatrixGate(raw_types.Gate):
230
233
  return str(self._matrix.round(3))
231
234
 
232
235
 
233
- def _matrix_to_diagram_symbol(matrix: np.ndarray, args: 'protocols.CircuitDiagramInfoArgs') -> str:
236
+ def _matrix_to_diagram_symbol(matrix: np.ndarray, args: protocols.CircuitDiagramInfoArgs) -> str:
234
237
  if args.precision is not None:
235
238
  matrix = matrix.round(args.precision)
236
239
  result = str(matrix)
@@ -11,6 +11,9 @@
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 re
15
18
 
16
19
  import numpy as np
@@ -410,3 +413,16 @@ def test_matrixgate_name_serialization():
410
413
  gate_after_serialization3 = cirq.read_json(json_text=cirq.to_json(gate3))
411
414
  assert gate3._name == ''
412
415
  assert gate_after_serialization3._name == ''
416
+
417
+
418
+ def test_decompose_when_qubits_not_in_ascending_order():
419
+ # Previous code for preserving global phase would misorder qubits
420
+ q0, q1 = cirq.LineQubit.range(2)
421
+ circuit1 = cirq.Circuit()
422
+ matrix = cirq.testing.random_unitary(4, random_state=0)
423
+ circuit1.append(cirq.MatrixGate(matrix).on(q1, q0))
424
+ u1 = cirq.unitary(circuit1)
425
+ decomposed = cirq.decompose(circuit1)
426
+ circuit2 = cirq.Circuit(decomposed)
427
+ u2 = cirq.unitary(circuit2)
428
+ np.testing.assert_allclose(u1, u2, atol=1e-14)