cirq-core 1.5.0.dev20250409225226__py3-none-any.whl → 1.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (732) hide show
  1. cirq/__init__.py +16 -17
  2. cirq/_compat.py +21 -20
  3. cirq/_compat_test.py +14 -34
  4. cirq/_doc.py +4 -2
  5. cirq/_import.py +8 -6
  6. cirq/_import_test.py +4 -2
  7. cirq/_version.py +6 -6
  8. cirq/_version_test.py +2 -2
  9. cirq/circuits/_block_diagram_drawer.py +11 -10
  10. cirq/circuits/_block_diagram_drawer_test.py +8 -6
  11. cirq/circuits/_box_drawing_character_data.py +8 -8
  12. cirq/circuits/_box_drawing_character_data_test.py +3 -1
  13. cirq/circuits/_bucket_priority_queue.py +9 -7
  14. cirq/circuits/_bucket_priority_queue_test.py +22 -20
  15. cirq/circuits/circuit.py +248 -172
  16. cirq/circuits/circuit_operation.py +73 -83
  17. cirq/circuits/circuit_operation_test.py +128 -90
  18. cirq/circuits/circuit_test.py +211 -151
  19. cirq/circuits/frozen_circuit.py +23 -60
  20. cirq/circuits/frozen_circuit_test.py +31 -8
  21. cirq/circuits/insert_strategy.py +7 -5
  22. cirq/circuits/insert_strategy_test.py +4 -2
  23. cirq/circuits/moment.py +88 -40
  24. cirq/circuits/moment_test.py +128 -51
  25. cirq/circuits/optimization_pass.py +5 -5
  26. cirq/circuits/optimization_pass_test.py +10 -10
  27. cirq/circuits/qasm_output.py +11 -11
  28. cirq/circuits/qasm_output_test.py +25 -22
  29. cirq/circuits/text_diagram_drawer.py +23 -38
  30. cirq/circuits/text_diagram_drawer_test.py +19 -17
  31. cirq/conftest.py +4 -3
  32. cirq/contrib/__init__.py +4 -4
  33. cirq/contrib/acquaintance/__init__.py +1 -1
  34. cirq/contrib/acquaintance/bipartite.py +5 -8
  35. cirq/contrib/acquaintance/bipartite_test.py +18 -13
  36. cirq/contrib/acquaintance/devices.py +2 -2
  37. cirq/contrib/acquaintance/devices_test.py +5 -3
  38. cirq/contrib/acquaintance/executor.py +5 -5
  39. cirq/contrib/acquaintance/executor_test.py +13 -9
  40. cirq/contrib/acquaintance/gates.py +18 -28
  41. cirq/contrib/acquaintance/gates_test.py +24 -20
  42. cirq/contrib/acquaintance/inspection_utils.py +8 -4
  43. cirq/contrib/acquaintance/inspection_utils_test.py +4 -2
  44. cirq/contrib/acquaintance/mutation_utils.py +4 -4
  45. cirq/contrib/acquaintance/mutation_utils_test.py +4 -2
  46. cirq/contrib/acquaintance/optimizers.py +4 -4
  47. cirq/contrib/acquaintance/optimizers_test.py +4 -1
  48. cirq/contrib/acquaintance/permutation.py +15 -27
  49. cirq/contrib/acquaintance/permutation_test.py +26 -17
  50. cirq/contrib/acquaintance/shift.py +4 -4
  51. cirq/contrib/acquaintance/shift_swap_network.py +4 -4
  52. cirq/contrib/acquaintance/shift_swap_network_test.py +9 -6
  53. cirq/contrib/acquaintance/shift_test.py +8 -6
  54. cirq/contrib/acquaintance/strategies/cubic.py +2 -2
  55. cirq/contrib/acquaintance/strategies/cubic_test.py +4 -2
  56. cirq/contrib/acquaintance/strategies/quartic_paired.py +6 -6
  57. cirq/contrib/acquaintance/strategies/quartic_paired_test.py +10 -6
  58. cirq/contrib/acquaintance/testing.py +2 -0
  59. cirq/contrib/acquaintance/topological_sort.py +2 -2
  60. cirq/contrib/acquaintance/topological_sort_test.py +3 -1
  61. cirq/contrib/bayesian_network/bayesian_network_gate.py +9 -10
  62. cirq/contrib/bayesian_network/bayesian_network_gate_test.py +14 -9
  63. cirq/contrib/circuitdag/circuit_dag.py +4 -4
  64. cirq/contrib/circuitdag/circuit_dag_test.py +17 -15
  65. cirq/contrib/custom_simulators/custom_state_simulator.py +5 -5
  66. cirq/contrib/custom_simulators/custom_state_simulator_test.py +22 -17
  67. cirq/contrib/graph_device/graph_device.py +12 -11
  68. cirq/contrib/graph_device/graph_device_test.py +18 -14
  69. cirq/contrib/graph_device/hypergraph.py +16 -14
  70. cirq/contrib/graph_device/hypergraph_test.py +13 -11
  71. cirq/contrib/graph_device/uniform_graph_device.py +6 -4
  72. cirq/contrib/graph_device/uniform_graph_device_test.py +11 -3
  73. cirq/contrib/hacks/disable_validation.py +6 -1
  74. cirq/contrib/hacks/disable_validation_test.py +3 -1
  75. cirq/contrib/json.py +31 -5
  76. cirq/contrib/json_test.py +6 -3
  77. cirq/contrib/json_test_data/DampedReadoutNoiseModel.json +12 -0
  78. cirq/contrib/json_test_data/DampedReadoutNoiseModel.repr +4 -0
  79. cirq/contrib/json_test_data/DepolarizingNoiseModel.json +12 -0
  80. cirq/contrib/json_test_data/DepolarizingNoiseModel.repr +4 -0
  81. cirq/contrib/json_test_data/DepolarizingWithDampedReadoutNoiseModel.json +6 -0
  82. cirq/contrib/json_test_data/DepolarizingWithDampedReadoutNoiseModel.repr +1 -0
  83. cirq/contrib/json_test_data/DepolarizingWithReadoutNoiseModel.json +5 -0
  84. cirq/contrib/json_test_data/DepolarizingWithReadoutNoiseModel.repr +1 -0
  85. cirq/contrib/json_test_data/ReadoutNoiseModel.json +12 -0
  86. cirq/contrib/json_test_data/ReadoutNoiseModel.repr +4 -0
  87. cirq/contrib/json_test_data/__init__.py +17 -0
  88. cirq/contrib/json_test_data/spec.py +32 -0
  89. cirq/contrib/noise_models/noise_models.py +119 -5
  90. cirq/contrib/noise_models/noise_models_test.py +37 -9
  91. cirq/contrib/paulistring/clifford_optimize.py +6 -4
  92. cirq/contrib/paulistring/clifford_optimize_test.py +6 -5
  93. cirq/contrib/paulistring/clifford_target_gateset.py +10 -10
  94. cirq/contrib/paulistring/clifford_target_gateset_test.py +13 -11
  95. cirq/contrib/paulistring/optimize.py +2 -0
  96. cirq/contrib/paulistring/optimize_test.py +4 -3
  97. cirq/contrib/paulistring/pauli_string_dag.py +2 -0
  98. cirq/contrib/paulistring/pauli_string_dag_test.py +3 -1
  99. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +255 -120
  100. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +398 -19
  101. cirq/contrib/paulistring/pauli_string_optimize.py +7 -1
  102. cirq/contrib/paulistring/pauli_string_optimize_test.py +5 -3
  103. cirq/contrib/paulistring/recombine.py +6 -4
  104. cirq/contrib/paulistring/recombine_test.py +3 -1
  105. cirq/contrib/paulistring/separate.py +9 -6
  106. cirq/contrib/paulistring/separate_test.py +3 -1
  107. cirq/contrib/qasm_import/_lexer.py +3 -2
  108. cirq/contrib/qasm_import/_lexer_test.py +49 -13
  109. cirq/contrib/qasm_import/_parser.py +547 -83
  110. cirq/contrib/qasm_import/_parser_test.py +988 -97
  111. cirq/contrib/qasm_import/exception.py +2 -0
  112. cirq/contrib/qasm_import/qasm.py +8 -2
  113. cirq/contrib/qasm_import/qasm_test.py +7 -4
  114. cirq/contrib/qcircuit/qcircuit_diagram_info.py +5 -5
  115. cirq/contrib/qcircuit/qcircuit_diagram_info_test.py +4 -1
  116. cirq/contrib/qcircuit/qcircuit_pdf.py +7 -3
  117. cirq/contrib/qcircuit/qcircuit_pdf_test.py +3 -1
  118. cirq/contrib/qcircuit/qcircuit_test.py +10 -8
  119. cirq/contrib/quantum_volume/quantum_volume.py +31 -27
  120. cirq/contrib/quantum_volume/quantum_volume_test.py +19 -16
  121. cirq/contrib/quimb/density_matrix.py +15 -14
  122. cirq/contrib/quimb/density_matrix_test.py +10 -7
  123. cirq/contrib/quimb/grid_circuits.py +5 -2
  124. cirq/contrib/quimb/grid_circuits_test.py +3 -0
  125. cirq/contrib/quimb/mps_simulator.py +20 -20
  126. cirq/contrib/quimb/mps_simulator_test.py +3 -0
  127. cirq/contrib/quimb/state_vector.py +12 -11
  128. cirq/contrib/quimb/state_vector_test.py +3 -0
  129. cirq/contrib/quirk/export_to_quirk.py +5 -3
  130. cirq/contrib/quirk/export_to_quirk_test.py +18 -16
  131. cirq/contrib/quirk/linearize_circuit.py +2 -0
  132. cirq/contrib/quirk/quirk_gate.py +18 -17
  133. cirq/contrib/routing/device.py +5 -3
  134. cirq/contrib/routing/device_test.py +2 -0
  135. cirq/contrib/routing/greedy.py +10 -21
  136. cirq/contrib/routing/greedy_test.py +4 -2
  137. cirq/contrib/routing/initialization.py +2 -2
  138. cirq/contrib/routing/initialization_test.py +5 -3
  139. cirq/contrib/routing/router.py +9 -5
  140. cirq/contrib/routing/router_test.py +2 -0
  141. cirq/contrib/routing/swap_network.py +3 -3
  142. cirq/contrib/routing/swap_network_test.py +3 -1
  143. cirq/contrib/routing/utils.py +2 -2
  144. cirq/contrib/routing/utils_test.py +3 -0
  145. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +15 -9
  146. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py +3 -0
  147. cirq/contrib/svg/svg.py +3 -3
  148. cirq/contrib/svg/svg_test.py +8 -5
  149. cirq/devices/device.py +4 -4
  150. cirq/devices/device_test.py +7 -4
  151. cirq/devices/grid_device_metadata.py +10 -10
  152. cirq/devices/grid_device_metadata_test.py +3 -0
  153. cirq/devices/grid_qubit.py +29 -21
  154. cirq/devices/grid_qubit_test.py +3 -0
  155. cirq/devices/insertion_noise_model.py +7 -7
  156. cirq/devices/insertion_noise_model_test.py +7 -5
  157. cirq/devices/line_qubit.py +13 -13
  158. cirq/devices/line_qubit_test.py +2 -0
  159. cirq/devices/named_topologies.py +18 -29
  160. cirq/devices/named_topologies_test.py +13 -10
  161. cirq/devices/noise_model.py +3 -3
  162. cirq/devices/noise_model_test.py +19 -15
  163. cirq/devices/noise_properties.py +15 -6
  164. cirq/devices/noise_properties_test.py +34 -3
  165. cirq/devices/noise_utils.py +11 -9
  166. cirq/devices/noise_utils_test.py +2 -0
  167. cirq/devices/superconducting_qubits_noise_properties.py +23 -22
  168. cirq/devices/superconducting_qubits_noise_properties_test.py +6 -6
  169. cirq/devices/thermal_noise_model.py +107 -37
  170. cirq/devices/thermal_noise_model_test.py +21 -0
  171. cirq/devices/unconstrained_device.py +5 -3
  172. cirq/devices/unconstrained_device_test.py +2 -0
  173. cirq/experiments/__init__.py +4 -2
  174. cirq/experiments/benchmarking/__init__.py +17 -0
  175. cirq/experiments/benchmarking/parallel_xeb.py +677 -0
  176. cirq/experiments/benchmarking/parallel_xeb_test.py +447 -0
  177. cirq/experiments/fidelity_estimation.py +14 -8
  178. cirq/experiments/fidelity_estimation_test.py +3 -0
  179. cirq/experiments/n_qubit_tomography.py +17 -16
  180. cirq/experiments/n_qubit_tomography_test.py +8 -5
  181. cirq/experiments/purity_estimation.py +2 -0
  182. cirq/experiments/purity_estimation_test.py +2 -0
  183. cirq/experiments/qubit_characterizations.py +207 -103
  184. cirq/experiments/qubit_characterizations_test.py +40 -12
  185. cirq/experiments/random_quantum_circuit_generation.py +56 -70
  186. cirq/experiments/random_quantum_circuit_generation_test.py +11 -8
  187. cirq/experiments/readout_confusion_matrix.py +24 -22
  188. cirq/experiments/readout_confusion_matrix_test.py +2 -0
  189. cirq/experiments/single_qubit_readout_calibration.py +30 -15
  190. cirq/experiments/single_qubit_readout_calibration_test.py +5 -2
  191. cirq/experiments/t1_decay_experiment.py +9 -7
  192. cirq/experiments/t1_decay_experiment_test.py +13 -11
  193. cirq/experiments/t2_decay_experiment.py +16 -13
  194. cirq/experiments/t2_decay_experiment_test.py +2 -0
  195. cirq/experiments/two_qubit_xeb.py +64 -57
  196. cirq/experiments/two_qubit_xeb_test.py +10 -6
  197. cirq/experiments/xeb_fitting.py +39 -35
  198. cirq/experiments/xeb_sampling.py +37 -44
  199. cirq/experiments/xeb_sampling_test.py +3 -0
  200. cirq/experiments/xeb_simulation.py +14 -10
  201. cirq/experiments/xeb_simulation_test.py +5 -5
  202. cirq/experiments/z_phase_calibration.py +32 -29
  203. cirq/experiments/z_phase_calibration_test.py +3 -4
  204. cirq/interop/quirk/cells/__init__.py +1 -1
  205. cirq/interop/quirk/cells/all_cells.py +7 -2
  206. cirq/interop/quirk/cells/arithmetic_cells.py +29 -41
  207. cirq/interop/quirk/cells/arithmetic_cells_test.py +17 -14
  208. cirq/interop/quirk/cells/cell.py +19 -28
  209. cirq/interop/quirk/cells/cell_test.py +3 -0
  210. cirq/interop/quirk/cells/composite_cell.py +13 -28
  211. cirq/interop/quirk/cells/composite_cell_test.py +2 -0
  212. cirq/interop/quirk/cells/control_cells.py +15 -15
  213. cirq/interop/quirk/cells/control_cells_test.py +7 -5
  214. cirq/interop/quirk/cells/frequency_space_cells.py +4 -3
  215. cirq/interop/quirk/cells/frequency_space_cells_test.py +3 -1
  216. cirq/interop/quirk/cells/ignored_cells.py +3 -0
  217. cirq/interop/quirk/cells/ignored_cells_test.py +3 -1
  218. cirq/interop/quirk/cells/input_cells.py +7 -5
  219. cirq/interop/quirk/cells/input_cells_test.py +7 -5
  220. cirq/interop/quirk/cells/input_rotation_cells.py +15 -13
  221. cirq/interop/quirk/cells/input_rotation_cells_test.py +9 -7
  222. cirq/interop/quirk/cells/measurement_cells.py +5 -2
  223. cirq/interop/quirk/cells/measurement_cells_test.py +3 -1
  224. cirq/interop/quirk/cells/parse.py +22 -23
  225. cirq/interop/quirk/cells/parse_test.py +12 -10
  226. cirq/interop/quirk/cells/qubit_permutation_cells.py +5 -3
  227. cirq/interop/quirk/cells/qubit_permutation_cells_test.py +9 -7
  228. cirq/interop/quirk/cells/scalar_cells.py +4 -1
  229. cirq/interop/quirk/cells/scalar_cells_test.py +3 -1
  230. cirq/interop/quirk/cells/single_qubit_rotation_cells.py +5 -2
  231. cirq/interop/quirk/cells/single_qubit_rotation_cells_test.py +5 -3
  232. cirq/interop/quirk/cells/swap_cell.py +8 -6
  233. cirq/interop/quirk/cells/swap_cell_test.py +6 -4
  234. cirq/interop/quirk/cells/testing.py +6 -6
  235. cirq/interop/quirk/cells/testing_test.py +8 -6
  236. cirq/interop/quirk/cells/unsupported_cells.py +3 -0
  237. cirq/interop/quirk/cells/unsupported_cells_test.py +4 -2
  238. cirq/interop/quirk/url_to_circuit.py +23 -36
  239. cirq/interop/quirk/url_to_circuit_test.py +4 -1
  240. cirq/json_resolver_cache.py +14 -12
  241. cirq/linalg/__init__.py +4 -6
  242. cirq/linalg/combinators.py +7 -5
  243. cirq/linalg/combinators_test.py +10 -7
  244. cirq/linalg/decompositions.py +24 -35
  245. cirq/linalg/decompositions_test.py +3 -1
  246. cirq/linalg/diagonalize.py +6 -4
  247. cirq/linalg/diagonalize_test.py +15 -14
  248. cirq/linalg/operator_spaces.py +14 -14
  249. cirq/linalg/operator_spaces_test.py +13 -11
  250. cirq/linalg/predicates.py +18 -9
  251. cirq/linalg/predicates_test.py +5 -0
  252. cirq/linalg/tolerance.py +6 -3
  253. cirq/linalg/tolerance_test.py +6 -4
  254. cirq/linalg/transformations.py +23 -20
  255. cirq/linalg/transformations_test.py +73 -43
  256. cirq/neutral_atoms/convert_to_neutral_atom_gates.py +9 -3
  257. cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py +3 -1
  258. cirq/neutral_atoms/neutral_atom_devices.py +2 -0
  259. cirq/ops/__init__.py +2 -0
  260. cirq/ops/arithmetic_operation.py +21 -21
  261. cirq/ops/arithmetic_operation_test.py +7 -8
  262. cirq/ops/boolean_hamiltonian.py +23 -22
  263. cirq/ops/boolean_hamiltonian_test.py +12 -9
  264. cirq/ops/classically_controlled_operation.py +31 -36
  265. cirq/ops/classically_controlled_operation_test.py +121 -117
  266. cirq/ops/clifford_gate.py +98 -81
  267. cirq/ops/clifford_gate_test.py +72 -57
  268. cirq/ops/common_channels.py +44 -44
  269. cirq/ops/common_channels_test.py +83 -81
  270. cirq/ops/common_gate_families.py +9 -7
  271. cirq/ops/common_gate_families_test.py +11 -7
  272. cirq/ops/common_gates.py +164 -183
  273. cirq/ops/common_gates_test.py +135 -95
  274. cirq/ops/control_values.py +23 -26
  275. cirq/ops/control_values_test.py +22 -20
  276. cirq/ops/controlled_gate.py +64 -112
  277. cirq/ops/controlled_gate_test.py +130 -35
  278. cirq/ops/controlled_operation.py +24 -35
  279. cirq/ops/controlled_operation_test.py +8 -6
  280. cirq/ops/dense_pauli_string.py +38 -49
  281. cirq/ops/dense_pauli_string_test.py +4 -2
  282. cirq/ops/diagonal_gate.py +18 -31
  283. cirq/ops/diagonal_gate_test.py +13 -13
  284. cirq/ops/eigen_gate.py +29 -29
  285. cirq/ops/eigen_gate_test.py +45 -28
  286. cirq/ops/fourier_transform.py +14 -20
  287. cirq/ops/fourier_transform_test.py +15 -12
  288. cirq/ops/fsim_gate.py +43 -42
  289. cirq/ops/fsim_gate_test.py +29 -29
  290. cirq/ops/gate_features.py +2 -0
  291. cirq/ops/gate_features_test.py +5 -3
  292. cirq/ops/gate_operation.py +43 -65
  293. cirq/ops/gate_operation_test.py +46 -42
  294. cirq/ops/gateset.py +28 -40
  295. cirq/ops/gateset_test.py +4 -2
  296. cirq/ops/global_phase_op.py +45 -20
  297. cirq/ops/global_phase_op_test.py +44 -20
  298. cirq/ops/greedy_qubit_manager.py +10 -8
  299. cirq/ops/greedy_qubit_manager_test.py +5 -3
  300. cirq/ops/identity.py +14 -12
  301. cirq/ops/identity_test.py +24 -20
  302. cirq/ops/kraus_channel.py +11 -8
  303. cirq/ops/kraus_channel_test.py +14 -11
  304. cirq/ops/linear_combinations.py +65 -77
  305. cirq/ops/linear_combinations_test.py +14 -9
  306. cirq/ops/matrix_gates.py +21 -18
  307. cirq/ops/matrix_gates_test.py +16 -0
  308. cirq/ops/measure_util.py +15 -20
  309. cirq/ops/measure_util_test.py +2 -0
  310. cirq/ops/measurement_gate.py +26 -37
  311. cirq/ops/measurement_gate_test.py +2 -0
  312. cirq/ops/mixed_unitary_channel.py +12 -9
  313. cirq/ops/mixed_unitary_channel_test.py +14 -11
  314. cirq/ops/named_qubit.py +16 -13
  315. cirq/ops/named_qubit_test.py +15 -13
  316. cirq/ops/op_tree.py +9 -7
  317. cirq/ops/op_tree_test.py +22 -19
  318. cirq/ops/parallel_gate.py +15 -17
  319. cirq/ops/parallel_gate_test.py +18 -16
  320. cirq/ops/parity_gates.py +23 -25
  321. cirq/ops/parity_gates_test.py +36 -32
  322. cirq/ops/pauli_gates.py +22 -21
  323. cirq/ops/pauli_gates_test.py +29 -20
  324. cirq/ops/pauli_interaction_gate.py +15 -19
  325. cirq/ops/pauli_interaction_gate_test.py +10 -8
  326. cirq/ops/pauli_measurement_gate.py +23 -35
  327. cirq/ops/pauli_measurement_gate_test.py +2 -0
  328. cirq/ops/pauli_string.py +92 -120
  329. cirq/ops/pauli_string_phasor.py +52 -45
  330. cirq/ops/pauli_string_phasor_test.py +4 -5
  331. cirq/ops/pauli_string_raw_types.py +9 -7
  332. cirq/ops/pauli_string_raw_types_test.py +2 -0
  333. cirq/ops/pauli_string_test.py +31 -154
  334. cirq/ops/pauli_sum_exponential.py +12 -12
  335. cirq/ops/pauli_sum_exponential_test.py +12 -10
  336. cirq/ops/permutation_gate.py +8 -6
  337. cirq/ops/permutation_gate_test.py +10 -8
  338. cirq/ops/phased_iswap_gate.py +16 -16
  339. cirq/ops/phased_iswap_gate_test.py +17 -15
  340. cirq/ops/phased_x_gate.py +16 -17
  341. cirq/ops/phased_x_gate_test.py +18 -16
  342. cirq/ops/phased_x_z_gate.py +24 -22
  343. cirq/ops/phased_x_z_gate_test.py +17 -11
  344. cirq/ops/projector.py +16 -11
  345. cirq/ops/projector_test.py +19 -16
  346. cirq/ops/qid_util.py +7 -5
  347. cirq/ops/qid_util_test.py +2 -0
  348. cirq/ops/qubit_manager.py +11 -9
  349. cirq/ops/qubit_manager_test.py +6 -4
  350. cirq/ops/qubit_order.py +11 -14
  351. cirq/ops/qubit_order_or_list.py +4 -2
  352. cirq/ops/qubit_order_test.py +12 -10
  353. cirq/ops/random_gate_channel.py +12 -10
  354. cirq/ops/random_gate_channel_test.py +14 -11
  355. cirq/ops/raw_types.py +109 -129
  356. cirq/ops/raw_types_test.py +63 -57
  357. cirq/ops/state_preparation_channel.py +7 -7
  358. cirq/ops/state_preparation_channel_test.py +11 -9
  359. cirq/ops/swap_gates.py +13 -15
  360. cirq/ops/swap_gates_test.py +19 -17
  361. cirq/ops/tags.py +5 -3
  362. cirq/ops/tags_test.py +4 -2
  363. cirq/ops/three_qubit_gates.py +43 -76
  364. cirq/ops/three_qubit_gates_test.py +19 -17
  365. cirq/ops/two_qubit_diagonal_gate.py +13 -13
  366. cirq/ops/two_qubit_diagonal_gate_test.py +10 -8
  367. cirq/ops/uniform_superposition_gate.py +5 -3
  368. cirq/ops/uniform_superposition_gate_test.py +5 -3
  369. cirq/ops/wait_gate.py +17 -14
  370. cirq/ops/wait_gate_test.py +9 -6
  371. cirq/protocols/__init__.py +0 -3
  372. cirq/protocols/act_on_protocol.py +8 -6
  373. cirq/protocols/act_on_protocol_test.py +15 -12
  374. cirq/protocols/apply_channel_protocol.py +10 -14
  375. cirq/protocols/apply_channel_protocol_test.py +2 -0
  376. cirq/protocols/apply_mixture_protocol.py +13 -42
  377. cirq/protocols/apply_mixture_protocol_test.py +7 -5
  378. cirq/protocols/apply_unitary_protocol.py +39 -34
  379. cirq/protocols/apply_unitary_protocol_test.py +4 -1
  380. cirq/protocols/approximate_equality_protocol.py +2 -0
  381. cirq/protocols/approximate_equality_protocol_test.py +2 -0
  382. cirq/protocols/circuit_diagram_info_protocol.py +58 -42
  383. cirq/protocols/circuit_diagram_info_protocol_test.py +70 -12
  384. cirq/protocols/commutes_protocol.py +8 -7
  385. cirq/protocols/commutes_protocol_test.py +2 -0
  386. cirq/protocols/control_key_protocol.py +6 -4
  387. cirq/protocols/control_key_protocol_test.py +3 -1
  388. cirq/protocols/decompose_protocol.py +49 -48
  389. cirq/protocols/decompose_protocol_test.py +27 -16
  390. cirq/protocols/equal_up_to_global_phase_protocol.py +2 -0
  391. cirq/protocols/equal_up_to_global_phase_protocol_test.py +9 -6
  392. cirq/protocols/has_stabilizer_effect_protocol.py +7 -5
  393. cirq/protocols/has_stabilizer_effect_protocol_test.py +7 -5
  394. cirq/protocols/has_unitary_protocol.py +10 -6
  395. cirq/protocols/has_unitary_protocol_test.py +13 -8
  396. cirq/protocols/hash_from_pickle_test.py +2 -11
  397. cirq/protocols/inverse_protocol.py +13 -16
  398. cirq/protocols/inverse_protocol_test.py +5 -3
  399. cirq/protocols/json_serialization.py +35 -54
  400. cirq/protocols/json_serialization_test.py +14 -21
  401. cirq/protocols/json_test_data/CXSWAP.json +46 -0
  402. cirq/protocols/json_test_data/CXSWAP.repr +13 -0
  403. cirq/protocols/json_test_data/CZSWAP.json +46 -0
  404. cirq/protocols/json_test_data/CZSWAP.repr +13 -0
  405. cirq/protocols/json_test_data/CircuitOperation.json +6 -3
  406. cirq/protocols/json_test_data/CircuitOperation.repr_inward +4 -2
  407. cirq/protocols/json_test_data/Moment.json +24 -1
  408. cirq/protocols/json_test_data/Moment.repr +6 -1
  409. cirq/protocols/json_test_data/ThermalNoiseModel.json +32 -0
  410. cirq/protocols/json_test_data/ThermalNoiseModel.repr +1 -0
  411. cirq/protocols/json_test_data/spec.py +6 -2
  412. cirq/protocols/kraus_protocol.py +47 -7
  413. cirq/protocols/kraus_protocol_test.py +86 -12
  414. cirq/protocols/measurement_key_protocol.py +15 -16
  415. cirq/protocols/measurement_key_protocol_test.py +13 -11
  416. cirq/protocols/mixture_protocol.py +7 -5
  417. cirq/protocols/mixture_protocol_test.py +4 -2
  418. cirq/protocols/mul_protocol.py +2 -3
  419. cirq/protocols/mul_protocol_test.py +2 -0
  420. cirq/protocols/pauli_expansion_protocol.py +6 -3
  421. cirq/protocols/pauli_expansion_protocol_test.py +5 -3
  422. cirq/protocols/phase_protocol.py +2 -0
  423. cirq/protocols/phase_protocol_test.py +3 -1
  424. cirq/protocols/pow_protocol.py +11 -16
  425. cirq/protocols/pow_protocol_test.py +2 -0
  426. cirq/protocols/qasm.py +14 -20
  427. cirq/protocols/qasm_test.py +6 -3
  428. cirq/protocols/qid_shape_protocol.py +8 -8
  429. cirq/protocols/qid_shape_protocol_test.py +3 -1
  430. cirq/protocols/resolve_parameters.py +5 -3
  431. cirq/protocols/resolve_parameters_test.py +8 -7
  432. cirq/protocols/trace_distance_bound.py +6 -4
  433. cirq/protocols/trace_distance_bound_test.py +3 -1
  434. cirq/protocols/unitary_protocol.py +17 -7
  435. cirq/protocols/unitary_protocol_test.py +12 -2
  436. cirq/qis/channels.py +6 -2
  437. cirq/qis/channels_test.py +20 -16
  438. cirq/qis/clifford_tableau.py +21 -19
  439. cirq/qis/clifford_tableau_test.py +2 -2
  440. cirq/qis/entropy.py +14 -3
  441. cirq/qis/entropy_test.py +3 -1
  442. cirq/qis/measures.py +13 -13
  443. cirq/qis/measures_test.py +20 -14
  444. cirq/qis/noise_utils.py +2 -0
  445. cirq/qis/noise_utils_test.py +9 -7
  446. cirq/qis/quantum_state_representation.py +7 -8
  447. cirq/qis/states.py +58 -56
  448. cirq/qis/states_test.py +2 -0
  449. cirq/sim/classical_simulator.py +23 -22
  450. cirq/sim/classical_simulator_test.py +2 -0
  451. cirq/sim/clifford/clifford_simulator.py +23 -21
  452. cirq/sim/clifford/clifford_simulator_test.py +7 -4
  453. cirq/sim/clifford/clifford_tableau_simulation_state.py +10 -7
  454. cirq/sim/clifford/clifford_tableau_simulation_state_test.py +5 -5
  455. cirq/sim/clifford/stabilizer_ch_form_simulation_state.py +8 -6
  456. cirq/sim/clifford/stabilizer_ch_form_simulation_state_test.py +8 -6
  457. cirq/sim/clifford/stabilizer_sampler.py +9 -7
  458. cirq/sim/clifford/stabilizer_sampler_test.py +4 -2
  459. cirq/sim/clifford/stabilizer_simulation_state.py +14 -13
  460. cirq/sim/clifford/stabilizer_simulation_state_test.py +6 -4
  461. cirq/sim/clifford/stabilizer_state_ch_form.py +13 -11
  462. cirq/sim/clifford/stabilizer_state_ch_form_test.py +4 -2
  463. cirq/sim/density_matrix_simulation_state.py +26 -27
  464. cirq/sim/density_matrix_simulation_state_test.py +10 -8
  465. cirq/sim/density_matrix_simulator.py +30 -28
  466. cirq/sim/density_matrix_simulator_test.py +48 -48
  467. cirq/sim/density_matrix_utils.py +13 -11
  468. cirq/sim/density_matrix_utils_test.py +38 -36
  469. cirq/sim/mux.py +33 -31
  470. cirq/sim/mux_test.py +3 -0
  471. cirq/sim/simulation_product_state.py +15 -15
  472. cirq/sim/simulation_product_state_test.py +29 -26
  473. cirq/sim/simulation_state.py +29 -38
  474. cirq/sim/simulation_state_base.py +21 -32
  475. cirq/sim/simulation_state_test.py +15 -13
  476. cirq/sim/simulation_utils.py +5 -2
  477. cirq/sim/simulation_utils_test.py +5 -2
  478. cirq/sim/simulator.py +90 -106
  479. cirq/sim/simulator_base.py +33 -45
  480. cirq/sim/simulator_base_test.py +20 -15
  481. cirq/sim/simulator_test.py +23 -14
  482. cirq/sim/sparse_simulator.py +19 -17
  483. cirq/sim/sparse_simulator_test.py +41 -40
  484. cirq/sim/state_vector.py +15 -12
  485. cirq/sim/state_vector_simulation_state.py +31 -31
  486. cirq/sim/state_vector_simulation_state_test.py +16 -14
  487. cirq/sim/state_vector_simulator.py +17 -14
  488. cirq/sim/state_vector_simulator_test.py +2 -0
  489. cirq/sim/state_vector_test.py +6 -3
  490. cirq/study/flatten_expressions.py +16 -15
  491. cirq/study/flatten_expressions_test.py +13 -11
  492. cirq/study/resolver.py +18 -17
  493. cirq/study/resolver_test.py +22 -20
  494. cirq/study/result.py +17 -27
  495. cirq/study/result_test.py +2 -0
  496. cirq/study/sweepable.py +12 -10
  497. cirq/study/sweepable_test.py +3 -0
  498. cirq/study/sweeps.py +42 -61
  499. cirq/study/sweeps_test.py +33 -0
  500. cirq/testing/__init__.py +7 -11
  501. cirq/testing/_compat_test_data/module_a/__init__.py +1 -0
  502. cirq/testing/_compat_test_data/module_a/module_b/__init__.py +1 -0
  503. cirq/testing/_compat_test_data/module_a/sub/__init__.py +1 -0
  504. cirq/testing/circuit_compare.py +8 -17
  505. cirq/testing/circuit_compare_test.py +2 -0
  506. cirq/testing/consistent_act_on.py +13 -11
  507. cirq/testing/consistent_act_on_test.py +5 -3
  508. cirq/testing/consistent_channels.py +2 -0
  509. cirq/testing/consistent_channels_test.py +10 -8
  510. cirq/testing/consistent_controlled_gate_op.py +5 -5
  511. cirq/testing/consistent_controlled_gate_op_test.py +18 -18
  512. cirq/testing/consistent_decomposition.py +2 -2
  513. cirq/testing/consistent_decomposition_test.py +4 -2
  514. cirq/testing/consistent_pauli_expansion.py +2 -0
  515. cirq/testing/consistent_pauli_expansion_test.py +3 -1
  516. cirq/testing/consistent_phase_by.py +2 -0
  517. cirq/testing/consistent_phase_by_test.py +3 -1
  518. cirq/testing/consistent_protocols.py +14 -20
  519. cirq/testing/consistent_protocols_test.py +13 -11
  520. cirq/testing/consistent_qasm.py +6 -4
  521. cirq/testing/consistent_qasm_test.py +7 -7
  522. cirq/testing/consistent_resolve_parameters.py +2 -0
  523. cirq/testing/consistent_specified_has_unitary.py +2 -2
  524. cirq/testing/consistent_specified_has_unitary_test.py +6 -4
  525. cirq/testing/consistent_unitary.py +1 -0
  526. cirq/testing/consistent_unitary_test.py +4 -2
  527. cirq/testing/deprecation.py +5 -2
  528. cirq/testing/deprecation_test.py +5 -2
  529. cirq/testing/devices.py +7 -4
  530. cirq/testing/devices_test.py +7 -4
  531. cirq/testing/equals_tester.py +4 -2
  532. cirq/testing/equals_tester_test.py +21 -17
  533. cirq/testing/equivalent_basis_map.py +6 -4
  534. cirq/testing/equivalent_basis_map_test.py +6 -4
  535. cirq/testing/equivalent_repr_eval.py +6 -4
  536. cirq/testing/equivalent_repr_eval_test.py +5 -3
  537. cirq/testing/gate_features.py +2 -0
  538. cirq/testing/gate_features_test.py +7 -5
  539. cirq/testing/json.py +19 -15
  540. cirq/testing/json_test.py +5 -3
  541. cirq/testing/lin_alg_utils.py +10 -11
  542. cirq/testing/lin_alg_utils_test.py +14 -12
  543. cirq/testing/logs.py +7 -6
  544. cirq/testing/logs_test.py +9 -7
  545. cirq/testing/no_identifier_qubit.py +4 -2
  546. cirq/testing/no_identifier_qubit_test.py +5 -3
  547. cirq/testing/op_tree.py +2 -0
  548. cirq/testing/op_tree_test.py +4 -1
  549. cirq/testing/order_tester.py +2 -0
  550. cirq/testing/order_tester_test.py +8 -6
  551. cirq/testing/pytest_utils.py +2 -0
  552. cirq/testing/pytest_utils_test.py +4 -2
  553. cirq/testing/random_circuit.py +21 -20
  554. cirq/testing/random_circuit_test.py +12 -9
  555. cirq/testing/repr_pretty_tester.py +1 -0
  556. cirq/testing/repr_pretty_tester_test.py +5 -3
  557. cirq/testing/routing_devices.py +4 -1
  558. cirq/testing/routing_devices_test.py +9 -6
  559. cirq/testing/sample_circuits.py +4 -1
  560. cirq/testing/sample_circuits_test.py +3 -1
  561. cirq/testing/sample_gates.py +3 -0
  562. cirq/testing/sample_gates_test.py +5 -2
  563. cirq/transformers/__init__.py +11 -4
  564. cirq/transformers/align.py +9 -7
  565. cirq/transformers/align_test.py +2 -0
  566. cirq/transformers/analytical_decompositions/__init__.py +3 -6
  567. cirq/transformers/analytical_decompositions/clifford_decomposition.py +18 -16
  568. cirq/transformers/analytical_decompositions/clifford_decomposition_test.py +2 -0
  569. cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +19 -16
  570. cirq/transformers/analytical_decompositions/controlled_gate_decomposition_test.py +2 -0
  571. cirq/transformers/analytical_decompositions/cphase_to_fsim.py +11 -9
  572. cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +5 -3
  573. cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +5 -3
  574. cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +5 -3
  575. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +141 -44
  576. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +35 -1
  577. cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +8 -7
  578. cirq/transformers/analytical_decompositions/single_qubit_decompositions_test.py +2 -0
  579. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry.py +7 -4
  580. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry_test.py +3 -0
  581. cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +11 -19
  582. cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +8 -33
  583. cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +9 -11
  584. cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +2 -0
  585. cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +91 -27
  586. cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +36 -7
  587. cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +20 -21
  588. cirq/transformers/analytical_decompositions/two_qubit_to_fsim_test.py +8 -6
  589. cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +13 -15
  590. cirq/transformers/analytical_decompositions/two_qubit_to_ms_test.py +3 -1
  591. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +39 -41
  592. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap_test.py +2 -0
  593. cirq/transformers/drop_empty_moments.py +5 -3
  594. cirq/transformers/drop_empty_moments_test.py +4 -2
  595. cirq/transformers/drop_negligible_operations.py +7 -5
  596. cirq/transformers/drop_negligible_operations_test.py +2 -0
  597. cirq/transformers/dynamical_decoupling.py +49 -42
  598. cirq/transformers/dynamical_decoupling_test.py +223 -205
  599. cirq/transformers/eject_phased_paulis.py +28 -26
  600. cirq/transformers/eject_phased_paulis_test.py +12 -9
  601. cirq/transformers/eject_z.py +12 -12
  602. cirq/transformers/eject_z_test.py +2 -2
  603. cirq/transformers/expand_composite.py +6 -4
  604. cirq/transformers/expand_composite_test.py +3 -1
  605. cirq/transformers/gauge_compiling/__init__.py +3 -1
  606. cirq/transformers/gauge_compiling/cphase_gauge.py +2 -0
  607. cirq/transformers/gauge_compiling/cphase_gauge_test.py +2 -0
  608. cirq/transformers/gauge_compiling/cz_gauge.py +2 -0
  609. cirq/transformers/gauge_compiling/cz_gauge_test.py +1 -0
  610. cirq/transformers/gauge_compiling/gauge_compiling.py +45 -41
  611. cirq/transformers/gauge_compiling/gauge_compiling_test.py +2 -0
  612. cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +1 -0
  613. cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +5 -1
  614. cirq/transformers/gauge_compiling/iswap_gauge.py +2 -0
  615. cirq/transformers/gauge_compiling/iswap_gauge_test.py +1 -0
  616. cirq/transformers/gauge_compiling/spin_inversion_gauge.py +2 -0
  617. cirq/transformers/gauge_compiling/spin_inversion_gauge_test.py +2 -0
  618. cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +7 -6
  619. cirq/transformers/gauge_compiling/sqrt_cz_gauge_test.py +2 -0
  620. cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +2 -0
  621. cirq/transformers/gauge_compiling/sqrt_iswap_gauge_test.py +2 -0
  622. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +6 -3
  623. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils_test.py +3 -0
  624. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +12 -9
  625. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation_test.py +9 -7
  626. cirq/transformers/insertion_sort.py +8 -6
  627. cirq/transformers/insertion_sort_test.py +3 -1
  628. cirq/transformers/measurement_transformers.py +29 -29
  629. cirq/transformers/measurement_transformers_test.py +2 -0
  630. cirq/transformers/merge_k_qubit_gates.py +12 -10
  631. cirq/transformers/merge_k_qubit_gates_test.py +18 -18
  632. cirq/transformers/merge_single_qubit_gates.py +197 -20
  633. cirq/transformers/merge_single_qubit_gates_test.py +177 -5
  634. cirq/transformers/noise_adding.py +5 -3
  635. cirq/transformers/noise_adding_test.py +2 -0
  636. cirq/transformers/optimize_for_target_gateset.py +19 -17
  637. cirq/transformers/optimize_for_target_gateset_test.py +11 -8
  638. cirq/transformers/qubit_management_transformers.py +13 -11
  639. cirq/transformers/qubit_management_transformers_test.py +5 -3
  640. cirq/transformers/randomized_measurements.py +16 -14
  641. cirq/transformers/randomized_measurements_test.py +10 -4
  642. cirq/transformers/routing/initial_mapper.py +6 -4
  643. cirq/transformers/routing/initial_mapper_test.py +2 -0
  644. cirq/transformers/routing/line_initial_mapper.py +16 -14
  645. cirq/transformers/routing/line_initial_mapper_test.py +9 -7
  646. cirq/transformers/routing/mapping_manager.py +10 -10
  647. cirq/transformers/routing/mapping_manager_test.py +2 -0
  648. cirq/transformers/routing/route_circuit_cqc.py +33 -31
  649. cirq/transformers/routing/route_circuit_cqc_test.py +15 -13
  650. cirq/transformers/routing/visualize_routed_circuit.py +8 -7
  651. cirq/transformers/routing/visualize_routed_circuit_test.py +4 -2
  652. cirq/transformers/stratify.py +17 -15
  653. cirq/transformers/stratify_test.py +3 -0
  654. cirq/transformers/symbolize.py +103 -0
  655. cirq/transformers/symbolize_test.py +62 -0
  656. cirq/transformers/synchronize_terminal_measurements.py +10 -10
  657. cirq/transformers/synchronize_terminal_measurements_test.py +12 -10
  658. cirq/transformers/tag_transformers.py +97 -0
  659. cirq/transformers/tag_transformers_test.py +103 -0
  660. cirq/transformers/target_gatesets/compilation_target_gateset.py +21 -19
  661. cirq/transformers/target_gatesets/compilation_target_gateset_test.py +20 -16
  662. cirq/transformers/target_gatesets/cz_gateset.py +7 -5
  663. cirq/transformers/target_gatesets/cz_gateset_test.py +21 -19
  664. cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +9 -7
  665. cirq/transformers/target_gatesets/sqrt_iswap_gateset_test.py +25 -25
  666. cirq/transformers/transformer_api.py +34 -47
  667. cirq/transformers/transformer_api_test.py +9 -8
  668. cirq/transformers/transformer_primitives.py +39 -49
  669. cirq/transformers/transformer_primitives_test.py +10 -17
  670. cirq/value/abc_alt.py +6 -4
  671. cirq/value/abc_alt_test.py +5 -3
  672. cirq/value/angle.py +11 -12
  673. cirq/value/angle_test.py +5 -3
  674. cirq/value/classical_data.py +27 -27
  675. cirq/value/classical_data_test.py +11 -8
  676. cirq/value/condition.py +26 -24
  677. cirq/value/condition_test.py +2 -0
  678. cirq/value/digits.py +14 -11
  679. cirq/value/digits_test.py +2 -0
  680. cirq/value/duration.py +23 -20
  681. cirq/value/duration_test.py +2 -0
  682. cirq/value/linear_dict.py +25 -30
  683. cirq/value/linear_dict_test.py +10 -8
  684. cirq/value/measurement_key.py +12 -12
  685. cirq/value/measurement_key_test.py +2 -0
  686. cirq/value/periodic_value.py +4 -4
  687. cirq/value/periodic_value_test.py +11 -7
  688. cirq/value/probability.py +3 -1
  689. cirq/value/probability_test.py +4 -2
  690. cirq/value/product_state.py +15 -13
  691. cirq/value/product_state_test.py +4 -1
  692. cirq/value/random_state.py +2 -0
  693. cirq/value/random_state_test.py +5 -3
  694. cirq/value/timestamp.py +11 -7
  695. cirq/value/timestamp_test.py +14 -12
  696. cirq/value/type_alias.py +4 -4
  697. cirq/value/value_equality_attr.py +8 -9
  698. cirq/value/value_equality_attr_test.py +14 -11
  699. cirq/vis/density_matrix.py +3 -3
  700. cirq/vis/density_matrix_test.py +20 -17
  701. cirq/vis/heatmap.py +24 -37
  702. cirq/vis/heatmap_test.py +3 -0
  703. cirq/vis/histogram.py +9 -6
  704. cirq/vis/histogram_test.py +5 -2
  705. cirq/vis/state_histogram.py +10 -8
  706. cirq/vis/state_histogram_test.py +7 -5
  707. cirq/vis/vis_utils.py +4 -1
  708. cirq/vis/vis_utils_test.py +4 -1
  709. cirq/work/collector.py +12 -18
  710. cirq/work/collector_test.py +15 -10
  711. cirq/work/observable_grouping.py +6 -7
  712. cirq/work/observable_grouping_test.py +10 -9
  713. cirq/work/observable_measurement.py +47 -45
  714. cirq/work/observable_measurement_data.py +22 -17
  715. cirq/work/observable_measurement_data_test.py +4 -1
  716. cirq/work/observable_measurement_test.py +48 -29
  717. cirq/work/observable_readout_calibration.py +5 -2
  718. cirq/work/observable_readout_calibration_test.py +5 -2
  719. cirq/work/observable_settings.py +13 -22
  720. cirq/work/observable_settings_test.py +9 -7
  721. cirq/work/pauli_sum_collector.py +12 -10
  722. cirq/work/pauli_sum_collector_test.py +9 -9
  723. cirq/work/sampler.py +42 -43
  724. cirq/work/sampler_test.py +31 -24
  725. cirq/work/zeros_sampler.py +6 -4
  726. cirq/work/zeros_sampler_test.py +7 -5
  727. {cirq_core-1.5.0.dev20250409225226.dist-info → cirq_core-1.6.0.dist-info}/METADATA +7 -8
  728. cirq_core-1.6.0.dist-info/RECORD +1241 -0
  729. {cirq_core-1.5.0.dev20250409225226.dist-info → cirq_core-1.6.0.dist-info}/WHEEL +1 -1
  730. cirq_core-1.5.0.dev20250409225226.dist-info/RECORD +0 -1216
  731. {cirq_core-1.5.0.dev20250409225226.dist-info → cirq_core-1.6.0.dist-info}/licenses/LICENSE +0 -0
  732. {cirq_core-1.5.0.dev20250409225226.dist-info → cirq_core-1.6.0.dist-info}/top_level.txt +0 -0
@@ -12,36 +12,43 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
-
16
15
  """Utility methods for decomposing arbitrary n-qubit (2^n x 2^n) unitary.
17
16
 
18
17
  Based on:
19
18
  Synthesis of Quantum Logic Circuits. Tech. rep. 2006,
20
19
  https://arxiv.org/abs/quant-ph/0406176
21
20
  """
22
- from typing import Callable, Iterable, List, TYPE_CHECKING
21
+
22
+ from __future__ import annotations
23
+
24
+ from typing import Callable, cast, Iterable, TYPE_CHECKING
23
25
 
24
26
  import numpy as np
27
+ from attr import define
25
28
  from scipy.linalg import cossin
26
29
 
27
30
  from cirq import ops
28
31
  from cirq.circuits.frozen_circuit import FrozenCircuit
29
32
  from cirq.linalg import decompositions, predicates
30
33
  from cirq.protocols import unitary_protocol
31
- from cirq.transformers.analytical_decompositions.three_qubit_decomposition import (
32
- three_qubit_matrix_to_operations,
33
- )
34
34
  from cirq.transformers.analytical_decompositions.two_qubit_to_cz import (
35
35
  two_qubit_matrix_to_cz_operations,
36
+ two_qubit_matrix_to_diagonal_and_cz_operations,
36
37
  )
37
38
 
38
39
  if TYPE_CHECKING:
39
40
  import cirq
40
41
 
41
42
 
43
+ @define
44
+ class _TwoQubitGate:
45
+ location: int
46
+ matrix: np.ndarray
47
+
48
+
42
49
  def quantum_shannon_decomposition(
43
- qubits: 'List[cirq.Qid]', u: np.ndarray, atol: float = 1e-8
44
- ) -> Iterable['cirq.Operation']:
50
+ qubits: list[cirq.Qid], u: np.ndarray, atol: float = 1e-8
51
+ ) -> Iterable[cirq.Operation]:
45
52
  """Decomposes n-qubit unitary 1-q, 2-q and GlobalPhase gates, preserving global phase.
46
53
 
47
54
  The gates used are CX/YPow/ZPow/CNOT/GlobalPhase/CZ/PhasedXZGate/PhasedXPowGate.
@@ -65,14 +72,12 @@ def quantum_shannon_decomposition(
65
72
  1. _single_qubit_decomposition
66
73
  OR
67
74
  (Recursive Case)
68
- 1. _msb_demuxer
69
- 2. _multiplexed_cossin
70
- 3. _msb_demuxer
75
+ 1. _recursive_decomposition
71
76
 
72
77
  Yields:
73
78
  A single 2-qubit or 1-qubit operations from OP TREE
74
79
  composed from the set
75
- { CNOT, rz, ry, ZPowGate }
80
+ { CNOT, CZ, rz, ry, ZPowGate }
76
81
 
77
82
  Raises:
78
83
  ValueError: If the u matrix is non-unitary
@@ -96,30 +101,92 @@ def quantum_shannon_decomposition(
96
101
  yield from _single_qubit_decomposition(qubits[0], u)
97
102
  return
98
103
 
99
- if n == 4:
100
- operations = tuple(
101
- two_qubit_matrix_to_cz_operations(
102
- qubits[0], qubits[1], u, allow_partial_czs=True, clean_operations=True, atol=atol
103
- )
104
+ # Collect all operations from the recursive decomposition
105
+ shannon_decomp: list[cirq.Operation | list[cirq.Operation]] = [
106
+ *_recursive_decomposition(qubits, u)
107
+ ]
108
+ # Separate all 2-qubit generic gates while keeping track of location
109
+ two_qubit_gates = [
110
+ _TwoQubitGate(location=loc, matrix=unitary_protocol.unitary(o))
111
+ for loc, o in enumerate(cast(list[ops.Operation], shannon_decomp))
112
+ if isinstance(o.gate, ops.MatrixGate)
113
+ ]
114
+ # Apply case A.2 from Shende et al.
115
+ q0 = qubits[-2]
116
+ q1 = qubits[-1]
117
+ for idx in range(len(two_qubit_gates) - 1, 0, -1):
118
+ diagonal, operations = two_qubit_matrix_to_diagonal_and_cz_operations(
119
+ q0,
120
+ q1,
121
+ two_qubit_gates[idx].matrix,
122
+ allow_partial_czs=True,
123
+ clean_operations=True,
124
+ atol=atol,
104
125
  )
105
- yield from operations
106
- i, j = np.unravel_index(np.argmax(np.abs(u)), u.shape)
107
- new_unitary = unitary_protocol.unitary(FrozenCircuit.from_moments(*operations))
108
- global_phase = np.angle(u[i, j]) - np.angle(new_unitary[i, j])
109
- if np.abs(global_phase) > 1e-9:
110
- yield ops.global_phase_operation(np.exp(1j * global_phase))
111
- return
126
+ global_phase = _global_phase_difference(
127
+ two_qubit_gates[idx].matrix, [ops.MatrixGate(diagonal)(q0, q1), *operations]
128
+ )
129
+ if not np.isclose(global_phase, 0, atol=atol):
130
+ operations.append(ops.global_phase_operation(np.exp(1j * global_phase)))
131
+ # Replace the generic gate with ops from OP TREE
132
+ shannon_decomp[two_qubit_gates[idx].location] = operations
133
+ # Join the diagonal with the unitary to be decomposed in the next step
134
+ two_qubit_gates[idx - 1].matrix = diagonal @ two_qubit_gates[idx - 1].matrix
135
+ if len(two_qubit_gates) > 0:
136
+ operations = two_qubit_matrix_to_cz_operations(
137
+ q0,
138
+ q1,
139
+ two_qubit_gates[0].matrix,
140
+ allow_partial_czs=True,
141
+ clean_operations=True,
142
+ atol=atol,
143
+ )
144
+ global_phase = _global_phase_difference(two_qubit_gates[0].matrix, operations)
145
+ if not np.isclose(global_phase, 0, atol=atol):
146
+ operations.append(ops.global_phase_operation(np.exp(1j * global_phase)))
147
+ shannon_decomp[two_qubit_gates[0].location] = operations
148
+ # Yield the final operations in order
149
+ yield from cast(Iterable[ops.Operation], ops.flatten_op_tree(shannon_decomp))
150
+
151
+
152
+ def _recursive_decomposition(qubits: list[cirq.Qid], u: np.ndarray) -> Iterable[cirq.Operation]:
153
+ """Recursive step in the quantum shannon decomposition.
112
154
 
113
- if n == 8:
114
- operations = tuple(
115
- three_qubit_matrix_to_operations(qubits[0], qubits[1], qubits[2], u, atol=atol)
155
+ Decomposes n-qubit unitary into generic 2-qubit gates, CNOT, CZ and 1-qubit gates.
156
+ All generic 2-qubit gates are applied to the two least significant qubits and
157
+ are not decomposed further here.
158
+
159
+ Args:
160
+ qubits: List of qubits in order of significance
161
+ u: Numpy array for unitary matrix representing gate to be decomposed
162
+
163
+ Calls:
164
+ 1. _msb_demuxer
165
+ 2. _multiplexed_cossin
166
+ 3. _msb_demuxer
167
+
168
+ Yields:
169
+ Generic 2-qubit gates or operations from {ry,rz,CNOT,CZ}.
170
+
171
+ Raises:
172
+ ValueError: If the u matrix is not of shape (2^n,2^n)
173
+ ValueError: If the u matrix is not of size at least 4
174
+ """
175
+ n = u.shape[0]
176
+ if n & (n - 1):
177
+ raise ValueError(
178
+ f"Expected input matrix u to be a (2^n x 2^n) shaped numpy array, \
179
+ but instead got shape {u.shape}"
180
+ )
181
+
182
+ if n <= 2:
183
+ raise ValueError(
184
+ f"Expected input matrix u for recursive step to have size at least 4, \
185
+ but it has size {n}"
116
186
  )
117
- yield from operations
118
- i, j = np.unravel_index(np.argmax(np.abs(u)), u.shape)
119
- new_unitary = unitary_protocol.unitary(FrozenCircuit.from_moments(*operations))
120
- global_phase = np.angle(u[i, j]) - np.angle(new_unitary[i, j])
121
- if np.abs(global_phase) > 1e-9:
122
- yield ops.global_phase_operation(np.exp(1j * global_phase))
187
+
188
+ if n == 4:
189
+ yield ops.MatrixGate(u).on(*qubits)
123
190
  return
124
191
 
125
192
  # Perform a cosine-sine (linalg) decomposition on u
@@ -135,11 +202,31 @@ def quantum_shannon_decomposition(
135
202
  # Yield ops from multiplexed Ry part
136
203
  yield from _multiplexed_cossin(qubits, theta, ops.ry)
137
204
 
205
+ # Optimization A.1 in Shende et al. - the last CZ gate in the multiplexed Ry part
206
+ # is merged into the generic multiplexor (u1, u2)
207
+ # This gate is CZ(qubits[1], qubits[0]) = CZ(qubits[0], qubits[1])
208
+ # as CZ is symmetric.
209
+ # For the u1⊕u2 multiplexor operator:
210
+ # as u1 is the operator in case qubits[0] = |0>,
211
+ # and u2 is the operator in case qubits[0] = |1>
212
+ # we can represent the merge by phasing u2 with Z ⊗ I
213
+ cz_diag = np.concatenate((np.ones(n >> 2), np.full(n >> 2, -1)))
214
+ u2 = u2 @ np.diag(cz_diag)
215
+
138
216
  # Yield ops from decomposition of multiplexed u1/u2 part
139
217
  yield from _msb_demuxer(qubits, u1, u2)
140
218
 
141
219
 
142
- def _single_qubit_decomposition(qubit: 'cirq.Qid', u: np.ndarray) -> Iterable['cirq.Operation']:
220
+ def _global_phase_difference(u: np.ndarray, ops: list[cirq.Operation]) -> float:
221
+ """Returns the difference in global phase between unitary u and
222
+ a list of operations computing u.
223
+ """
224
+ i, j = np.unravel_index(np.argmax(np.abs(u)), u.shape)
225
+ new_unitary = unitary_protocol.unitary(FrozenCircuit.from_moments(*ops))
226
+ return np.angle(u[i, j]) - np.angle(new_unitary[i, j])
227
+
228
+
229
+ def _single_qubit_decomposition(qubit: cirq.Qid, u: np.ndarray) -> Iterable[cirq.Operation]:
143
230
  """Decomposes single-qubit gate, and returns list of operations, keeping phase invariant.
144
231
 
145
232
  Args:
@@ -183,8 +270,8 @@ def _single_qubit_decomposition(qubit: 'cirq.Qid', u: np.ndarray) -> Iterable['c
183
270
 
184
271
 
185
272
  def _msb_demuxer(
186
- demux_qubits: 'List[cirq.Qid]', u1: np.ndarray, u2: np.ndarray
187
- ) -> Iterable['cirq.Operation']:
273
+ demux_qubits: list[cirq.Qid], u1: np.ndarray, u2: np.ndarray
274
+ ) -> Iterable[cirq.Operation]:
188
275
  """Demultiplexes a unitary matrix that is multiplexed in its most-significant-qubit.
189
276
 
190
277
  Decomposition structure:
@@ -200,11 +287,14 @@ def _msb_demuxer(
200
287
  u2: Lower-right quadrant of total unitary to be decomposed (see diagram)
201
288
 
202
289
  Calls:
203
- 1. quantum_shannon_decomposition
290
+ 1. _recursive_decomposition
204
291
  2. _multiplexed_cossin
205
- 3. quantum_shannon_decomposition
292
+ 3. _recursive_decomposition
206
293
 
207
- Yields: Single operation from OP TREE of 2-qubit and 1-qubit operations
294
+ Yields:
295
+ Generic 2-qubit gates on the two least significant qubits,
296
+ CNOT gates with the target not on the two least significant qubits,
297
+ ry or rz
208
298
  """
209
299
  # Perform a diagonalization to find values
210
300
  u1 = u1.astype(np.complex128)
@@ -229,7 +319,7 @@ def _msb_demuxer(
229
319
  # Last term is given by ( I ⊗ W ), demultiplexed
230
320
  # Remove most-significant (demuxed) control-qubit
231
321
  # Yield operations for QSD on W
232
- yield from quantum_shannon_decomposition(demux_qubits[1:], W, atol=1e-6)
322
+ yield from _recursive_decomposition(demux_qubits[1:], W)
233
323
 
234
324
  # Use complex phase of d_i to give theta_i (so d_i* gives -theta_i)
235
325
  # Observe that middle part looks like Σ_i( Rz(theta_i)⊗|i><i| )
@@ -237,7 +327,7 @@ def _msb_demuxer(
237
327
  yield from _multiplexed_cossin(demux_qubits, -np.angle(d), ops.rz)
238
328
 
239
329
  # Yield operations for QSD on V
240
- yield from quantum_shannon_decomposition(demux_qubits[1:], V, atol=1e-6)
330
+ yield from _recursive_decomposition(demux_qubits[1:], V)
241
331
 
242
332
 
243
333
  def _nth_gray(n: int) -> int:
@@ -246,8 +336,8 @@ def _nth_gray(n: int) -> int:
246
336
 
247
337
 
248
338
  def _multiplexed_cossin(
249
- cossin_qubits: 'List[cirq.Qid]', angles: List[float], rot_func: Callable = ops.ry
250
- ) -> Iterable['cirq.Operation']:
339
+ cossin_qubits: list[cirq.Qid], angles: list[float], rot_func: Callable = ops.ry
340
+ ) -> Iterable[cirq.Operation]:
251
341
  """Performs a multiplexed rotation over all qubits in this unitary matrix,
252
342
 
253
343
  Uses ry and rz multiplexing for quantum shannon decomposition
@@ -261,7 +351,7 @@ def _multiplexed_cossin(
261
351
  Calls:
262
352
  No major calls
263
353
 
264
- Yields: Single operation from OP TREE from set 1- and 2-qubit gates: {ry,rz,CNOT}
354
+ Yields: Single operation from OP TREE from set 1- and 2-qubit gates: {ry,rz,CNOT,CZ}
265
355
  """
266
356
  # Most significant qubit is main qubit with rotation function applied
267
357
  main_qubit = cossin_qubits[0]
@@ -302,4 +392,11 @@ def _multiplexed_cossin(
302
392
  yield rot_func(rotation).on(main_qubit)
303
393
 
304
394
  # Add a CNOT from the select qubit to the main qubit
305
- yield ops.CNOT(control_qubits[select_qubit], main_qubit)
395
+ # Optimization A.1 in Shende et al. - use CZ instead of CNOT for ry rotations
396
+ if rot_func == ops.ry:
397
+ # Don't emit the last gate, as it will be merged into the generic multiplexor
398
+ # in the cosine-sine decomposition
399
+ if j < len(angles) - 1:
400
+ yield ops.CZ(control_qubits[select_qubit], main_qubit)
401
+ else:
402
+ yield ops.CNOT(control_qubits[select_qubit], main_qubit)
@@ -12,16 +12,20 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  import numpy as np
16
18
  import pytest
17
19
  from scipy.stats import unitary_group
18
20
 
19
21
  import cirq
20
22
  from cirq.ops import common_gates
23
+ from cirq.testing import random_two_qubit_circuit_with_czs
21
24
  from cirq.transformers.analytical_decompositions.quantum_shannon_decomposition import (
22
25
  _msb_demuxer,
23
26
  _multiplexed_cossin,
24
27
  _nth_gray,
28
+ _recursive_decomposition,
25
29
  _single_qubit_decomposition,
26
30
  quantum_shannon_decomposition,
27
31
  )
@@ -47,6 +51,14 @@ def test_qsd_n_qubit_errors():
47
51
  cirq.Circuit(quantum_shannon_decomposition(qubits, np.ones((8, 8))))
48
52
 
49
53
 
54
+ def test_recursive_decomposition_n_qubit_errors():
55
+ qubits = [cirq.NamedQubit(f'q{i}') for i in range(3)]
56
+ with pytest.raises(ValueError, match="shaped numpy array"):
57
+ cirq.Circuit(_recursive_decomposition(qubits, np.eye(9)))
58
+ with pytest.raises(ValueError, match="size at least 4"):
59
+ cirq.Circuit(_recursive_decomposition(qubits, np.eye(2)))
60
+
61
+
50
62
  def test_random_single_qubit_decomposition():
51
63
  U = unitary_group.rvs(2)
52
64
  qubit = cirq.NamedQubit('q0')
@@ -78,10 +90,18 @@ def test_multiplexed_cossin():
78
90
  multiplexed_ry = np.array(multiplexed_ry)
79
91
  qubits = [cirq.NamedQubit(f'q{i}') for i in range(2)]
80
92
  circuit = cirq.Circuit(_multiplexed_cossin(qubits, [angle_1, angle_2]))
93
+ # Add back the CZ gate removed by the A.1 optimization
94
+ circuit += cirq.CZ(qubits[1], qubits[0])
81
95
  # Test return is equal to inital unitary
82
96
  assert cirq.approx_eq(multiplexed_ry, circuit.unitary(), atol=1e-9)
83
97
  # Test all operations in gate set
84
- gates = (common_gates.Rz, common_gates.Ry, common_gates.ZPowGate, common_gates.CXPowGate)
98
+ gates = (
99
+ common_gates.Rz,
100
+ common_gates.Ry,
101
+ common_gates.ZPowGate,
102
+ common_gates.CXPowGate,
103
+ common_gates.CZPowGate,
104
+ )
85
105
  assert all(isinstance(op.gate, gates) for op in circuit.all_operations())
86
106
 
87
107
 
@@ -201,3 +221,17 @@ def test_qft5():
201
221
  )
202
222
  new_unitary = cirq.unitary(shannon_circuit)
203
223
  np.testing.assert_allclose(new_unitary, desired_unitary, atol=1e-6)
224
+
225
+
226
+ def test_random_circuit_decomposition():
227
+ qubits = cirq.LineQubit.range(3)
228
+ test_circuit = (
229
+ random_two_qubit_circuit_with_czs(3, qubits[0], qubits[1])
230
+ + random_two_qubit_circuit_with_czs(3, qubits[1], qubits[2])
231
+ + random_two_qubit_circuit_with_czs(3, qubits[0], qubits[2])
232
+ )
233
+ circuit = cirq.Circuit(quantum_shannon_decomposition(qubits, test_circuit.unitary()))
234
+ # Test return is equal to initial unitary
235
+ assert cirq.approx_eq(test_circuit.unitary(), circuit.unitary(), atol=1e-9)
236
+ # Test all operations have at most 2 qubits.
237
+ assert all(cirq.num_qubits(op) <= 2 for op in circuit.all_operations())
@@ -14,8 +14,9 @@
14
14
 
15
15
  """Utility methods related to optimizing quantum circuits."""
16
16
 
17
+ from __future__ import annotations
18
+
17
19
  import math
18
- from typing import List, Optional, Tuple
19
20
 
20
21
  import numpy as np
21
22
  import sympy
@@ -39,7 +40,7 @@ def _signed_mod_1(x: float) -> float:
39
40
 
40
41
  def single_qubit_matrix_to_pauli_rotations(
41
42
  mat: np.ndarray, atol: float = 0
42
- ) -> List[Tuple[ops.Pauli, float]]:
43
+ ) -> list[tuple[ops.Pauli, float]]:
43
44
  """Implements a single-qubit operation with few rotations.
44
45
 
45
46
  Args:
@@ -98,7 +99,7 @@ def single_qubit_matrix_to_pauli_rotations(
98
99
  return [(pauli, ht) for pauli, ht in rotation_list if not is_no_turn(ht)]
99
100
 
100
101
 
101
- def single_qubit_matrix_to_gates(mat: np.ndarray, tolerance: float = 0) -> List[ops.Gate]:
102
+ def single_qubit_matrix_to_gates(mat: np.ndarray, tolerance: float = 0) -> list[ops.Gate]:
102
103
  """Implements a single-qubit operation with few gates.
103
104
 
104
105
  Args:
@@ -114,7 +115,7 @@ def single_qubit_matrix_to_gates(mat: np.ndarray, tolerance: float = 0) -> List[
114
115
  return [pauli**ht for pauli, ht in rotations]
115
116
 
116
117
 
117
- def single_qubit_op_to_framed_phase_form(mat: np.ndarray) -> Tuple[np.ndarray, complex, complex]:
118
+ def single_qubit_op_to_framed_phase_form(mat: np.ndarray) -> tuple[np.ndarray, complex, complex]:
118
119
  """Decomposes a 2x2 unitary M into U^-1 * diag(1, r) * U * diag(g, g).
119
120
 
120
121
  U translates the rotation axis of M to the Z axis.
@@ -141,7 +142,7 @@ def single_qubit_op_to_framed_phase_form(mat: np.ndarray) -> Tuple[np.ndarray, c
141
142
  return u, r, g
142
143
 
143
144
 
144
- def _deconstruct_single_qubit_matrix_into_gate_turns(mat: np.ndarray) -> Tuple[float, float, float]:
145
+ def _deconstruct_single_qubit_matrix_into_gate_turns(mat: np.ndarray) -> tuple[float, float, float]:
145
146
  """Breaks down a 2x2 unitary into gate parameters.
146
147
 
147
148
  Args:
@@ -165,7 +166,7 @@ def _deconstruct_single_qubit_matrix_into_gate_turns(mat: np.ndarray) -> Tuple[f
165
166
  return (_signed_mod_1(xy_turn), _signed_mod_1(xy_phase_turn), _signed_mod_1(total_z_turn))
166
167
 
167
168
 
168
- def single_qubit_matrix_to_phased_x_z(mat: np.ndarray, atol: float = 0) -> List[ops.Gate]:
169
+ def single_qubit_matrix_to_phased_x_z(mat: np.ndarray, atol: float = 0) -> list[ops.Gate]:
169
170
  """Implements a single-qubit operation with a PhasedX and Z gate.
170
171
 
171
172
  If one of the gates isn't needed, it will be omitted.
@@ -196,7 +197,7 @@ def single_qubit_matrix_to_phased_x_z(mat: np.ndarray, atol: float = 0) -> List[
196
197
  return result
197
198
 
198
199
 
199
- def single_qubit_matrix_to_phxz(mat: np.ndarray, atol: float = 0) -> Optional[ops.PhasedXZGate]:
200
+ def single_qubit_matrix_to_phxz(mat: np.ndarray, atol: float = 0) -> ops.PhasedXZGate | None:
200
201
  """Implements a single-qubit operation with a PhasedXZ gate.
201
202
 
202
203
  Under the hood, this uses deconstruct_single_qubit_matrix_into_angles which
@@ -12,6 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from __future__ import annotations
16
+
15
17
  import random
16
18
  from typing import Sequence
17
19
 
@@ -13,7 +13,10 @@
13
13
  # limitations under the License.
14
14
 
15
15
  """Analytical decompositions for 2-qubit unitaries when one input qubit is in the |0> state."""
16
- from typing import List, TYPE_CHECKING
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import TYPE_CHECKING
17
20
 
18
21
  import numpy as np
19
22
 
@@ -25,13 +28,13 @@ if TYPE_CHECKING:
25
28
 
26
29
 
27
30
  def two_qubit_matrix_to_cz_isometry(
28
- q0: 'cirq.Qid',
29
- q1: 'cirq.Qid',
31
+ q0: cirq.Qid,
32
+ q1: cirq.Qid,
30
33
  mat: np.ndarray,
31
34
  allow_partial_czs: bool = False,
32
35
  atol: float = 1e-8,
33
36
  clean_operations: bool = True,
34
- ) -> List['cirq.Operation']:
37
+ ) -> list[cirq.Operation]:
35
38
  """Decomposes a 2q operation into at-most 2 CZs + 1q rotations; assuming `q0` is initially |0>.
36
39
 
37
40
  The method implements isometry from one to two qubits; assuming qubit `q0` is always in the |0>
@@ -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 numpy as np
15
18
  import pytest
16
19
 
@@ -14,9 +14,12 @@
14
14
 
15
15
  """Utility methods for decomposing three-qubit unitaries."""
16
16
 
17
- from typing import List, Optional, Sequence, Tuple, Union
17
+ from __future__ import annotations
18
+
19
+ from typing import Sequence
18
20
 
19
21
  import numpy as np
22
+ import scipy.linalg
20
23
 
21
24
  import cirq
22
25
  from cirq import ops, transformers as opt
@@ -24,7 +27,7 @@ from cirq import ops, transformers as opt
24
27
 
25
28
  def three_qubit_matrix_to_operations(
26
29
  q0: ops.Qid, q1: ops.Qid, q2: ops.Qid, u: np.ndarray, atol: float = 1e-8
27
- ) -> List[ops.Operation]:
30
+ ) -> list[ops.Operation]:
28
31
  """Returns operations for a 3 qubit unitary.
29
32
 
30
33
  The algorithm is described in Shende et al.:
@@ -45,24 +48,13 @@ def three_qubit_matrix_to_operations(
45
48
 
46
49
  Raises:
47
50
  ValueError: If the u matrix is non-unitary or not of shape (8,8).
48
- ImportError: If the decomposition cannot be done because the SciPy version is less than
49
- 1.5.0 and so does not contain the required `cossin` method.
50
51
  """
51
52
  if np.shape(u) != (8, 8):
52
53
  raise ValueError(f"Expected unitary matrix with shape (8,8) got {np.shape(u)}")
53
54
  if not cirq.is_unitary(u, atol=atol):
54
55
  raise ValueError(f"Matrix is not unitary: {u}")
55
56
 
56
- try:
57
- from scipy.linalg import cossin
58
- except ImportError: # pragma: no cover
59
- raise ImportError(
60
- "cirq.three_qubit_unitary_to_operations requires "
61
- "SciPy 1.5.0+, as it uses the cossin function. Please"
62
- " upgrade scipy in your environment to use this "
63
- "function!"
64
- )
65
- (u1, u2), theta, (v1h, v2h) = cossin(u, 4, 4, separate=True)
57
+ (u1, u2), theta, (v1h, v2h) = scipy.linalg.cossin(u, 4, 4, separate=True)
66
58
 
67
59
  cs_ops = _cs_to_ops(q0, q1, q2, theta)
68
60
  if len(cs_ops) > 0 and cs_ops[-1] == cirq.CZ(q2, q0):
@@ -85,7 +77,7 @@ def three_qubit_matrix_to_operations(
85
77
  return list(cirq.Circuit(vdh_ops + cs_ops + ud_ops).all_operations())
86
78
 
87
79
 
88
- def _cs_to_ops(q0: ops.Qid, q1: ops.Qid, q2: ops.Qid, theta: np.ndarray) -> List[ops.Operation]:
80
+ def _cs_to_ops(q0: ops.Qid, q1: ops.Qid, q2: ops.Qid, theta: np.ndarray) -> list[ops.Operation]:
89
81
  """Converts theta angles based Cosine Sine matrix to operations.
90
82
 
91
83
  Using the optimization as per Appendix A.1, it uses CZ gates instead of
@@ -124,9 +116,9 @@ def _two_qubit_multiplexor_to_ops(
124
116
  u1: np.ndarray,
125
117
  u2: np.ndarray,
126
118
  shift_left: bool = True,
127
- diagonal: Optional[np.ndarray] = None,
119
+ diagonal: np.ndarray | None = None,
128
120
  atol: float = 1e-8,
129
- ) -> Tuple[Optional[np.ndarray], List[ops.Operation]]:
121
+ ) -> tuple[np.ndarray | None, list[ops.Operation]]:
130
122
  r"""Converts a two qubit double multiplexor to circuit.
131
123
  Input: U_1 ⊕ U_2, with select qubit a (i.e. a = |0> => U_1(b,c),
132
124
  a = |1> => U_2(b,c).
@@ -185,7 +177,7 @@ def _two_qubit_multiplexor_to_ops(
185
177
 
186
178
  w = d_v @ w
187
179
 
188
- d_w: Optional[np.ndarray]
180
+ d_w: np.ndarray | None
189
181
 
190
182
  # if it's interesting to extract the diagonal then let's do it
191
183
  if shift_left:
@@ -258,7 +250,7 @@ def _middle_multiplexor_to_ops(q0: ops.Qid, q1: ops.Qid, q2: ops.Qid, eigvals: n
258
250
  return _optimize_multiplexed_angles_circuit(ops)
259
251
 
260
252
 
261
- def _multiplexed_angles(theta: Union[Sequence[float], np.ndarray]) -> np.ndarray:
253
+ def _multiplexed_angles(theta: Sequence[float] | np.ndarray) -> np.ndarray:
262
254
  """Calculates the angles for a 4-way multiplexed rotation.
263
255
 
264
256
  For example, if we want rz(theta[i]) if the select qubits are in state
@@ -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
  from random import random
16
- from typing import Callable
17
18
 
18
19
  import numpy as np
19
20
  import pytest
@@ -29,20 +30,6 @@ from cirq.transformers.analytical_decompositions.three_qubit_decomposition impor
29
30
  )
30
31
 
31
32
 
32
- def _skip_if_scipy(*, version_is_greater_than_1_5_0: bool) -> Callable[[Callable], Callable]:
33
- def decorator(func): # pragma: no cover
34
- try:
35
- # pylint: disable=unused-import
36
- from scipy.linalg import cossin
37
-
38
- return None if version_is_greater_than_1_5_0 else func
39
- except ImportError:
40
- return func if version_is_greater_than_1_5_0 else None
41
-
42
- return decorator
43
-
44
-
45
- @_skip_if_scipy(version_is_greater_than_1_5_0=False)
46
33
  @pytest.mark.parametrize(
47
34
  "u",
48
35
  [
@@ -52,7 +39,7 @@ def _skip_if_scipy(*, version_is_greater_than_1_5_0: bool) -> Callable[[Callable
52
39
  cirq.CCX._unitary_(),
53
40
  ],
54
41
  )
55
- def test_three_qubit_matrix_to_operations(u):
42
+ def test_three_qubit_matrix_to_operations(u) -> None:
56
43
  a, b, c = cirq.LineQubit.range(3)
57
44
  operations = cirq.three_qubit_matrix_to_operations(a, b, c, u)
58
45
  final_circuit = cirq.Circuit(operations)
@@ -68,8 +55,7 @@ def test_three_qubit_matrix_to_operations(u):
68
55
  assert num_two_qubit_gates <= 20, f"expected at most 20 CZ/CNOTs got {num_two_qubit_gates}"
69
56
 
70
57
 
71
- @_skip_if_scipy(version_is_greater_than_1_5_0=False)
72
- def test_three_qubit_matrix_to_operations_errors():
58
+ def test_three_qubit_matrix_to_operations_errors() -> None:
73
59
  a, b, c = cirq.LineQubit.range(3)
74
60
  with pytest.raises(ValueError, match="(8,8)"):
75
61
  cirq.three_qubit_matrix_to_operations(a, b, c, np.eye(2))
@@ -77,17 +63,6 @@ def test_three_qubit_matrix_to_operations_errors():
77
63
  cirq.three_qubit_matrix_to_operations(a, b, c, cirq.unitary(cirq.CCX) * 2)
78
64
 
79
65
 
80
- # on environments with scipy <1.5.0 this will not be sufficient to cover the
81
- # full three_qubit_matrix_to_operations method. In case we ever introduce a CI
82
- # environment like that, we'll need to ignore the coverage somehow conditionally on
83
- # the scipy version.
84
- @_skip_if_scipy(version_is_greater_than_1_5_0=True)
85
- def test_three_qubit_matrix_to_operations_scipy_error(): # pragma: no cover
86
- a, b, c = cirq.LineQubit.range(3)
87
- with pytest.raises(ImportError, match="three_qubit.*1.5.0+"):
88
- cirq.three_qubit_matrix_to_operations(a, b, c, np.eye(8))
89
-
90
-
91
66
  @pytest.mark.parametrize(
92
67
  ["theta", "num_czs"],
93
68
  [
@@ -100,7 +75,7 @@ def test_three_qubit_matrix_to_operations_scipy_error(): # pragma: no cover
100
75
  (np.array([0.3, 0.3, -0.3, -0.3]), 2),
101
76
  ],
102
77
  )
103
- def test_cs_to_ops(theta, num_czs):
78
+ def test_cs_to_ops(theta, num_czs) -> None:
104
79
  a, b, c = cirq.LineQubit.range(3)
105
80
  cs = _theta_to_cs(theta)
106
81
  circuit_cs = cirq.Circuit(_cs_to_ops(a, b, c, theta))
@@ -126,7 +101,7 @@ def _theta_to_cs(theta: np.ndarray) -> np.ndarray:
126
101
  return np.block([[c, -s], [s, c]])
127
102
 
128
103
 
129
- def test_multiplexed_angles():
104
+ def test_multiplexed_angles() -> None:
130
105
  theta = [random() * np.pi, random() * np.pi, random() * np.pi, random() * np.pi]
131
106
 
132
107
  angles = _multiplexed_angles(theta)
@@ -190,7 +165,7 @@ def test_multiplexed_angles():
190
165
  [([-0.3, 0.3, -0.3, -0.3]), 4],
191
166
  ],
192
167
  )
193
- def test_middle_multiplexor(angles, num_cnots):
168
+ def test_middle_multiplexor(angles, num_cnots) -> None:
194
169
  a, b, c = cirq.LineQubit.range(3)
195
170
  eigvals = np.exp(np.array(angles) * np.pi * 1j)
196
171
  d = np.diag(np.sqrt(eigvals))
@@ -212,7 +187,7 @@ def test_middle_multiplexor(angles, num_cnots):
212
187
 
213
188
 
214
189
  @pytest.mark.parametrize("shift_left", [True, False])
215
- def test_two_qubit_multiplexor_to_circuit(shift_left):
190
+ def test_two_qubit_multiplexor_to_circuit(shift_left) -> None:
216
191
  a, b, c = cirq.LineQubit.range(3)
217
192
  u1 = cirq.testing.random_unitary(4)
218
193
  u2 = cirq.testing.random_unitary(4)