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,15 +12,21 @@
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
+
17
+ import itertools
15
18
  import random
16
- from typing import Dict, Sequence
19
+ from typing import Sequence
17
20
 
18
21
  import numpy as np
19
22
  import pytest
20
23
 
21
24
  import cirq
22
25
  from cirq.contrib.paulistring import measure_pauli_strings
23
- from cirq.experiments import SingleQubitReadoutCalibrationResult
26
+ from cirq.contrib.paulistring.pauli_string_measurement_with_readout_mitigation import (
27
+ _process_pauli_measurement_results,
28
+ )
29
+ from cirq.experiments.single_qubit_readout_calibration import SingleQubitReadoutCalibrationResult
24
30
  from cirq.experiments.single_qubit_readout_calibration_test import NoisySingleQubitReadoutSampler
25
31
 
26
32
 
@@ -32,9 +38,14 @@ def _create_ghz(number_of_qubits: int, qubits: Sequence[cirq.Qid]) -> cirq.Circu
32
38
  return ghz_circuit
33
39
 
34
40
 
35
- def _generate_random_pauli_string(qubits: Sequence[cirq.Qid], enable_coeff: bool = False):
41
+ def _generate_random_pauli_string(
42
+ qubits: Sequence[cirq.Qid], enable_coeff: bool = False, allow_pauli_i: bool = True
43
+ ):
36
44
  pauli_ops = [cirq.I, cirq.X, cirq.Y, cirq.Z]
37
45
 
46
+ if not allow_pauli_i:
47
+ pauli_ops = [cirq.X, cirq.Y, cirq.Z]
48
+
38
49
  operators = {q: random.choice(pauli_ops) for q in qubits}
39
50
  # Ensure at least one non-identity.
40
51
  operators[random.choice(qubits)] = random.choice(pauli_ops[1:])
@@ -45,6 +56,49 @@ def _generate_random_pauli_string(qubits: Sequence[cirq.Qid], enable_coeff: bool
45
56
  return cirq.PauliString(operators)
46
57
 
47
58
 
59
+ def _generate_qwc_paulis(
60
+ input_pauli: cirq.PauliString, num_output: int, exclude_input_pauli: bool = False
61
+ ) -> list[cirq.PauliString]:
62
+ """Generates PauliStrings that are Qubit-Wise Commuting (QWC)
63
+ with the input_pauli.
64
+
65
+ All operations in input_pauli must not be pauli I.
66
+ """
67
+ allowed_paulis_per_qubit = []
68
+ qubits = input_pauli.qubits
69
+
70
+ for qubit in qubits:
71
+ pauli_op = input_pauli.get(qubit, cirq.I)
72
+
73
+ allowed_pauli_op = []
74
+ if pauli_op == cirq.I:
75
+ allowed_pauli_op = [cirq.I, cirq.X, cirq.Y, cirq.Z] # pragma: no cover
76
+ elif pauli_op == cirq.X:
77
+ allowed_pauli_op = [cirq.I, cirq.X]
78
+ elif pauli_op == cirq.Y:
79
+ allowed_pauli_op = [cirq.I, cirq.Y]
80
+ elif pauli_op == cirq.Z:
81
+ allowed_pauli_op = [cirq.I, cirq.Z]
82
+
83
+ allowed_paulis_per_qubit.append(allowed_pauli_op)
84
+
85
+ qwc_paulis: list[cirq.PauliString] = []
86
+
87
+ for pauli_combination in itertools.product(*allowed_paulis_per_qubit):
88
+ pauli_dict = {}
89
+ for i, qid in enumerate(qubits):
90
+ pauli_dict[qid] = pauli_combination[i]
91
+
92
+ qwc_pauli: cirq.PauliString = cirq.PauliString(pauli_dict)
93
+ if exclude_input_pauli and qwc_pauli == input_pauli:
94
+ continue # pragma: no cover
95
+ if all(q == cirq.I for q in qwc_pauli):
96
+ continue
97
+ qwc_paulis.append(qwc_pauli)
98
+
99
+ return qwc_paulis if num_output > len(qwc_paulis) else random.sample(qwc_paulis, num_output)
100
+
101
+
48
102
  def _ideal_expectation_based_on_pauli_string(
49
103
  pauli_string: cirq.PauliString, final_state_vector: np.ndarray
50
104
  ) -> float:
@@ -61,7 +115,7 @@ def test_pauli_string_measurement_errors_no_noise() -> None:
61
115
  circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
62
116
  sampler = cirq.Simulator()
63
117
 
64
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
118
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
65
119
  circuits_to_pauli[circuit] = [_generate_random_pauli_string(qubits) for _ in range(3)]
66
120
 
67
121
  circuits_with_pauli_expectations = measure_pauli_strings(
@@ -109,7 +163,7 @@ def test_pauli_string_measurement_errors_with_coefficient_no_noise() -> None:
109
163
  circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
110
164
  sampler = cirq.Simulator()
111
165
 
112
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
166
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
113
167
  circuits_to_pauli[circuit] = [_generate_random_pauli_string(qubits, True) for _ in range(3)]
114
168
 
115
169
  circuits_with_pauli_expectations = measure_pauli_strings(
@@ -149,6 +203,60 @@ def test_pauli_string_measurement_errors_with_coefficient_no_noise() -> None:
149
203
  }
150
204
 
151
205
 
206
+ def test_group_pauli_string_measurement_errors_no_noise_with_coefficient() -> None:
207
+ """Test that the mitigated expectation is close to the ideal expectation
208
+ based on the group of Pauli strings"""
209
+
210
+ qubits = cirq.LineQubit.range(5)
211
+ circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
212
+ sampler = cirq.Simulator()
213
+
214
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
215
+ circuits_to_pauli[circuit] = [
216
+ _generate_qwc_paulis(
217
+ _generate_random_pauli_string(qubits, enable_coeff=True, allow_pauli_i=False), 100, True
218
+ )
219
+ for _ in range(3)
220
+ ]
221
+ circuits_to_pauli[circuit].append([cirq.PauliString({q: cirq.X for q in qubits})])
222
+
223
+ circuits_with_pauli_expectations = measure_pauli_strings(
224
+ circuits_to_pauli, sampler, 100, 100, 100, 100
225
+ )
226
+
227
+ for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
228
+ assert isinstance(circuit_with_pauli_expectations.circuit, cirq.FrozenCircuit)
229
+
230
+ expected_val_simulation = sampler.simulate(
231
+ circuit_with_pauli_expectations.circuit.unfreeze()
232
+ )
233
+ final_state_vector = expected_val_simulation.final_state_vector
234
+
235
+ for pauli_string_measurement_results in circuit_with_pauli_expectations.results:
236
+ # Since there is no noise, the mitigated and unmitigated expectations should be the same
237
+ assert np.isclose(
238
+ pauli_string_measurement_results.mitigated_expectation,
239
+ pauli_string_measurement_results.unmitigated_expectation,
240
+ )
241
+ assert np.isclose(
242
+ pauli_string_measurement_results.mitigated_expectation,
243
+ _ideal_expectation_based_on_pauli_string(
244
+ pauli_string_measurement_results.pauli_string, final_state_vector
245
+ ),
246
+ atol=4 * pauli_string_measurement_results.mitigated_stddev,
247
+ )
248
+ assert isinstance(
249
+ pauli_string_measurement_results.calibration_result,
250
+ SingleQubitReadoutCalibrationResult,
251
+ )
252
+ assert pauli_string_measurement_results.calibration_result.zero_state_errors == {
253
+ q: 0 for q in pauli_string_measurement_results.pauli_string.qubits
254
+ }
255
+ assert pauli_string_measurement_results.calibration_result.one_state_errors == {
256
+ q: 0 for q in pauli_string_measurement_results.pauli_string.qubits
257
+ }
258
+
259
+
152
260
  def test_pauli_string_measurement_errors_with_noise() -> None:
153
261
  """Test that the mitigated expectation is close to the ideal expectation
154
262
  based on the Pauli string"""
@@ -157,7 +265,7 @@ def test_pauli_string_measurement_errors_with_noise() -> None:
157
265
  sampler = NoisySingleQubitReadoutSampler(p0=0.1, p1=0.005, seed=1234)
158
266
  simulator = cirq.Simulator()
159
267
 
160
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
268
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
161
269
  circuits_to_pauli[circuit] = [_generate_random_pauli_string(qubits) for _ in range(3)]
162
270
 
163
271
  circuits_with_pauli_expectations = measure_pauli_strings(
@@ -196,6 +304,57 @@ def test_pauli_string_measurement_errors_with_noise() -> None:
196
304
  assert 0.0045 < error < 0.0055
197
305
 
198
306
 
307
+ def test_group_pauli_string_measurement_errors_with_noise() -> None:
308
+ """Test that the mitigated expectation is close to the ideal expectation
309
+ based on the group Pauli strings"""
310
+ qubits = cirq.LineQubit.range(7)
311
+ circuit = cirq.FrozenCircuit(_create_ghz(7, qubits))
312
+ sampler = NoisySingleQubitReadoutSampler(p0=0.1, p1=0.005, seed=1234)
313
+ simulator = cirq.Simulator()
314
+
315
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
316
+ circuits_to_pauli[circuit] = [
317
+ _generate_qwc_paulis(
318
+ _generate_random_pauli_string(qubits, enable_coeff=True, allow_pauli_i=False), 5
319
+ )
320
+ ]
321
+
322
+ circuits_with_pauli_expectations = measure_pauli_strings(
323
+ circuits_to_pauli, sampler, 800, 1000, 800, np.random.default_rng()
324
+ )
325
+
326
+ for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
327
+ assert isinstance(circuit_with_pauli_expectations.circuit, cirq.FrozenCircuit)
328
+
329
+ expected_val_simulation = simulator.simulate(
330
+ circuit_with_pauli_expectations.circuit.unfreeze()
331
+ )
332
+ final_state_vector = expected_val_simulation.final_state_vector
333
+
334
+ for pauli_string_measurement_results in circuit_with_pauli_expectations.results:
335
+ assert np.isclose(
336
+ pauli_string_measurement_results.mitigated_expectation,
337
+ _ideal_expectation_based_on_pauli_string(
338
+ pauli_string_measurement_results.pauli_string, final_state_vector
339
+ ),
340
+ atol=4 * pauli_string_measurement_results.mitigated_stddev,
341
+ )
342
+
343
+ assert isinstance(
344
+ pauli_string_measurement_results.calibration_result,
345
+ SingleQubitReadoutCalibrationResult,
346
+ )
347
+
348
+ for (
349
+ error
350
+ ) in pauli_string_measurement_results.calibration_result.zero_state_errors.values():
351
+ assert 0.08 < error < 0.12
352
+ for (
353
+ error
354
+ ) in pauli_string_measurement_results.calibration_result.one_state_errors.values():
355
+ assert 0.0045 < error < 0.0055
356
+
357
+
199
358
  def test_many_circuits_input_measurement_with_noise() -> None:
200
359
  """Test that the mitigated expectation is close to the ideal expectation
201
360
  based on the Pauli string for multiple circuits"""
@@ -213,7 +372,7 @@ def test_many_circuits_input_measurement_with_noise() -> None:
213
372
  circuit_2 = cirq.FrozenCircuit(_create_ghz(5, qubits_2))
214
373
  circuit_3 = cirq.FrozenCircuit(_create_ghz(8, qubits_3))
215
374
 
216
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
375
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
217
376
  circuits_to_pauli[circuit_1] = [_generate_random_pauli_string(qubits_1) for _ in range(3)]
218
377
  circuits_to_pauli[circuit_2] = [_generate_random_pauli_string(qubits_2) for _ in range(3)]
219
378
  circuits_to_pauli[circuit_3] = [_generate_random_pauli_string(qubits_3) for _ in range(3)]
@@ -261,7 +420,7 @@ def test_allow_measurement_without_readout_mitigation() -> None:
261
420
  circuit = cirq.FrozenCircuit(_create_ghz(7, qubits))
262
421
  sampler = NoisySingleQubitReadoutSampler(p0=0.1, p1=0.005, seed=1234)
263
422
 
264
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
423
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
265
424
  circuits_to_pauli[circuit] = [
266
425
  _generate_random_pauli_string(qubits, True),
267
426
  _generate_random_pauli_string(qubits),
@@ -285,6 +444,36 @@ def test_allow_measurement_without_readout_mitigation() -> None:
285
444
  assert pauli_string_measurement_results.calibration_result is None
286
445
 
287
446
 
447
+ def test_allow_group_pauli_measurement_without_readout_mitigation() -> None:
448
+ """Test that the function allows to measure without error mitigation"""
449
+ qubits = cirq.LineQubit.range(7)
450
+ circuit = cirq.FrozenCircuit(_create_ghz(7, qubits))
451
+ sampler = NoisySingleQubitReadoutSampler(p0=0.1, p1=0.005, seed=1234)
452
+
453
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
454
+ circuits_to_pauli[circuit] = [
455
+ _generate_qwc_paulis(_generate_random_pauli_string(qubits, True), 2, True),
456
+ _generate_qwc_paulis(_generate_random_pauli_string(qubits), 4),
457
+ _generate_qwc_paulis(_generate_random_pauli_string(qubits), 6),
458
+ ]
459
+
460
+ circuits_with_pauli_expectations = measure_pauli_strings(
461
+ circuits_to_pauli, sampler, 100, 100, 0, np.random.default_rng()
462
+ )
463
+
464
+ for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
465
+ assert isinstance(circuit_with_pauli_expectations.circuit, cirq.FrozenCircuit)
466
+
467
+ for pauli_string_measurement_results in circuit_with_pauli_expectations.results:
468
+ # Since there's no mitigation, the mitigated and unmitigated expectations
469
+ # should be the same
470
+ assert np.isclose(
471
+ pauli_string_measurement_results.mitigated_expectation,
472
+ pauli_string_measurement_results.unmitigated_expectation,
473
+ )
474
+ assert pauli_string_measurement_results.calibration_result is None
475
+
476
+
288
477
  def test_many_circuits_with_coefficient() -> None:
289
478
  """Test that the mitigated expectation is close to the ideal expectation
290
479
  based on the Pauli string for multiple circuits"""
@@ -302,7 +491,7 @@ def test_many_circuits_with_coefficient() -> None:
302
491
  circuit_2 = cirq.FrozenCircuit(_create_ghz(5, qubits_2))
303
492
  circuit_3 = cirq.FrozenCircuit(_create_ghz(8, qubits_3))
304
493
 
305
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
494
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
306
495
  circuits_to_pauli[circuit_1] = [_generate_random_pauli_string(qubits_1, True) for _ in range(3)]
307
496
  circuits_to_pauli[circuit_2] = [_generate_random_pauli_string(qubits_2, True) for _ in range(3)]
308
497
  circuits_to_pauli[circuit_3] = [_generate_random_pauli_string(qubits_3, True) for _ in range(3)]
@@ -344,6 +533,77 @@ def test_many_circuits_with_coefficient() -> None:
344
533
  assert 0.0045 < error < 0.0055
345
534
 
346
535
 
536
+ def test_many_group_pauli_in_circuits_with_coefficient() -> None:
537
+ """Test that the mitigated expectation is close to the ideal expectation
538
+ based on the Pauli string for multiple circuits"""
539
+ qubits_1 = cirq.LineQubit.range(3)
540
+ qubits_2 = [
541
+ cirq.GridQubit(0, 1),
542
+ cirq.GridQubit(1, 1),
543
+ cirq.GridQubit(1, 0),
544
+ cirq.GridQubit(1, 2),
545
+ cirq.GridQubit(2, 1),
546
+ ]
547
+ qubits_3 = cirq.LineQubit.range(8)
548
+
549
+ circuit_1 = cirq.FrozenCircuit(_create_ghz(3, qubits_1))
550
+ circuit_2 = cirq.FrozenCircuit(_create_ghz(5, qubits_2))
551
+ circuit_3 = cirq.FrozenCircuit(_create_ghz(8, qubits_3))
552
+
553
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
554
+ circuits_to_pauli[circuit_1] = [
555
+ _generate_qwc_paulis(
556
+ _generate_random_pauli_string(qubits_1, enable_coeff=True, allow_pauli_i=False), 4
557
+ )
558
+ ]
559
+ circuits_to_pauli[circuit_2] = [
560
+ _generate_qwc_paulis(
561
+ _generate_random_pauli_string(qubits_2, enable_coeff=True, allow_pauli_i=False), 5
562
+ )
563
+ ]
564
+ circuits_to_pauli[circuit_3] = [
565
+ _generate_qwc_paulis(
566
+ _generate_random_pauli_string(qubits_3, enable_coeff=True, allow_pauli_i=False), 6
567
+ )
568
+ ]
569
+
570
+ sampler = NoisySingleQubitReadoutSampler(p0=0.03, p1=0.005, seed=1234)
571
+ simulator = cirq.Simulator()
572
+
573
+ circuits_with_pauli_expectations = measure_pauli_strings(
574
+ circuits_to_pauli, sampler, 1000, 1000, 1000, np.random.default_rng()
575
+ )
576
+
577
+ for circuit_with_pauli_expectations in circuits_with_pauli_expectations:
578
+ assert isinstance(circuit_with_pauli_expectations.circuit, cirq.FrozenCircuit)
579
+
580
+ expected_val_simulation = simulator.simulate(
581
+ circuit_with_pauli_expectations.circuit.unfreeze()
582
+ )
583
+ final_state_vector = expected_val_simulation.final_state_vector
584
+
585
+ for pauli_string_measurement_results in circuit_with_pauli_expectations.results:
586
+ assert np.isclose(
587
+ pauli_string_measurement_results.mitigated_expectation,
588
+ _ideal_expectation_based_on_pauli_string(
589
+ pauli_string_measurement_results.pauli_string, final_state_vector
590
+ ),
591
+ atol=4 * pauli_string_measurement_results.mitigated_stddev,
592
+ )
593
+ assert isinstance(
594
+ pauli_string_measurement_results.calibration_result,
595
+ SingleQubitReadoutCalibrationResult,
596
+ )
597
+ for (
598
+ error
599
+ ) in pauli_string_measurement_results.calibration_result.zero_state_errors.values():
600
+ assert 0.025 < error < 0.035
601
+ for (
602
+ error
603
+ ) in pauli_string_measurement_results.calibration_result.one_state_errors.values():
604
+ assert 0.0045 < error < 0.0055
605
+
606
+
347
607
  def test_coefficient_not_real_number() -> None:
348
608
  """Test that the coefficient of input pauli string is not real.
349
609
  Should return error in this case"""
@@ -351,7 +611,7 @@ def test_coefficient_not_real_number() -> None:
351
611
  random_pauli_string = _generate_random_pauli_string(qubits_1, True) * (3 + 4j)
352
612
  circuit_1 = cirq.FrozenCircuit(_create_ghz(3, qubits_1))
353
613
 
354
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
614
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
355
615
  circuits_to_pauli[circuit_1] = [
356
616
  random_pauli_string,
357
617
  _generate_random_pauli_string(qubits_1, True),
@@ -386,7 +646,7 @@ def test_invalid_input_circuit_type() -> None:
386
646
  """Test that the input circuit type is not frozen circuit"""
387
647
  qubits = cirq.LineQubit.range(5)
388
648
 
389
- qubits_to_pauli: Dict[tuple, list[cirq.PauliString]] = {}
649
+ qubits_to_pauli: dict[tuple, list[cirq.PauliString]] = {}
390
650
  qubits_to_pauli[tuple(qubits)] = [cirq.PauliString({q: cirq.X for q in qubits})]
391
651
  with pytest.raises(
392
652
  TypeError, match="All keys in 'circuits_to_pauli' must be FrozenCircuit instances."
@@ -415,13 +675,14 @@ def test_invalid_input_pauli_string_type() -> None:
415
675
  circuit_1 = cirq.FrozenCircuit(_create_ghz(5, qubits_1))
416
676
  circuit_2 = cirq.FrozenCircuit(_create_ghz(5, qubits_2))
417
677
 
418
- circuits_to_pauli: Dict[cirq.FrozenCircuit, cirq.FrozenCircuit] = {}
419
- circuits_to_pauli[circuit_1] = circuit_2
678
+ circuits_to_pauli: dict[cirq.FrozenCircuit, cirq.FrozenCircuit] = {}
679
+ circuits_to_pauli[circuit_1] = [_generate_random_pauli_string(qubits_1)] # type: ignore
680
+ circuits_to_pauli[circuit_2] = [circuit_1, circuit_2] # type: ignore
420
681
 
421
682
  with pytest.raises(
422
683
  TypeError,
423
684
  match="All elements in the Pauli string lists must be cirq.PauliString "
424
- "instances, got <class 'cirq.circuits.moment.Moment'>.",
685
+ "instances, got <class 'cirq.circuits.frozen_circuit.FrozenCircuit'>.",
425
686
  ):
426
687
  measure_pauli_strings(
427
688
  circuits_to_pauli, # type: ignore[arg-type]
@@ -447,7 +708,7 @@ def test_all_pauli_strings_are_pauli_i() -> None:
447
708
  circuit_1 = cirq.FrozenCircuit(_create_ghz(5, qubits_1))
448
709
  circuit_2 = cirq.FrozenCircuit(_create_ghz(5, qubits_2))
449
710
 
450
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
711
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
451
712
  circuits_to_pauli[circuit_1] = [
452
713
  cirq.PauliString({q: cirq.I for q in qubits_1}),
453
714
  cirq.PauliString({q: cirq.X for q in qubits_1}),
@@ -471,7 +732,7 @@ def test_zero_pauli_repetitions() -> None:
471
732
 
472
733
  circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
473
734
 
474
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
735
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
475
736
  circuits_to_pauli[circuit] = [cirq.PauliString({q: cirq.X for q in qubits})]
476
737
  with pytest.raises(ValueError, match="Must provide non-zero pauli_repetitions."):
477
738
  measure_pauli_strings(
@@ -485,7 +746,7 @@ def test_negative_num_random_bitstrings() -> None:
485
746
 
486
747
  circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
487
748
 
488
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
749
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
489
750
  circuits_to_pauli[circuit] = [cirq.PauliString({q: cirq.X for q in qubits})]
490
751
  with pytest.raises(ValueError, match="Must provide zero or more num_random_bitstrings."):
491
752
  measure_pauli_strings(
@@ -499,7 +760,7 @@ def test_zero_readout_repetitions() -> None:
499
760
 
500
761
  circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
501
762
 
502
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
763
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
503
764
  circuits_to_pauli[circuit] = [cirq.PauliString({q: cirq.X for q in qubits})]
504
765
  with pytest.raises(
505
766
  ValueError, match="Must provide non-zero readout_repetitions for readout" + " calibration."
@@ -515,9 +776,127 @@ def test_rng_type_mismatch() -> None:
515
776
 
516
777
  circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
517
778
 
518
- circuits_to_pauli: Dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
779
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
519
780
  circuits_to_pauli[circuit] = [cirq.PauliString({q: cirq.X for q in qubits})]
520
781
  with pytest.raises(ValueError, match="Must provide a numpy random generator or a seed"):
521
782
  measure_pauli_strings(
522
783
  circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, "test" # type: ignore[arg-type]
523
784
  )
785
+
786
+
787
+ def test_pauli_type_mismatch() -> None:
788
+ """Test that the input paulis are not a sequence of PauliStrings."""
789
+ qubits = cirq.LineQubit.range(5)
790
+
791
+ circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
792
+
793
+ circuits_to_pauli: dict[cirq.FrozenCircuit, int] = {}
794
+ circuits_to_pauli[circuit] = 1
795
+ with pytest.raises(
796
+ TypeError,
797
+ match="Expected all elements to be either a sequence of PauliStrings or sequences of"
798
+ " ops.PauliStrings. Got <class 'int'> instead.",
799
+ ):
800
+ measure_pauli_strings(
801
+ circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, "test" # type: ignore[arg-type]
802
+ )
803
+
804
+
805
+ def test_group_paulis_are_not_qwc() -> None:
806
+ """Test that the group paulis are not qwc."""
807
+ qubits = cirq.LineQubit.range(5)
808
+
809
+ circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
810
+
811
+ pauli_str1: cirq.PauliString = cirq.PauliString({qubits[0]: cirq.X, qubits[1]: cirq.Y})
812
+ pauli_str2: cirq.PauliString = cirq.PauliString({qubits[0]: cirq.Y})
813
+
814
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
815
+ circuits_to_pauli[circuit] = [[pauli_str1, pauli_str2]] # type: ignore
816
+ with pytest.raises(
817
+ ValueError, match="The group of Pauli strings are not Qubit-Wise Commuting with each other."
818
+ ):
819
+ measure_pauli_strings(
820
+ circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, np.random.default_rng()
821
+ )
822
+
823
+
824
+ def test_empty_group_paulis_not_allowed() -> None:
825
+ """Test that the group paulis are empty"""
826
+ qubits = cirq.LineQubit.range(5)
827
+
828
+ circuit = cirq.FrozenCircuit(_create_ghz(5, qubits))
829
+
830
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[cirq.PauliString]] = {}
831
+ circuits_to_pauli[circuit] = [[]] # type: ignore
832
+ with pytest.raises(ValueError, match="Empty group of Pauli strings is not allowed"):
833
+ measure_pauli_strings(
834
+ circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, np.random.default_rng()
835
+ )
836
+
837
+
838
+ def test_group_paulis_type_mismatch() -> None:
839
+ """Test that the group paulis type is not correct"""
840
+ qubits_1 = cirq.LineQubit.range(3)
841
+ qubits_2 = [
842
+ cirq.GridQubit(0, 1),
843
+ cirq.GridQubit(1, 1),
844
+ cirq.GridQubit(1, 0),
845
+ cirq.GridQubit(1, 2),
846
+ cirq.GridQubit(2, 1),
847
+ ]
848
+ qubits_3 = cirq.LineQubit.range(8)
849
+
850
+ circuit_1 = cirq.FrozenCircuit(_create_ghz(3, qubits_1))
851
+ circuit_2 = cirq.FrozenCircuit(_create_ghz(5, qubits_2))
852
+ circuit_3 = cirq.FrozenCircuit(_create_ghz(8, qubits_3))
853
+
854
+ circuits_to_pauli: dict[cirq.FrozenCircuit, list[list[cirq.PauliString]]] = {}
855
+ circuits_to_pauli[circuit_1] = [
856
+ _generate_qwc_paulis(
857
+ _generate_random_pauli_string(qubits_1, enable_coeff=True, allow_pauli_i=False), 6
858
+ )
859
+ for _ in range(3)
860
+ ]
861
+ circuits_to_pauli[circuit_2] = [_generate_random_pauli_string(qubits_2, True) for _ in range(3)]
862
+ circuits_to_pauli[circuit_3] = [_generate_random_pauli_string(qubits_3, True) for _ in range(3)]
863
+
864
+ with pytest.raises(
865
+ TypeError,
866
+ match="Expected all elements to be sequences of ops.PauliString, "
867
+ "but found <class 'cirq.ops.pauli_string.PauliString'>.",
868
+ ):
869
+ measure_pauli_strings(
870
+ circuits_to_pauli, cirq.Simulator(), 1000, 1000, 1000, np.random.default_rng()
871
+ )
872
+
873
+
874
+ def test_process_pauli_measurement_results_raises_error_on_missing_calibration() -> None:
875
+ """Test that the function raises an error if the calibration result is missing."""
876
+ qubits: Sequence[cirq.Qid] = cirq.LineQubit.range(5)
877
+
878
+ measurement_op = cirq.measure(*qubits, key='m')
879
+ test_circuits: list[cirq.Circuit] = [_create_ghz(5, qubits) + measurement_op for _ in range(3)]
880
+
881
+ pauli_strings = [_generate_random_pauli_string(qubits, True) for _ in range(3)]
882
+ sampler = cirq.Simulator()
883
+
884
+ circuit_results = sampler.run_batch(test_circuits, repetitions=1000)
885
+
886
+ pauli_strings_qubits = sorted(
887
+ set(itertools.chain.from_iterable(ps.qubits for ps in pauli_strings))
888
+ )
889
+ empty_calibration_result_dict = {tuple(pauli_strings_qubits): None}
890
+
891
+ with pytest.raises(
892
+ ValueError,
893
+ match="Readout mitigation is enabled, but no calibration result was found for qubits",
894
+ ):
895
+ _process_pauli_measurement_results(
896
+ qubits,
897
+ [pauli_strings],
898
+ circuit_results[0], # type: ignore[arg-type]
899
+ empty_calibration_result_dict, # type: ignore[arg-type]
900
+ 1000,
901
+ 1.0,
902
+ )
@@ -12,15 +12,21 @@
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
+
17
+ from typing import TYPE_CHECKING
18
+
15
19
  import networkx
16
20
 
17
21
  from cirq import circuits, linalg
18
- from cirq.contrib import circuitdag
19
22
  from cirq.contrib.paulistring.pauli_string_dag import pauli_string_dag_from_circuit
20
23
  from cirq.contrib.paulistring.recombine import move_pauli_strings_into_circuit
21
24
  from cirq.contrib.paulistring.separate import convert_and_separate_circuit
22
25
  from cirq.ops import PauliStringGateOperation
23
26
 
27
+ if TYPE_CHECKING:
28
+ from cirq.contrib import circuitdag
29
+
24
30
 
25
31
  def pauli_string_optimized_circuit(
26
32
  circuit: circuits.Circuit, move_cliffords: bool = True, atol: float = 1e-8
@@ -12,11 +12,13 @@
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 cirq
16
18
  from cirq.contrib.paulistring import CliffordTargetGateset, pauli_string_optimized_circuit
17
19
 
18
20
 
19
- def test_optimize():
21
+ def test_optimize() -> None:
20
22
  q0, q1 = cirq.LineQubit.range(2)
21
23
  c_orig = cirq.Circuit(
22
24
  cirq.X(q0) ** 0.25, cirq.H(q0), cirq.CZ(q0, q1), cirq.H(q0), cirq.X(q0) ** 0.125
@@ -50,7 +52,7 @@ def test_optimize():
50
52
  )
51
53
 
52
54
 
53
- def test_handles_measurement_gate():
55
+ def test_handles_measurement_gate() -> None:
54
56
  q0, q1 = cirq.LineQubit.range(2)
55
57
  c_orig = cirq.Circuit(
56
58
  cirq.X(q0) ** 0.25,
@@ -75,7 +77,7 @@ def test_handles_measurement_gate():
75
77
  )
76
78
 
77
79
 
78
- def test_optimize_large_circuit():
80
+ def test_optimize_large_circuit() -> None:
79
81
  q0, q1, q2 = cirq.LineQubit.range(3)
80
82
  c_orig = cirq.testing.nonoptimal_toffoli_circuit(q0, q1, q2)
81
83
 
@@ -12,7 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from typing import Any, Callable, cast, Iterable, List, Sequence, Tuple, Union
15
+ from __future__ import annotations
16
+
17
+ from typing import Any, Callable, cast, Iterable, Sequence
16
18
 
17
19
  from cirq import circuits, ops, protocols
18
20
  from cirq.contrib import circuitdag
@@ -26,7 +28,7 @@ def _sorted_best_string_placements(
26
28
  possible_nodes: Iterable[Any],
27
29
  output_ops: Sequence[ops.Operation],
28
30
  key: Callable[[Any], ops.PauliStringPhasor] = lambda node: node.val,
29
- ) -> List[Tuple[ops.PauliStringPhasor, int, circuitdag.Unique[ops.PauliStringPhasor]]]:
31
+ ) -> list[tuple[ops.PauliStringPhasor, int, circuitdag.Unique[ops.PauliStringPhasor]]]:
30
32
  sort_key = lambda placement: (-len(placement[0].pauli_string), placement[1])
31
33
 
32
34
  node_maxes = []
@@ -53,7 +55,7 @@ def _sorted_best_string_placements(
53
55
  ):
54
56
  # This is as far through as this Pauli string can move
55
57
  break
56
- string_op = string_op.pass_operations_over([out_op], after_to_before=True)
58
+ string_op = string_op.conjugated_by(protocols.inverse(out_op))
57
59
  curr = (string_op, i + 1, possible_node)
58
60
  if sort_key(curr) > sort_key(node_max):
59
61
  node_max = curr
@@ -64,7 +66,7 @@ def _sorted_best_string_placements(
64
66
 
65
67
 
66
68
  def move_pauli_strings_into_circuit(
67
- circuit_left: Union[circuits.Circuit, circuitdag.CircuitDag], circuit_right: circuits.Circuit
69
+ circuit_left: circuits.Circuit | circuitdag.CircuitDag, circuit_right: circuits.Circuit
68
70
  ) -> circuits.Circuit:
69
71
  if isinstance(circuit_left, circuitdag.CircuitDag):
70
72
  string_dag = circuitdag.CircuitDag(pauli_string_reorder_pred, circuit_left)
@@ -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 cirq
16
18
  from cirq.contrib.paulistring import (
17
19
  convert_and_separate_circuit,
@@ -26,7 +28,7 @@ def _assert_no_multi_qubit_pauli_strings(circuit: cirq.Circuit) -> None:
26
28
  assert len(op.pauli_string) == 1 # pragma: no cover
27
29
 
28
30
 
29
- def test_move_non_clifford_into_clifford():
31
+ def test_move_non_clifford_into_clifford() -> None:
30
32
  q0, q1, q2 = cirq.LineQubit.range(3)
31
33
  c_orig = cirq.testing.nonoptimal_toffoli_circuit(q0, q1, q2)
32
34