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
@@ -0,0 +1,677 @@
1
+ # Copyright 2025 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """A module for performing and analysing parallel XEB."""
16
+
17
+ from __future__ import annotations
18
+
19
+ from concurrent import futures
20
+ from typing import overload, Sequence, TYPE_CHECKING, Union
21
+
22
+ import attrs
23
+ import networkx as nx
24
+ import numpy as np
25
+ import pandas as pd
26
+
27
+ import cirq.experiments.random_quantum_circuit_generation as rqcg
28
+ import cirq.experiments.two_qubit_xeb as tqxeb
29
+ import cirq.experiments.xeb_fitting as xeb_fitting
30
+ from cirq import circuits, devices, ops, protocols, sim, value
31
+
32
+ if TYPE_CHECKING:
33
+ import cirq
34
+
35
+ _TARGET_T = Union['cirq.Gate', 'cirq.Operation', 'cirq.AbstractCircuit']
36
+ _QUBIT_PAIR_T = tuple['cirq.GridQubit', 'cirq.GridQubit']
37
+ _CANONICAL_TARGET_T = Union['cirq.Operation', dict[_QUBIT_PAIR_T, 'cirq.Operation']]
38
+ _PROBABILITIES_DICT_T = dict[_QUBIT_PAIR_T, list[list[np.ndarray]]]
39
+
40
+
41
+ def _canonize_pair(pair: _QUBIT_PAIR_T) -> _QUBIT_PAIR_T:
42
+ return min(pair), max(pair)
43
+
44
+
45
+ @attrs.frozen
46
+ class XEBParameters:
47
+ """A frozen dataclass that holds the parameter of an XEB experiment.
48
+
49
+ Attributes:
50
+ n_repetitions: The number of repetitions to use.
51
+ n_combinations: The number of combinations to generate.
52
+ n_circuits: The number of circuits to generate.
53
+ cycle_depths: The cycle depths to use.
54
+ """
55
+
56
+ n_repetitions: int = 10**4
57
+ n_combinations: int = 10
58
+ n_circuits: int = 20
59
+ cycle_depths: tuple[int, ...] = attrs.field(default=(5, 25, 50, 100, 200, 300), converter=tuple)
60
+
61
+
62
+ @attrs.frozen
63
+ class XEBWideCircuitInfo:
64
+ """Represents an XEB circuit expanded to the given cycle depth.
65
+
66
+ Attributes:
67
+ wide_circuit: The expanded circuit.
68
+ pairs: A list of the pairs benchmarked by the given circuit.
69
+ narrow_template_indices: Integer indices of the circuits in the narrow circuit library
70
+ used to build the given wide circuit.
71
+ cycle_depth: Optional, the depth of the cycle forming the wide circuit.
72
+ """
73
+
74
+ wide_circuit: circuits.Circuit
75
+ pairs: Sequence[_QUBIT_PAIR_T] = attrs.field(
76
+ converter=lambda seq: [_canonize_pair(pair) for pair in seq]
77
+ )
78
+ narrow_template_indices: tuple[int, ...] = attrs.field(converter=tuple)
79
+ cycle_depth: int | None = None
80
+
81
+ @staticmethod
82
+ def from_narrow_circuits(
83
+ circuit_templates: Sequence[cirq.Circuit],
84
+ permutation: np.ndarray,
85
+ pairs: Sequence[_QUBIT_PAIR_T],
86
+ target: _CANONICAL_TARGET_T,
87
+ ) -> XEBWideCircuitInfo:
88
+ """A static method that merges a sequence of narrow circuits into a wide circuit.
89
+
90
+ Args:
91
+ circuit_templates: A sequence of 2Q (i.e. narrow) circuits.
92
+ permutation: A permutation that maps a qubit-pair to a narrow circuit.
93
+ pairs: The list of qubit-pairs to benchmark.
94
+ target: The target 2Q operation to benchmark.
95
+
96
+ Returns:
97
+ An XEBWideCircuitInfo instance representing the glued circuits.
98
+ """
99
+ transformed_circuits = []
100
+ has_circuit_operations = False
101
+ for i, pair in zip(permutation, pairs, strict=True):
102
+ circuit = circuit_templates[i].transform_qubits(lambda q: pair[q.x])
103
+ if isinstance(target, ops.Operation):
104
+ xeb_op = target.with_qubits(*pair)
105
+ else:
106
+ if pair not in target:
107
+ continue
108
+ xeb_op = target[pair]
109
+ xeb_op = xeb_op.with_qubits(*pair)
110
+
111
+ if isinstance(xeb_op, circuits.CircuitOperation):
112
+ xeb_op = xeb_op.mapped_op()
113
+ has_circuit_operations = True
114
+
115
+ def _map_operation(op):
116
+ num_qubits = protocols.num_qubits(op)
117
+ if num_qubits <= 1:
118
+ return op
119
+ assert num_qubits == 2
120
+ return xeb_op
121
+
122
+ circuit = circuit.map_operations(_map_operation)
123
+ transformed_circuits.append(circuit)
124
+
125
+ zipped_circuit = circuits.Circuit.zip(*transformed_circuits)
126
+ if has_circuit_operations and len(circuit_templates) > 1:
127
+ # Each moment must have at most one circuit operation.
128
+ new_moments = []
129
+ for moment in zipped_circuit:
130
+ if any(isinstance(op, circuits.CircuitOperation) for op in moment):
131
+ new_moments.append(
132
+ _transform_moment_with_circuit_ops_to_moment_with_single_op(moment)
133
+ )
134
+ else:
135
+ new_moments.append(moment)
136
+ zipped_circuit = circuits.Circuit.from_moments(*new_moments)
137
+ return XEBWideCircuitInfo(zipped_circuit, pairs, narrow_template_indices=permutation)
138
+
139
+ def sliced_circuits(self, cycle_depths: Sequence[int]) -> Sequence[XEBWideCircuitInfo]:
140
+ """Slices the wide circuit into the given cycle depths and appends necessary measurements.
141
+
142
+ Args:
143
+ cycle_depths: the cycle depths to cut the wide circuit into.
144
+
145
+ Returns:
146
+ A sequence of XEBWideCircuitInfo representing the sliced circuits.
147
+ """
148
+ xeb_circuits = []
149
+ for cycle_depth in cycle_depths:
150
+ circuit_depth = 2 * cycle_depth + 1
151
+ xeb_circuit = self.wide_circuit[:circuit_depth]
152
+ xeb_circuit.append(
153
+ circuits.Moment(ops.measure(pair, key=str(pair)) for pair in self.pairs)
154
+ )
155
+ xeb_circuits.append(
156
+ attrs.evolve(self, wide_circuit=xeb_circuit, cycle_depth=cycle_depth)
157
+ )
158
+ return xeb_circuits
159
+
160
+
161
+ def _target_to_operation(target: _TARGET_T) -> cirq.Operation:
162
+ if isinstance(target, ops.Gate):
163
+ return target(*devices.LineQid.for_gate(target))
164
+ elif isinstance(target, circuits.AbstractCircuit):
165
+ return circuits.CircuitOperation(target.freeze())
166
+ return target
167
+
168
+
169
+ def _canonize_target(target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T]) -> _CANONICAL_TARGET_T:
170
+ if isinstance(target, (ops.Gate, ops.Operation, circuits.AbstractCircuit)):
171
+ return _target_to_operation(target)
172
+ return {k: _target_to_operation(v) for k, v in target.items()}
173
+
174
+
175
+ def _transform_moment_with_circuit_ops_to_moment_with_single_op(
176
+ moment: circuits.Moment,
177
+ ) -> circuits.Moment:
178
+ """Merges all circuit operations in a moment into a single circuit operation.
179
+
180
+ Args:
181
+ moment: A cirq moment composed of single and two qubit operations.
182
+
183
+ Returns:
184
+ A Moment with at most one CircuitOperation.
185
+ """
186
+ circuit_ops = [
187
+ op.mapped_circuit() for op in moment if isinstance(op, circuits.CircuitOperation)
188
+ ]
189
+ not_circuit_ops = [op for op in moment if not isinstance(op, circuits.CircuitOperation)]
190
+ all_subcircuits = circuit_ops
191
+ if not_circuit_ops:
192
+ all_subcircuits.append(circuits.Circuit(circuits.Moment(not_circuit_ops)))
193
+ return circuits.Moment(circuits.CircuitOperation(circuits.FrozenCircuit.zip(*all_subcircuits)))
194
+
195
+
196
+ def create_combination_circuits(
197
+ circuit_templates: Sequence[cirq.Circuit],
198
+ combinations_by_layer: Sequence[rqcg.CircuitLibraryCombination],
199
+ target: _CANONICAL_TARGET_T,
200
+ ) -> Sequence[XEBWideCircuitInfo]:
201
+ """Zips two-qubit circuits into a single wide circuit for each of the given combinations.
202
+
203
+ Args:
204
+ circuit_templates: A sequence of narrow circuits.
205
+ combinations_by_layer: A sequence of combinations.
206
+ target: The target 2Q operation.
207
+
208
+ Returns:
209
+ A sequence of XEBWideCircuitInfo representing the wide circuits.
210
+ """
211
+ wide_circuits_info = []
212
+ for layer_comb in combinations_by_layer:
213
+ pairs = layer_comb.pairs
214
+ if isinstance(target, dict):
215
+ pairs = [pair for pair in pairs if pair in target]
216
+ assert pairs
217
+ for comb in layer_comb.combinations:
218
+ wide_circuits_info.append(
219
+ XEBWideCircuitInfo.from_narrow_circuits(
220
+ circuit_templates,
221
+ permutation=comb,
222
+ pairs=layer_comb.pairs, # type: ignore[arg-type]
223
+ target=target,
224
+ )
225
+ )
226
+ return wide_circuits_info
227
+
228
+
229
+ def simulate_circuit(
230
+ simulator: cirq.Simulator, circuit: cirq.Circuit, cycle_depths: Sequence[int]
231
+ ) -> Sequence[np.ndarray]:
232
+ """Simulates the given circuit and returns the state probabilities for each cycle depth.
233
+
234
+ Args:
235
+ simulator: A cirq simulator.
236
+ circuit: The circuit to simulate.
237
+ cycle_depths: A sequence of integers representing the depths for which we need the
238
+ state probabilities.
239
+
240
+ Returns:
241
+ - The cuircuit_id, same as given in input.
242
+ - The state probabilities for each cycle depth.
243
+ """
244
+ cycle_depths_set = frozenset(cycle_depths)
245
+ result = []
246
+ for moment_i, step_result in enumerate(simulator.simulate_moment_steps(circuit=circuit)):
247
+ # Translate from moment_i to cycle_depth:
248
+ # We know circuit_depth = cycle_depth * 2 + 1, and step_result is the result *after*
249
+ # moment_i, so circuit_depth = moment_i + 1 and moment_i = cycle_depth * 2.
250
+ if moment_i % 2 == 1:
251
+ continue
252
+ cycle_depth = moment_i // 2
253
+ if cycle_depth not in cycle_depths_set:
254
+ continue
255
+
256
+ psi = step_result.state_vector()
257
+ pure_probs = value.state_vector_to_probabilities(psi)
258
+
259
+ result.append(pure_probs)
260
+ return result
261
+
262
+
263
+ @overload
264
+ def simulate_circuit_library(
265
+ circuit_templates: Sequence[cirq.Circuit],
266
+ target_or_dict: ops.Operation,
267
+ cycle_depths: Sequence[int],
268
+ pool: futures.Executor | None = None,
269
+ ) -> Sequence[Sequence[np.ndarray]]: ...
270
+
271
+
272
+ @overload
273
+ def simulate_circuit_library(
274
+ circuit_templates: Sequence[cirq.Circuit],
275
+ target_or_dict: dict[_QUBIT_PAIR_T, ops.Operation],
276
+ cycle_depths: Sequence[int],
277
+ pool: futures.Executor | None = None,
278
+ ) -> dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]: ...
279
+
280
+
281
+ def simulate_circuit_library(
282
+ circuit_templates: Sequence[cirq.Circuit],
283
+ target_or_dict: _CANONICAL_TARGET_T,
284
+ cycle_depths: Sequence[int],
285
+ pool: futures.Executor | None = None,
286
+ ) -> Sequence[Sequence[np.ndarray]] | dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]:
287
+ """Simulate the given sequence of circuits.
288
+
289
+ Args:
290
+ circuit_templates: A sequence of circuits to simulate.
291
+ target_or_dict: The target operation or dictionary mapping qubit-pairs to operations.
292
+ cycle_depths: A list of integers giving the cycle depths to use in benchmarking.
293
+ pool: An optional concurrent.futures.Executor pool (e.g. ThreadPoolExecutor).
294
+ If given, the simulations are performed asynchronously.
295
+
296
+ Returns:
297
+ If target_or_dict is an operation:
298
+ A sequence of the result of simulate_circuit for each circuit_templates.
299
+ Else:
300
+ A dictionary mapping the keys of the map to a sequence of the result of
301
+ simulate_circuit for each circuit_templates.
302
+ """
303
+ two_qubit_ops = []
304
+ keys = None
305
+ if isinstance(target_or_dict, dict):
306
+ keys = tuple(target_or_dict.keys())
307
+ two_qubit_ops = list(target_or_dict[k] for k in keys)
308
+ else:
309
+ two_qubit_ops = [target_or_dict]
310
+
311
+ all_circuits = []
312
+ for target_op in two_qubit_ops:
313
+
314
+ def _map_op(op: ops.Operation) -> ops.Operation:
315
+ num_qubits = protocols.num_qubits(op)
316
+ if num_qubits <= 1:
317
+ return op
318
+ assert num_qubits == 2
319
+ return target_op.with_qubits(*op.qubits)
320
+
321
+ for circuit in circuit_templates:
322
+ all_circuits.append(circuit.map_operations(_map_op))
323
+
324
+ if pool is None:
325
+ simulation_results = [
326
+ simulate_circuit(
327
+ sim.Simulator(seed=np.random.RandomState(), dtype=np.complex128),
328
+ circuit=circuit,
329
+ cycle_depths=cycle_depths,
330
+ )
331
+ for circuit in all_circuits
332
+ ]
333
+ else:
334
+ simulation_results = [[np.empty(0)] for _ in range(len(all_circuits))]
335
+ tasks = [
336
+ pool.submit(
337
+ simulate_circuit,
338
+ simulator=sim.Simulator(seed=np.random.RandomState(), dtype=np.complex128),
339
+ circuit=circuit,
340
+ cycle_depths=cycle_depths,
341
+ )
342
+ for circuit in all_circuits
343
+ ]
344
+ tasks_index = {t: i for i, t in enumerate(tasks)}
345
+ for task in futures.as_completed(tasks):
346
+ sim_result = task.result()
347
+ i = tasks_index[task]
348
+ simulation_results[i] = sim_result
349
+
350
+ if keys is None:
351
+ return simulation_results
352
+
353
+ num_templates = len(circuit_templates)
354
+ return {
355
+ keys[i]: simulation_results[i * num_templates : (i + 1) * num_templates]
356
+ for i in range(len(keys))
357
+ }
358
+
359
+
360
+ def sample_all_circuits(
361
+ sampler: cirq.Sampler, circuits: Sequence[cirq.Circuit], repetitions: int
362
+ ) -> Sequence[dict[str, np.ndarray]]:
363
+ """Calls sampler.run_batch on the given circuits and estimates the state probabilities.
364
+
365
+ Args:
366
+ sampler: A cirq sampler.
367
+ circuits: A sequence of circuits.
368
+ repetitions: An integer, the number of sampling repetitions.
369
+
370
+ Returns:
371
+ For each circuit, a dictionary mapping measurement keys to the estimated probabilities.
372
+ """
373
+ sampling_results = []
374
+ for (result,) in sampler.run_batch(programs=circuits, repetitions=repetitions):
375
+ record = {}
376
+ for key in result.data.keys():
377
+ values = result.data[key]
378
+ sampled_probs = np.bincount(values, minlength=4) / len(values)
379
+ record[key] = sampled_probs
380
+ sampling_results.append(record)
381
+ return sampling_results
382
+
383
+
384
+ def _reshape_sampling_results(
385
+ sampling_results: Sequence[dict[str, np.ndarray]],
386
+ cycle_depths: Sequence[int],
387
+ wide_circuits_info: Sequence[XEBWideCircuitInfo],
388
+ pairs: Sequence[_QUBIT_PAIR_T],
389
+ num_templates: int,
390
+ ) -> _PROBABILITIES_DICT_T:
391
+ cycle_depth_to_index = {d: i for i, d in enumerate(cycle_depths)}
392
+ sampled_probabilities = {
393
+ pair: [[np.empty(0)] * num_templates for _ in range(len(cycle_depths))] for pair in pairs
394
+ }
395
+
396
+ for sampling_result, info in zip(sampling_results, wide_circuits_info, strict=True):
397
+ cycle_depth = info.cycle_depth
398
+ assert cycle_depth is not None
399
+ cycle_idx = cycle_depth_to_index[cycle_depth]
400
+ for template_idx, pair in zip(info.narrow_template_indices, info.pairs, strict=True):
401
+ pair = _canonize_pair(pair)
402
+ key = str(pair)
403
+ sampled_prob = sampling_result.get(key, np.empty(0))
404
+ sampled_probabilities[pair][cycle_idx][template_idx] = sampled_prob
405
+ return sampled_probabilities
406
+
407
+
408
+ def _reshape_simulation_results(
409
+ simulation_results: (
410
+ Sequence[Sequence[np.ndarray]] | dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]
411
+ ),
412
+ cycle_depths: Sequence[int],
413
+ pairs: Sequence[_QUBIT_PAIR_T],
414
+ num_templates: int,
415
+ ) -> _PROBABILITIES_DICT_T:
416
+ cycle_depth_to_index = {d: i for i, d in enumerate(cycle_depths)}
417
+
418
+ if isinstance(simulation_results, dict):
419
+ pure_probabilities = {
420
+ pair: [[np.empty(0)] * num_templates for _ in range(len(cycle_depths))]
421
+ for pair in pairs
422
+ }
423
+ for pair, simulation_result_for_pair in simulation_results.items():
424
+ for template_idx, template_simulation_result in enumerate(simulation_result_for_pair):
425
+ for cycle_depth, pure_probs in zip(
426
+ cycle_depths, template_simulation_result, strict=True
427
+ ):
428
+ cycle_idx = cycle_depth_to_index[cycle_depth]
429
+ pure_probabilities[pair][cycle_idx][template_idx] = pure_probs
430
+
431
+ return pure_probabilities
432
+ else:
433
+ common_pure_probs = [[np.empty(0)] * num_templates for _ in range(len(cycle_depths))]
434
+ for template_idx, template_simulation_result in enumerate(simulation_results):
435
+ for cycle_depth, pure_probs in zip(
436
+ cycle_depths, template_simulation_result, strict=True
437
+ ):
438
+ cycle_idx = cycle_depth_to_index[cycle_depth]
439
+ common_pure_probs[cycle_idx][template_idx] = pure_probs
440
+ return {pair: common_pure_probs for pair in pairs}
441
+
442
+
443
+ @attrs.frozen
444
+ class XEBFidelity:
445
+ """The estimated fidelity of a given pair at a give cycle depth.
446
+
447
+ Attributes:
448
+ pair: A qubit pair.
449
+ cycle_depth: The depth of the cycle.
450
+ fidelity: The estimated fidelity.
451
+ """
452
+
453
+ pair: _QUBIT_PAIR_T
454
+ cycle_depth: int
455
+ fidelity: float
456
+
457
+
458
+ def _cross_entropy(p: np.ndarray, q: np.ndarray, eps: float = 1e-60) -> float:
459
+ q[q <= 0] = eps # for numerical stability
460
+ return -np.dot(p, np.log2(q))
461
+
462
+
463
+ def estimate_fidelities(
464
+ sampling_results: Sequence[dict[str, np.ndarray]],
465
+ simulation_results: (
466
+ Sequence[Sequence[np.ndarray]] | dict[_QUBIT_PAIR_T, Sequence[Sequence[np.ndarray]]]
467
+ ),
468
+ cycle_depths: Sequence[int],
469
+ wide_circuits_info: Sequence[XEBWideCircuitInfo],
470
+ pairs: Sequence[_QUBIT_PAIR_T],
471
+ num_templates: int,
472
+ ) -> Sequence[XEBFidelity]:
473
+ """Estimates the fidelities from the given sampling and simulation results.
474
+
475
+ Args:
476
+ sampling_results: The result of `sample_all_circuits`.
477
+ simulation_results: The result of `simulate_circuit_library`,
478
+ cycle_depths: The sequence of cycle depths,
479
+ wide_circuits_info: Sequence of XEBWideCircuitInfo detailing describing
480
+ the sampled circuits.
481
+ pairs: The qubit pairs being tests,
482
+ num_templates: The number of circuit templates used for benchmarking,
483
+
484
+ Returns:
485
+ A sequence of XEBFidelity objects.
486
+ """
487
+
488
+ sampled_probabilities = _reshape_sampling_results(
489
+ sampling_results, cycle_depths, wide_circuits_info, pairs, num_templates
490
+ )
491
+
492
+ pure_probabilities = _reshape_simulation_results(
493
+ simulation_results, cycle_depths, pairs, num_templates
494
+ )
495
+
496
+ records = []
497
+ for pair in pairs:
498
+ for depth_idx, cycle_depth in enumerate(cycle_depths):
499
+ numerator = 0.0
500
+ denominator = 0.0
501
+ for template_idx in range(num_templates):
502
+ pure_probs = pure_probabilities[pair][depth_idx][template_idx]
503
+ sampled_probs = sampled_probabilities[pair][depth_idx][template_idx]
504
+ if len(sampled_probs) == 0:
505
+ continue
506
+ assert (
507
+ len(sampled_probs) == 4
508
+ ), f'{pair=} {cycle_depth=} {template_idx=}: {sampled_probs=}'
509
+ p_uniform = np.ones_like(pure_probs) / len(pure_probs)
510
+ pure_probs /= pure_probs.sum()
511
+ sampled_probs /= sampled_probs.sum()
512
+
513
+ h_up = _cross_entropy(p_uniform, pure_probs) # H[uniform, pure probs]
514
+ h_sp = _cross_entropy(sampled_probs, pure_probs) # H[sampled probs, pure probs]
515
+ h_pp = _cross_entropy(pure_probs, pure_probs) # H[pure probs]
516
+
517
+ y = h_up - h_sp
518
+ x = h_up - h_pp
519
+ numerator += x * y
520
+ denominator += x**2
521
+ fidelity = numerator / denominator
522
+ records.append(XEBFidelity(pair=pair, cycle_depth=cycle_depth, fidelity=fidelity))
523
+ return records
524
+
525
+
526
+ def _extract_pairs(
527
+ sampler: cirq.Sampler,
528
+ target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T],
529
+ qubits: Sequence[cirq.GridQubit] | None,
530
+ pairs: Sequence[_QUBIT_PAIR_T] | None,
531
+ ) -> Sequence[_QUBIT_PAIR_T]:
532
+ if isinstance(target, dict):
533
+ if pairs is None:
534
+ pairs = tuple(target.keys())
535
+ else:
536
+ assert target.keys() == set(pairs)
537
+ qubits, device_pairs = tqxeb.qubits_and_pairs(sampler, qubits, pairs)
538
+ device_pairs = [_canonize_pair(pair) for pair in device_pairs]
539
+ if pairs is None:
540
+ return device_pairs
541
+ else:
542
+ pairs = [_canonize_pair(p) for p in pairs]
543
+ return tuple(set(pairs) & set(device_pairs))
544
+
545
+
546
+ def parallel_xeb_workflow(
547
+ sampler: cirq.Sampler,
548
+ target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T],
549
+ ideal_target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T] | None = None,
550
+ qubits: Sequence[cirq.GridQubit] | None = None,
551
+ pairs: Sequence[_QUBIT_PAIR_T] | None = None,
552
+ parameters: XEBParameters = XEBParameters(),
553
+ rng: np.random.Generator | None = None,
554
+ pool: futures.Executor | None = None,
555
+ ) -> Sequence[XEBFidelity]:
556
+ """A utility method that runs the full XEB workflow.
557
+
558
+ Args:
559
+ sampler: The quantum engine or simulator to run the circuits.
560
+ target: The entangling gate, op, circuit or dict mapping pairs to ops.
561
+ ideal_target: The ideal target(s) to branch mark against. If None, use `target`.
562
+ qubits: Qubits under test. If None, uses all qubits on the sampler's device.
563
+ pairs: Pairs to use. If not specified, use all pairs between adjacent qubits.
564
+ parameters: An `XEBParameters` containing the parameters of the XEB experiment.
565
+ rng: The random number generator to use.
566
+ pool: An optional `concurrent.futures.Executor` pool.
567
+
568
+ Returns:
569
+ A sequence of XEBFidelity listing the estimated fidelity for each qubit_pair per depth.
570
+
571
+ Raises:
572
+ ValueError: If qubits are not specified and the sampler has no device.
573
+ """
574
+ if rng is None:
575
+ rng = np.random.default_rng()
576
+ rs = np.random.RandomState(rng.integers(0, 10**9))
577
+
578
+ pairs = _extract_pairs(sampler, target, qubits, pairs)
579
+ graph = nx.Graph(pairs)
580
+
581
+ circuit_templates = rqcg.generate_library_of_2q_circuits(
582
+ n_library_circuits=parameters.n_circuits,
583
+ random_state=rs,
584
+ # Any two qubit gate works here since we creating templates rather than the actual circuits.
585
+ two_qubit_gate=ops.CZ,
586
+ max_cycle_depth=max(parameters.cycle_depths),
587
+ )
588
+
589
+ combs_by_layer = rqcg.get_random_combinations_for_device(
590
+ n_library_circuits=len(circuit_templates),
591
+ n_combinations=parameters.n_combinations,
592
+ device_graph=graph,
593
+ random_state=rs,
594
+ )
595
+
596
+ canonical_target = _canonize_target(target)
597
+ if ideal_target is None:
598
+ canonical_ideal_target = canonical_target
599
+ else:
600
+ canonical_ideal_target = _canonize_target(ideal_target)
601
+
602
+ if isinstance(canonical_target, dict):
603
+ assert all(
604
+ all(pair in canonical_target for pair in layer_comb.pairs)
605
+ for layer_comb in combs_by_layer
606
+ )
607
+
608
+ if isinstance(canonical_ideal_target, dict):
609
+ assert all(
610
+ all(pair in canonical_ideal_target for pair in layer_comb.pairs)
611
+ for layer_comb in combs_by_layer
612
+ )
613
+
614
+ wide_circuits_info = create_combination_circuits(
615
+ circuit_templates, combs_by_layer, canonical_target
616
+ )
617
+ wide_circuits_info = [
618
+ info_with_depth
619
+ for info in wide_circuits_info
620
+ for info_with_depth in info.sliced_circuits(parameters.cycle_depths)
621
+ ]
622
+
623
+ # A map {measurement_key: sampled_probs} for each wide circuit
624
+ sampling_results = sample_all_circuits(
625
+ sampler, [info.wide_circuit for info in wide_circuits_info], parameters.n_repetitions
626
+ )
627
+
628
+ # Either of a pure_probability[circuit_template_idx][cycle_depth_index] or
629
+ # A map pure_probability[pair][circuit_template_idx][cycle_depth_index]
630
+ simulation_results = simulate_circuit_library(
631
+ circuit_templates, canonical_ideal_target, parameters.cycle_depths, pool
632
+ )
633
+
634
+ estimated_fidelities = estimate_fidelities(
635
+ sampling_results,
636
+ simulation_results,
637
+ parameters.cycle_depths,
638
+ wide_circuits_info,
639
+ pairs,
640
+ parameters.n_circuits,
641
+ )
642
+ return estimated_fidelities
643
+
644
+
645
+ def parallel_two_qubit_xeb(
646
+ sampler: cirq.Sampler,
647
+ target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T],
648
+ ideal_target: _TARGET_T | dict[_QUBIT_PAIR_T, _TARGET_T] | None = None,
649
+ qubits: Sequence[cirq.GridQubit] | None = None,
650
+ pairs: Sequence[_QUBIT_PAIR_T] | None = None,
651
+ parameters: XEBParameters = XEBParameters(),
652
+ rng: np.random.Generator | None = None,
653
+ pool: futures.Executor | None = None,
654
+ ) -> tqxeb.TwoQubitXEBResult:
655
+ """A convenience method that runs the full XEB workflow.
656
+
657
+ Args:
658
+ sampler: The quantum engine or simulator to run the circuits.
659
+ target: The entangling gate, op, circuit or dict mapping pairs to ops.
660
+ ideal_target: The ideal target(s) to branch mark against. If None, use `target`.
661
+ qubits: Qubits under test. If None, uses all qubits on the sampler's device.
662
+ pairs: Pairs to use. If not specified, use all pairs between adjacent qubits.
663
+ parameters: An `XEBParameters` containing the parameters of the XEB experiment.
664
+ rng: The random number generator to use.
665
+ pool: An optional `concurrent.futures.Executor` pool.
666
+
667
+ Returns:
668
+ A `TwoQubitXEBResult` object representing the result.
669
+
670
+ Raises:
671
+ ValueError: If qubits are not specified and the sampler has no device.
672
+ """
673
+ estimated_fidelities = parallel_xeb_workflow(
674
+ sampler, target, ideal_target, qubits, pairs, parameters, rng, pool
675
+ )
676
+ df = pd.DataFrame.from_records([attrs.asdict(ef) for ef in estimated_fidelities])
677
+ return tqxeb.TwoQubitXEBResult(xeb_fitting.fit_exponential_decays(df))