cirq-core 1.4.0.dev20240529225110__py3-none-any.whl → 1.5.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 (590) hide show
  1. cirq/__init__.py +587 -569
  2. cirq/_compat.py +9 -0
  3. cirq/_compat_test.py +11 -9
  4. cirq/_import.py +7 -8
  5. cirq/_version.py +31 -1
  6. cirq/_version_test.py +1 -1
  7. cirq/circuits/__init__.py +15 -9
  8. cirq/circuits/_block_diagram_drawer.py +1 -2
  9. cirq/circuits/_block_diagram_drawer_test.py +3 -3
  10. cirq/circuits/_box_drawing_character_data.py +0 -1
  11. cirq/circuits/_box_drawing_character_data_test.py +2 -2
  12. cirq/circuits/_bucket_priority_queue.py +0 -1
  13. cirq/circuits/_bucket_priority_queue_test.py +1 -1
  14. cirq/circuits/circuit.py +336 -234
  15. cirq/circuits/circuit_operation.py +102 -52
  16. cirq/circuits/circuit_operation_test.py +85 -4
  17. cirq/circuits/circuit_test.py +101 -32
  18. cirq/circuits/frozen_circuit.py +36 -32
  19. cirq/circuits/insert_strategy.py +10 -0
  20. cirq/circuits/insert_strategy_test.py +20 -0
  21. cirq/circuits/moment.py +79 -80
  22. cirq/circuits/moment_test.py +105 -2
  23. cirq/circuits/optimization_pass.py +15 -15
  24. cirq/circuits/optimization_pass_test.py +8 -9
  25. cirq/circuits/qasm_output.py +64 -33
  26. cirq/circuits/qasm_output_test.py +63 -2
  27. cirq/circuits/text_diagram_drawer.py +26 -56
  28. cirq/circuits/text_diagram_drawer_test.py +5 -4
  29. cirq/contrib/__init__.py +2 -2
  30. cirq/contrib/acquaintance/__init__.py +44 -29
  31. cirq/contrib/acquaintance/bipartite.py +8 -7
  32. cirq/contrib/acquaintance/bipartite_test.py +11 -1
  33. cirq/contrib/acquaintance/devices.py +5 -4
  34. cirq/contrib/acquaintance/devices_test.py +5 -1
  35. cirq/contrib/acquaintance/executor.py +18 -21
  36. cirq/contrib/acquaintance/executor_test.py +3 -2
  37. cirq/contrib/acquaintance/gates.py +36 -27
  38. cirq/contrib/acquaintance/gates_test.py +1 -1
  39. cirq/contrib/acquaintance/inspection_utils.py +10 -9
  40. cirq/contrib/acquaintance/inspection_utils_test.py +6 -1
  41. cirq/contrib/acquaintance/mutation_utils.py +10 -10
  42. cirq/contrib/acquaintance/optimizers.py +7 -6
  43. cirq/contrib/acquaintance/optimizers_test.py +1 -1
  44. cirq/contrib/acquaintance/permutation.py +22 -21
  45. cirq/contrib/acquaintance/permutation_test.py +1 -1
  46. cirq/contrib/acquaintance/shift.py +8 -6
  47. cirq/contrib/acquaintance/shift_swap_network.py +6 -4
  48. cirq/contrib/acquaintance/strategies/__init__.py +9 -3
  49. cirq/contrib/acquaintance/strategies/complete.py +4 -3
  50. cirq/contrib/acquaintance/strategies/cubic.py +5 -3
  51. cirq/contrib/acquaintance/strategies/quartic_paired.py +8 -6
  52. cirq/contrib/acquaintance/topological_sort.py +4 -2
  53. cirq/contrib/bayesian_network/__init__.py +3 -1
  54. cirq/contrib/bayesian_network/bayesian_network_gate.py +5 -3
  55. cirq/contrib/circuitdag/__init__.py +1 -1
  56. cirq/contrib/circuitdag/circuit_dag.py +24 -24
  57. cirq/contrib/circuitdag/circuit_dag_test.py +1 -1
  58. cirq/contrib/custom_simulators/custom_state_simulator.py +10 -8
  59. cirq/contrib/custom_simulators/custom_state_simulator_test.py +15 -11
  60. cirq/contrib/graph_device/__init__.py +8 -8
  61. cirq/contrib/graph_device/graph_device.py +8 -8
  62. cirq/contrib/graph_device/graph_device_test.py +0 -1
  63. cirq/contrib/graph_device/hypergraph_test.py +1 -0
  64. cirq/contrib/json.py +1 -2
  65. cirq/contrib/json_test.py +2 -2
  66. cirq/contrib/noise_models/__init__.py +5 -6
  67. cirq/contrib/noise_models/noise_models.py +8 -6
  68. cirq/contrib/paulistring/__init__.py +22 -10
  69. cirq/contrib/paulistring/clifford_optimize.py +1 -1
  70. cirq/contrib/paulistring/clifford_optimize_test.py +0 -1
  71. cirq/contrib/paulistring/clifford_target_gateset.py +15 -12
  72. cirq/contrib/paulistring/optimize.py +2 -2
  73. cirq/contrib/paulistring/optimize_test.py +0 -1
  74. cirq/contrib/paulistring/pauli_string_dag_test.py +0 -1
  75. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +379 -0
  76. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +523 -0
  77. cirq/contrib/paulistring/pauli_string_optimize.py +3 -1
  78. cirq/contrib/paulistring/pauli_string_optimize_test.py +1 -3
  79. cirq/contrib/paulistring/recombine.py +2 -2
  80. cirq/contrib/paulistring/recombine_test.py +2 -2
  81. cirq/contrib/paulistring/separate.py +3 -4
  82. cirq/contrib/qasm_import/__init__.py +2 -2
  83. cirq/contrib/qasm_import/_lexer.py +21 -26
  84. cirq/contrib/qasm_import/_lexer_test.py +90 -6
  85. cirq/contrib/qasm_import/_parser.py +238 -47
  86. cirq/contrib/qasm_import/_parser_test.py +514 -59
  87. cirq/contrib/qasm_import/qasm_test.py +1 -1
  88. cirq/contrib/qcircuit/__init__.py +6 -4
  89. cirq/contrib/qcircuit/qcircuit_diagram.py +5 -2
  90. cirq/contrib/qcircuit/qcircuit_pdf.py +1 -2
  91. cirq/{experiments/grid_parallel_two_qubit_xeb_test.py → contrib/qcircuit/qcircuit_pdf_test.py} +13 -12
  92. cirq/contrib/qcircuit/qcircuit_test.py +1 -1
  93. cirq/contrib/quantum_volume/__init__.py +7 -7
  94. cirq/contrib/quantum_volume/quantum_volume.py +6 -11
  95. cirq/contrib/quantum_volume/quantum_volume_test.py +3 -1
  96. cirq/contrib/quimb/__init__.py +16 -13
  97. cirq/contrib/quimb/density_matrix.py +1 -1
  98. cirq/contrib/quimb/mps_simulator.py +27 -28
  99. cirq/contrib/quimb/mps_simulator_test.py +5 -0
  100. cirq/contrib/quimb/state_vector.py +3 -10
  101. cirq/contrib/quirk/__init__.py +1 -1
  102. cirq/contrib/quirk/export_to_quirk.py +3 -3
  103. cirq/contrib/routing/__init__.py +12 -9
  104. cirq/contrib/routing/device.py +1 -1
  105. cirq/contrib/routing/device_test.py +1 -2
  106. cirq/contrib/routing/greedy.py +7 -5
  107. cirq/contrib/routing/greedy_test.py +5 -3
  108. cirq/contrib/routing/initialization.py +3 -1
  109. cirq/contrib/routing/initialization_test.py +1 -1
  110. cirq/contrib/routing/swap_network.py +6 -6
  111. cirq/contrib/routing/utils.py +6 -4
  112. cirq/contrib/routing/utils_test.py +1 -2
  113. cirq/{type_workarounds.py → contrib/shuffle_circuits/__init__.py} +5 -10
  114. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +250 -0
  115. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py +363 -0
  116. cirq/contrib/svg/__init__.py +1 -1
  117. cirq/contrib/svg/svg.py +12 -10
  118. cirq/contrib/svg/svg_test.py +3 -2
  119. cirq/devices/__init__.py +34 -25
  120. cirq/devices/device.py +16 -12
  121. cirq/devices/device_test.py +1 -0
  122. cirq/devices/grid_device_metadata.py +16 -12
  123. cirq/devices/grid_device_metadata_test.py +2 -1
  124. cirq/devices/grid_qubit.py +31 -26
  125. cirq/devices/grid_qubit_test.py +30 -1
  126. cirq/devices/insertion_noise_model.py +6 -6
  127. cirq/devices/insertion_noise_model_test.py +1 -1
  128. cirq/devices/line_qubit.py +28 -20
  129. cirq/devices/line_qubit_test.py +26 -0
  130. cirq/devices/named_topologies.py +12 -10
  131. cirq/devices/named_topologies_test.py +5 -4
  132. cirq/devices/noise_model.py +29 -33
  133. cirq/devices/noise_properties.py +2 -2
  134. cirq/devices/noise_properties_test.py +2 -2
  135. cirq/devices/noise_utils.py +3 -3
  136. cirq/devices/superconducting_qubits_noise_properties.py +2 -2
  137. cirq/devices/superconducting_qubits_noise_properties_test.py +3 -3
  138. cirq/devices/thermal_noise_model.py +2 -1
  139. cirq/devices/unconstrained_device.py +1 -1
  140. cirq/devices/unconstrained_device_test.py +6 -0
  141. cirq/experiments/__init__.py +51 -34
  142. cirq/experiments/qubit_characterizations.py +17 -15
  143. cirq/experiments/qubit_characterizations_test.py +4 -6
  144. cirq/experiments/random_quantum_circuit_generation.py +10 -9
  145. cirq/experiments/random_quantum_circuit_generation_test.py +21 -4
  146. cirq/experiments/readout_confusion_matrix.py +73 -8
  147. cirq/experiments/readout_confusion_matrix_test.py +104 -1
  148. cirq/experiments/single_qubit_readout_calibration.py +8 -6
  149. cirq/experiments/single_qubit_readout_calibration_test.py +1 -1
  150. cirq/experiments/t1_decay_experiment.py +4 -5
  151. cirq/experiments/t1_decay_experiment_test.py +1 -2
  152. cirq/experiments/t2_decay_experiment.py +0 -1
  153. cirq/experiments/t2_decay_experiment_test.py +1 -2
  154. cirq/experiments/two_qubit_xeb.py +157 -33
  155. cirq/experiments/two_qubit_xeb_test.py +38 -22
  156. cirq/experiments/xeb_fitting.py +99 -19
  157. cirq/experiments/xeb_fitting_test.py +64 -25
  158. cirq/experiments/xeb_sampling.py +14 -18
  159. cirq/experiments/xeb_simulation.py +4 -3
  160. cirq/experiments/xeb_simulation_test.py +20 -14
  161. cirq/experiments/z_phase_calibration.py +368 -0
  162. cirq/experiments/z_phase_calibration_test.py +241 -0
  163. cirq/interop/__init__.py +4 -1
  164. cirq/interop/quirk/__init__.py +7 -4
  165. cirq/interop/quirk/cells/__init__.py +17 -6
  166. cirq/interop/quirk/cells/arithmetic_cells.py +8 -8
  167. cirq/interop/quirk/cells/arithmetic_cells_test.py +1 -1
  168. cirq/interop/quirk/cells/cell.py +6 -6
  169. cirq/interop/quirk/cells/composite_cell.py +5 -5
  170. cirq/interop/quirk/cells/composite_cell_test.py +1 -1
  171. cirq/interop/quirk/cells/control_cells.py +1 -1
  172. cirq/interop/quirk/cells/frequency_space_cells.py +2 -2
  173. cirq/interop/quirk/cells/ignored_cells.py +1 -1
  174. cirq/interop/quirk/cells/input_cells.py +1 -1
  175. cirq/interop/quirk/cells/input_cells_test.py +1 -1
  176. cirq/interop/quirk/cells/input_rotation_cells.py +1 -1
  177. cirq/interop/quirk/cells/input_rotation_cells_test.py +1 -1
  178. cirq/interop/quirk/cells/measurement_cells.py +1 -1
  179. cirq/interop/quirk/cells/parse.py +8 -7
  180. cirq/interop/quirk/cells/parse_test.py +2 -2
  181. cirq/interop/quirk/cells/single_qubit_rotation_cells.py +1 -1
  182. cirq/interop/quirk/cells/swap_cell_test.py +1 -1
  183. cirq/interop/quirk/cells/unsupported_cells.py +1 -1
  184. cirq/interop/quirk/url_to_circuit.py +7 -7
  185. cirq/interop/quirk/url_to_circuit_test.py +1 -1
  186. cirq/ion/__init__.py +4 -2
  187. cirq/json_resolver_cache.py +15 -7
  188. cirq/linalg/__init__.py +62 -51
  189. cirq/linalg/combinators.py +4 -4
  190. cirq/linalg/combinators_test.py +4 -1
  191. cirq/linalg/decompositions.py +15 -40
  192. cirq/linalg/decompositions_test.py +16 -22
  193. cirq/linalg/diagonalize.py +1 -1
  194. cirq/linalg/diagonalize_test.py +1 -1
  195. cirq/linalg/operator_spaces.py +20 -4
  196. cirq/linalg/operator_spaces_test.py +15 -2
  197. cirq/linalg/predicates.py +3 -3
  198. cirq/linalg/predicates_test.py +1 -0
  199. cirq/linalg/tolerance.py +2 -2
  200. cirq/linalg/transformations.py +30 -12
  201. cirq/linalg/transformations_test.py +13 -0
  202. cirq/neutral_atoms/__init__.py +2 -2
  203. cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py +0 -1
  204. cirq/ops/__init__.py +172 -132
  205. cirq/ops/arithmetic_operation.py +2 -2
  206. cirq/ops/arithmetic_operation_test.py +2 -2
  207. cirq/ops/boolean_hamiltonian.py +3 -2
  208. cirq/ops/classically_controlled_operation.py +39 -12
  209. cirq/ops/classically_controlled_operation_test.py +147 -1
  210. cirq/ops/clifford_gate.py +38 -36
  211. cirq/ops/clifford_gate_test.py +75 -1
  212. cirq/ops/common_channels.py +16 -45
  213. cirq/ops/common_channels_test.py +10 -0
  214. cirq/ops/common_gate_families.py +1 -1
  215. cirq/ops/common_gate_families_test.py +1 -0
  216. cirq/ops/common_gates.py +48 -49
  217. cirq/ops/common_gates_test.py +18 -2
  218. cirq/ops/control_values.py +3 -3
  219. cirq/ops/control_values_test.py +2 -1
  220. cirq/ops/controlled_gate.py +36 -23
  221. cirq/ops/controlled_gate_test.py +70 -3
  222. cirq/ops/controlled_operation.py +6 -5
  223. cirq/ops/controlled_operation_test.py +7 -3
  224. cirq/ops/dense_pauli_string.py +11 -11
  225. cirq/ops/diagonal_gate.py +2 -2
  226. cirq/ops/diagonal_gate_test.py +1 -0
  227. cirq/ops/eigen_gate.py +16 -36
  228. cirq/ops/eigen_gate_test.py +60 -10
  229. cirq/ops/fourier_transform.py +1 -3
  230. cirq/ops/fourier_transform_test.py +2 -1
  231. cirq/ops/fsim_gate.py +42 -3
  232. cirq/ops/fsim_gate_test.py +21 -0
  233. cirq/ops/gate_operation.py +8 -8
  234. cirq/ops/gate_operation_test.py +4 -2
  235. cirq/ops/gateset_test.py +11 -2
  236. cirq/ops/global_phase_op.py +8 -7
  237. cirq/ops/global_phase_op_test.py +1 -1
  238. cirq/ops/greedy_qubit_manager_test.py +5 -0
  239. cirq/ops/identity.py +14 -4
  240. cirq/ops/identity_test.py +24 -0
  241. cirq/ops/kraus_channel.py +1 -0
  242. cirq/ops/kraus_channel_test.py +3 -1
  243. cirq/ops/linear_combinations.py +27 -21
  244. cirq/ops/linear_combinations_test.py +23 -4
  245. cirq/ops/matrix_gates.py +24 -8
  246. cirq/ops/measure_util.py +2 -2
  247. cirq/ops/measurement_gate.py +7 -4
  248. cirq/ops/measurement_gate_test.py +2 -1
  249. cirq/ops/mixed_unitary_channel.py +1 -0
  250. cirq/ops/mixed_unitary_channel_test.py +3 -1
  251. cirq/ops/named_qubit.py +8 -1
  252. cirq/ops/op_tree.py +3 -30
  253. cirq/ops/op_tree_test.py +4 -0
  254. cirq/ops/parallel_gate.py +2 -3
  255. cirq/ops/parallel_gate_test.py +2 -1
  256. cirq/ops/parity_gates.py +7 -8
  257. cirq/ops/parity_gates_test.py +1 -0
  258. cirq/ops/pauli_gates.py +5 -11
  259. cirq/ops/pauli_gates_test.py +1 -0
  260. cirq/ops/pauli_interaction_gate.py +11 -5
  261. cirq/ops/pauli_interaction_gate_test.py +2 -3
  262. cirq/ops/pauli_measurement_gate.py +6 -5
  263. cirq/ops/pauli_measurement_gate_test.py +1 -0
  264. cirq/ops/pauli_string.py +115 -130
  265. cirq/ops/pauli_string_phasor.py +21 -20
  266. cirq/ops/pauli_string_phasor_test.py +13 -3
  267. cirq/ops/pauli_string_raw_types.py +1 -0
  268. cirq/ops/pauli_string_test.py +192 -55
  269. cirq/ops/pauli_sum_exponential.py +3 -4
  270. cirq/ops/pauli_sum_exponential_test.py +0 -1
  271. cirq/ops/permutation_gate.py +2 -2
  272. cirq/ops/permutation_gate_test.py +1 -1
  273. cirq/ops/phased_iswap_gate.py +6 -7
  274. cirq/ops/phased_iswap_gate_test.py +21 -5
  275. cirq/ops/phased_x_gate.py +11 -25
  276. cirq/ops/phased_x_gate_test.py +19 -3
  277. cirq/ops/phased_x_z_gate.py +12 -11
  278. cirq/ops/projector.py +4 -5
  279. cirq/ops/qubit_manager.py +2 -1
  280. cirq/ops/qubit_manager_test.py +2 -1
  281. cirq/ops/qubit_order.py +1 -1
  282. cirq/ops/random_gate_channel.py +1 -1
  283. cirq/ops/random_gate_channel_test.py +0 -6
  284. cirq/ops/raw_types.py +146 -50
  285. cirq/ops/raw_types_test.py +37 -3
  286. cirq/ops/state_preparation_channel.py +2 -2
  287. cirq/ops/state_preparation_channel_test.py +2 -1
  288. cirq/ops/swap_gates.py +9 -4
  289. cirq/ops/three_qubit_gates.py +8 -8
  290. cirq/ops/three_qubit_gates_test.py +1 -0
  291. cirq/ops/two_qubit_diagonal_gate.py +4 -3
  292. cirq/ops/uniform_superposition_gate.py +4 -4
  293. cirq/ops/uniform_superposition_gate_test.py +1 -0
  294. cirq/ops/wait_gate.py +6 -8
  295. cirq/protocols/__init__.py +135 -83
  296. cirq/protocols/act_on_protocol.py +1 -1
  297. cirq/protocols/act_on_protocol_test.py +1 -1
  298. cirq/protocols/apply_channel_protocol.py +3 -3
  299. cirq/protocols/apply_mixture_protocol.py +15 -9
  300. cirq/protocols/apply_mixture_protocol_test.py +11 -0
  301. cirq/protocols/apply_unitary_protocol.py +2 -2
  302. cirq/protocols/apply_unitary_protocol_test.py +2 -1
  303. cirq/protocols/approximate_equality_protocol.py +7 -8
  304. cirq/protocols/approximate_equality_protocol_test.py +3 -1
  305. cirq/protocols/circuit_diagram_info_protocol.py +8 -6
  306. cirq/protocols/circuit_diagram_info_protocol_test.py +5 -0
  307. cirq/protocols/commutes_protocol.py +6 -6
  308. cirq/protocols/control_key_protocol.py +1 -1
  309. cirq/protocols/decompose_protocol.py +4 -5
  310. cirq/protocols/decompose_protocol_test.py +2 -1
  311. cirq/protocols/equal_up_to_global_phase_protocol.py +3 -3
  312. cirq/protocols/equal_up_to_global_phase_protocol_test.py +7 -0
  313. cirq/protocols/has_stabilizer_effect_protocol.py +5 -5
  314. cirq/protocols/has_unitary_protocol.py +1 -1
  315. cirq/protocols/has_unitary_protocol_test.py +8 -7
  316. cirq/protocols/hash_from_pickle_test.py +120 -0
  317. cirq/protocols/inverse_protocol.py +1 -1
  318. cirq/protocols/json_serialization.py +14 -1
  319. cirq/protocols/json_serialization_test.py +28 -7
  320. cirq/protocols/json_test_data/BitMaskKeyCondition.json +86 -0
  321. cirq/protocols/json_test_data/BitMaskKeyCondition.repr +7 -0
  322. cirq/protocols/json_test_data/Concat.json +19 -0
  323. cirq/protocols/json_test_data/Concat.repr +1 -0
  324. cirq/protocols/json_test_data/README.md +4 -2
  325. cirq/protocols/json_test_data/SympyCondition.json +60 -15
  326. cirq/protocols/json_test_data/SympyCondition.repr +4 -1
  327. cirq/protocols/json_test_data/_InverseCompositeGate.json +10 -0
  328. cirq/protocols/json_test_data/_InverseCompositeGate.repr +1 -0
  329. cirq/protocols/json_test_data/__init__.py +1 -1
  330. cirq/protocols/json_test_data/sympy.And.json +13 -0
  331. cirq/protocols/json_test_data/sympy.And.repr +1 -0
  332. cirq/protocols/json_test_data/sympy.Indexed.json +18 -0
  333. cirq/protocols/json_test_data/sympy.Indexed.repr +1 -0
  334. cirq/protocols/json_test_data/sympy.IndexedBase.json +9 -0
  335. cirq/protocols/json_test_data/sympy.IndexedBase.repr +1 -0
  336. cirq/protocols/json_test_data/sympy.Not.json +9 -0
  337. cirq/protocols/json_test_data/sympy.Not.repr +1 -0
  338. cirq/protocols/json_test_data/sympy.Or.json +13 -0
  339. cirq/protocols/json_test_data/sympy.Or.repr +1 -0
  340. cirq/protocols/json_test_data/sympy.Xor.json +13 -0
  341. cirq/protocols/json_test_data/sympy.Xor.repr +1 -0
  342. cirq/protocols/kraus_protocol.py +8 -8
  343. cirq/protocols/kraus_protocol_test.py +0 -1
  344. cirq/protocols/measurement_key_protocol.py +1 -1
  345. cirq/protocols/measurement_key_protocol_test.py +7 -7
  346. cirq/protocols/mixture_protocol.py +6 -4
  347. cirq/protocols/mixture_protocol_test.py +21 -13
  348. cirq/protocols/pauli_expansion_protocol.py +1 -0
  349. cirq/protocols/pow_protocol.py +1 -1
  350. cirq/protocols/qasm.py +25 -6
  351. cirq/protocols/qasm_test.py +17 -0
  352. cirq/protocols/qid_shape_protocol.py +2 -2
  353. cirq/protocols/resolve_parameters.py +2 -3
  354. cirq/protocols/resolve_parameters_test.py +2 -1
  355. cirq/protocols/trace_distance_bound.py +1 -1
  356. cirq/protocols/trace_distance_bound_test.py +1 -0
  357. cirq/protocols/unitary_protocol.py +3 -3
  358. cirq/protocols/unitary_protocol_test.py +1 -1
  359. cirq/qis/__init__.py +48 -35
  360. cirq/qis/channels_test.py +0 -9
  361. cirq/qis/clifford_tableau.py +46 -26
  362. cirq/qis/clifford_tableau_test.py +2 -1
  363. cirq/qis/entropy.py +115 -0
  364. cirq/qis/entropy_test.py +43 -0
  365. cirq/qis/measures.py +5 -4
  366. cirq/qis/measures_test.py +7 -0
  367. cirq/qis/noise_utils_test.py +4 -4
  368. cirq/qis/quantum_state_representation.py +1 -1
  369. cirq/qis/states.py +7 -7
  370. cirq/sim/__init__.py +55 -37
  371. cirq/sim/classical_simulator.py +7 -6
  372. cirq/sim/classical_simulator_test.py +3 -1
  373. cirq/sim/clifford/__init__.py +17 -9
  374. cirq/sim/clifford/clifford_simulator.py +5 -4
  375. cirq/sim/clifford/clifford_simulator_test.py +32 -9
  376. cirq/sim/clifford/clifford_tableau_simulation_state.py +1 -1
  377. cirq/sim/clifford/stabilizer_simulation_state.py +1 -1
  378. cirq/sim/clifford/stabilizer_state_ch_form.py +4 -3
  379. cirq/sim/density_matrix_simulator.py +3 -2
  380. cirq/sim/density_matrix_simulator_test.py +12 -4
  381. cirq/sim/density_matrix_utils.py +1 -1
  382. cirq/sim/mux.py +2 -2
  383. cirq/sim/simulation_state.py +4 -5
  384. cirq/sim/simulation_state_base.py +2 -2
  385. cirq/sim/simulation_state_test.py +1 -1
  386. cirq/sim/simulation_utils.py +3 -1
  387. cirq/sim/simulation_utils_test.py +2 -3
  388. cirq/sim/simulator.py +7 -6
  389. cirq/sim/simulator_base.py +5 -5
  390. cirq/sim/simulator_test.py +14 -3
  391. cirq/sim/sparse_simulator.py +4 -3
  392. cirq/sim/sparse_simulator_test.py +17 -9
  393. cirq/sim/state_vector.py +2 -2
  394. cirq/sim/state_vector_simulation_state_test.py +1 -1
  395. cirq/sim/state_vector_simulator.py +4 -4
  396. cirq/sim/state_vector_test.py +27 -32
  397. cirq/study/__init__.py +27 -21
  398. cirq/study/flatten_expressions.py +5 -6
  399. cirq/study/flatten_expressions_test.py +1 -1
  400. cirq/study/resolver.py +14 -11
  401. cirq/study/resolver_test.py +10 -1
  402. cirq/study/result.py +3 -3
  403. cirq/study/sweepable.py +15 -9
  404. cirq/study/sweepable_test.py +27 -0
  405. cirq/study/sweeps.py +65 -10
  406. cirq/study/sweeps_test.py +123 -0
  407. cirq/testing/__init__.py +86 -57
  408. cirq/testing/_compat_test_data/module_a/__init__.py +2 -2
  409. cirq/testing/_compat_test_data/module_a/sub/subsub/__init__.py +1 -1
  410. cirq/testing/circuit_compare.py +3 -4
  411. cirq/testing/circuit_compare_test.py +7 -8
  412. cirq/testing/consistent_act_on.py +3 -3
  413. cirq/testing/consistent_channels_test.py +2 -1
  414. cirq/testing/consistent_controlled_gate_op.py +3 -2
  415. cirq/testing/consistent_controlled_gate_op_test.py +2 -3
  416. cirq/testing/consistent_decomposition.py +1 -1
  417. cirq/testing/consistent_decomposition_test.py +1 -2
  418. cirq/testing/consistent_pauli_expansion_test.py +1 -1
  419. cirq/testing/consistent_phase_by.py +1 -1
  420. cirq/testing/consistent_phase_by_test.py +1 -2
  421. cirq/testing/consistent_protocols.py +11 -11
  422. cirq/testing/consistent_protocols_test.py +4 -5
  423. cirq/testing/consistent_qasm.py +8 -12
  424. cirq/testing/consistent_qasm_test.py +1 -1
  425. cirq/testing/consistent_resolve_parameters.py +2 -1
  426. cirq/testing/consistent_specified_has_unitary_test.py +1 -1
  427. cirq/testing/consistent_unitary.py +3 -1
  428. cirq/testing/consistent_unitary_test.py +3 -3
  429. cirq/testing/devices.py +1 -1
  430. cirq/testing/devices_test.py +1 -0
  431. cirq/testing/equals_tester.py +2 -4
  432. cirq/testing/equals_tester_test.py +6 -5
  433. cirq/testing/equivalent_basis_map.py +1 -0
  434. cirq/testing/equivalent_basis_map_test.py +0 -1
  435. cirq/testing/gate_features_test.py +5 -0
  436. cirq/testing/json.py +4 -4
  437. cirq/testing/lin_alg_utils_test.py +1 -1
  438. cirq/testing/order_tester.py +1 -1
  439. cirq/testing/order_tester_test.py +1 -1
  440. cirq/testing/pytest_utils.py +57 -0
  441. cirq/testing/pytest_utils_test.py +35 -0
  442. cirq/testing/random_circuit.py +2 -2
  443. cirq/testing/random_circuit_test.py +2 -2
  444. cirq/testing/routing_devices_test.py +2 -1
  445. cirq/testing/sample_circuits.py +1 -1
  446. cirq/testing/sample_gates.py +5 -4
  447. cirq/testing/sample_gates_test.py +2 -2
  448. cirq/transformers/__init__.py +101 -82
  449. cirq/transformers/align.py +12 -1
  450. cirq/transformers/align_test.py +13 -0
  451. cirq/transformers/analytical_decompositions/__init__.py +27 -24
  452. cirq/transformers/analytical_decompositions/clifford_decomposition.py +2 -1
  453. cirq/transformers/analytical_decompositions/clifford_decomposition_test.py +1 -1
  454. cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +1 -1
  455. cirq/transformers/analytical_decompositions/controlled_gate_decomposition_test.py +2 -0
  456. cirq/transformers/analytical_decompositions/cphase_to_fsim.py +1 -1
  457. cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +1 -1
  458. cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +2 -2
  459. cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +4 -4
  460. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +99 -24
  461. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +105 -14
  462. cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +1 -1
  463. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry.py +1 -1
  464. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry_test.py +1 -0
  465. cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +3 -4
  466. cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +1 -1
  467. cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +2 -1
  468. cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +2 -1
  469. cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +5 -6
  470. cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +2 -2
  471. cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +1 -1
  472. cirq/transformers/analytical_decompositions/two_qubit_to_fsim_test.py +1 -2
  473. cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +2 -2
  474. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +2 -2
  475. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap_test.py +2 -1
  476. cirq/transformers/drop_empty_moments.py +1 -0
  477. cirq/transformers/drop_negligible_operations.py +1 -0
  478. cirq/transformers/dynamical_decoupling.py +255 -43
  479. cirq/transformers/dynamical_decoupling_test.py +730 -17
  480. cirq/transformers/eject_phased_paulis.py +29 -15
  481. cirq/transformers/eject_phased_paulis_test.py +3 -8
  482. cirq/transformers/eject_z.py +3 -2
  483. cirq/transformers/eject_z_test.py +3 -3
  484. cirq/transformers/gauge_compiling/__init__.py +25 -9
  485. cirq/transformers/gauge_compiling/cphase_gauge.py +146 -0
  486. cirq/transformers/gauge_compiling/cphase_gauge_test.py +42 -0
  487. cirq/transformers/gauge_compiling/cz_gauge.py +4 -4
  488. cirq/transformers/gauge_compiling/gauge_compiling.py +245 -6
  489. cirq/transformers/gauge_compiling/gauge_compiling_test.py +107 -2
  490. cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +39 -2
  491. cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +10 -1
  492. cirq/transformers/gauge_compiling/iswap_gauge.py +2 -2
  493. cirq/transformers/gauge_compiling/spin_inversion_gauge.py +2 -2
  494. cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +23 -5
  495. cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +3 -2
  496. cirq/transformers/heuristic_decompositions/__init__.py +3 -3
  497. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +2 -1
  498. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils_test.py +1 -1
  499. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +4 -4
  500. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation_test.py +4 -4
  501. cirq/transformers/insertion_sort.py +64 -0
  502. cirq/transformers/insertion_sort_test.py +34 -0
  503. cirq/transformers/measurement_transformers.py +14 -1
  504. cirq/transformers/measurement_transformers_test.py +35 -0
  505. cirq/transformers/merge_k_qubit_gates.py +2 -2
  506. cirq/transformers/merge_single_qubit_gates.py +1 -1
  507. cirq/transformers/merge_single_qubit_gates_test.py +1 -1
  508. cirq/transformers/noise_adding.py +115 -0
  509. cirq/transformers/noise_adding_test.py +54 -0
  510. cirq/transformers/optimize_for_target_gateset.py +1 -1
  511. cirq/transformers/optimize_for_target_gateset_test.py +3 -2
  512. cirq/transformers/qubit_management_transformers.py +1 -1
  513. cirq/transformers/randomized_measurements.py +171 -0
  514. cirq/transformers/randomized_measurements_test.py +68 -0
  515. cirq/transformers/routing/__init__.py +14 -5
  516. cirq/transformers/routing/initial_mapper.py +1 -1
  517. cirq/transformers/routing/initial_mapper_test.py +1 -0
  518. cirq/transformers/routing/line_initial_mapper.py +3 -2
  519. cirq/transformers/routing/mapping_manager.py +2 -2
  520. cirq/transformers/routing/mapping_manager_test.py +2 -2
  521. cirq/transformers/routing/route_circuit_cqc.py +3 -2
  522. cirq/transformers/routing/route_circuit_cqc_test.py +2 -1
  523. cirq/transformers/routing/visualize_routed_circuit.py +1 -0
  524. cirq/transformers/routing/visualize_routed_circuit_test.py +1 -0
  525. cirq/transformers/stratify.py +2 -2
  526. cirq/transformers/synchronize_terminal_measurements.py +2 -1
  527. cirq/transformers/target_gatesets/__init__.py +7 -5
  528. cirq/transformers/target_gatesets/compilation_target_gateset.py +16 -3
  529. cirq/transformers/target_gatesets/compilation_target_gateset_test.py +2 -0
  530. cirq/transformers/target_gatesets/cz_gateset.py +5 -1
  531. cirq/transformers/target_gatesets/cz_gateset_test.py +23 -2
  532. cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +1 -1
  533. cirq/transformers/target_gatesets/sqrt_iswap_gateset_test.py +3 -2
  534. cirq/transformers/transformer_api.py +5 -4
  535. cirq/transformers/transformer_api_test.py +11 -3
  536. cirq/transformers/transformer_primitives.py +9 -31
  537. cirq/transformers/transformer_primitives_test.py +6 -5
  538. cirq/value/__init__.py +51 -30
  539. cirq/value/abc_alt.py +1 -2
  540. cirq/value/angle.py +2 -0
  541. cirq/value/classical_data.py +1 -0
  542. cirq/value/condition.py +149 -3
  543. cirq/value/condition_test.py +254 -0
  544. cirq/value/digits.py +1 -1
  545. cirq/value/duration.py +4 -4
  546. cirq/value/duration_test.py +2 -1
  547. cirq/value/linear_dict.py +85 -24
  548. cirq/value/linear_dict_test.py +94 -3
  549. cirq/value/measurement_key.py +9 -2
  550. cirq/value/periodic_value.py +2 -3
  551. cirq/value/periodic_value_test.py +5 -0
  552. cirq/value/probability.py +1 -0
  553. cirq/value/random_state.py +1 -1
  554. cirq/value/timestamp.py +2 -4
  555. cirq/value/timestamp_test.py +2 -1
  556. cirq/value/type_alias.py +2 -2
  557. cirq/value/value_equality_attr.py +14 -2
  558. cirq/value/value_equality_attr_test.py +1 -1
  559. cirq/vis/__init__.py +9 -6
  560. cirq/vis/density_matrix.py +1 -1
  561. cirq/vis/density_matrix_test.py +2 -5
  562. cirq/vis/heatmap.py +49 -12
  563. cirq/vis/heatmap_test.py +168 -4
  564. cirq/vis/histogram.py +1 -1
  565. cirq/vis/histogram_test.py +1 -2
  566. cirq/vis/state_histogram.py +7 -5
  567. cirq/vis/state_histogram_test.py +2 -2
  568. cirq/work/__init__.py +19 -13
  569. cirq/work/collector.py +2 -2
  570. cirq/work/observable_grouping.py +2 -2
  571. cirq/work/observable_measurement.py +3 -3
  572. cirq/work/observable_measurement_data.py +5 -2
  573. cirq/work/observable_measurement_test.py +8 -8
  574. cirq/work/observable_readout_calibration.py +2 -2
  575. cirq/work/observable_readout_calibration_test.py +2 -1
  576. cirq/work/observable_settings.py +8 -7
  577. cirq/work/observable_settings_test.py +3 -2
  578. cirq/work/pauli_sum_collector.py +1 -1
  579. cirq/work/sampler.py +8 -20
  580. cirq/work/sampler_test.py +4 -3
  581. cirq/work/zeros_sampler.py +1 -1
  582. cirq_core-1.5.0.dist-info/METADATA +125 -0
  583. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/RECORD +586 -552
  584. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/WHEEL +1 -1
  585. cirq/experiments/grid_parallel_two_qubit_xeb.py +0 -62
  586. cirq/protocols/json_test_data/GridParallelXEBMetadata.json +0 -119
  587. cirq/protocols/json_test_data/GridParallelXEBMetadata.repr +0 -1
  588. cirq_core-1.4.0.dev20240529225110.dist-info/METADATA +0 -50
  589. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/LICENSE +0 -0
  590. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/top_level.txt +0 -0
@@ -15,11 +15,13 @@
15
15
  """Utilities to compute readout confusion matrix and use it for readout error mitigation."""
16
16
 
17
17
  import time
18
- from typing import Any, Dict, Union, Sequence, List, Tuple, TYPE_CHECKING, Optional, cast
19
- import sympy
18
+ from typing import Any, cast, Dict, List, Optional, Sequence, Tuple, TYPE_CHECKING, Union
19
+
20
20
  import numpy as np
21
21
  import scipy.optimize
22
- from cirq import circuits, ops, vis, study
22
+ import sympy
23
+
24
+ from cirq import circuits, ops, study, vis
23
25
  from cirq._compat import proper_repr
24
26
 
25
27
  if TYPE_CHECKING:
@@ -31,7 +33,7 @@ class TensoredConfusionMatrices:
31
33
 
32
34
  The confusion matrix (CM) for one qubit is:
33
35
 
34
- [ Pr(0|0) Pr(1|0) ]
36
+ [ Pr(0|0) Pr(0|1) ]
35
37
  [ Pr(1|0) Pr(1|1) ]
36
38
 
37
39
  where Pr(i | j) = Probability of observing state "i" given state "j" was prepared.
@@ -71,7 +73,7 @@ class TensoredConfusionMatrices:
71
73
  confusion_matrices: Sequence of confusion matrices, computed for qubit patterns present
72
74
  in `measure_qubits`. A single confusion matrix is also accepted.
73
75
  measure_qubits: Sequence of smaller qubit patterns, for which the confusion matrices
74
- were computed. A single qubit pattern is also accepted. Note that the
76
+ were computed. A single qubit pattern is also accepted. Note that
75
77
  each qubit pattern is a sequence of qubits used to label the axes of
76
78
  the corresponding confusion matrix.
77
79
  repetitions: The number of repetitions that were used to estimate the confusion
@@ -173,13 +175,12 @@ class TensoredConfusionMatrices:
173
175
  return in_vars + out_vars
174
176
 
175
177
  def _confusion_matrix(self, qubits: Sequence['cirq.Qid']) -> np.ndarray:
176
- ein_input = []
178
+ ein_input: List[np.ndarray | List[int]] = []
177
179
  for qs, cm in zip(self.measure_qubits, self.confusion_matrices):
178
180
  ein_input.extend([cm.reshape((2, 2) * len(qs)), self._get_vars(qs)])
179
181
  ein_out = self._get_vars(qubits)
180
182
 
181
- # TODO(#5757): remove type ignore when numpy has proper override signature.
182
- ret = np.einsum(*ein_input, ein_out).reshape((2 ** len(qubits),) * 2) # type: ignore
183
+ ret = np.einsum(*ein_input, ein_out).reshape((2 ** len(qubits),) * 2)
183
184
  return ret / ret.sum(axis=1)
184
185
 
185
186
  def confusion_matrix(self, qubits: Optional[Sequence['cirq.Qid']] = None) -> np.ndarray:
@@ -298,6 +299,70 @@ class TensoredConfusionMatrices:
298
299
  ) # pragma: no cover
299
300
  return res.x
300
301
 
302
+ def readout_mitigation_pauli_uncorrelated(
303
+ self, qubits: Sequence['cirq.Qid'], measured_bitstrings: np.ndarray
304
+ ) -> tuple[float, float]:
305
+ r"""Uncorrelated readout error mitigation for a multi-qubit Pauli operator.
306
+
307
+ This function scalably performs readout error mitigation on an arbitrary-length Pauli
308
+ operator. It is a reimplementation of https://github.com/eliottrosenberg/correlated_SPAM
309
+ but specialized to the case in which readout is uncorrelated. We require that the confusion
310
+ matrix is a tensor product of single-qubit confusion matrices. We then invert the confusion
311
+ matrix by inverting each of the $C^{(q)}$ Then, in a bit-by-bit fashion, we apply the
312
+ inverses of the single-site confusion matrices to the bits of the measured bitstring,
313
+ contract them with the single-site Pauli operator, and take the product over all of the
314
+ bits. This could be generalized to tensor product spaces that are larger than single qubits,
315
+ but the essential simplification is that each tensor product space is small, so that none of
316
+ the response matrices is exponentially large.
317
+
318
+ This can result in mitigated Pauli operators that are not in the range [-1, 1], but if
319
+ the readout error is indeed uncorrelated and well-characterized, then it should converge
320
+ to being within this range. Results are improved both by a more precise characterization
321
+ of the response matrices (whose statistical uncertainty is not accounted for in the error
322
+ propagation here) and by increasing the number of measured bitstrings.
323
+
324
+ Args:
325
+ qubits: The qubits on which the Pauli operator acts.
326
+ measured_bitstrings: The experimentally measured bitstrings in the eigenbasis of the
327
+ Pauli operator. measured_bitstrings[i,j] is the ith bitstring, qubit j.
328
+
329
+ Returns:
330
+ The error-mitigated expectation value of the Pauli operator and its statistical
331
+ uncertainty (not including the uncertainty in the confusion matrices for now).
332
+
333
+ Raises:
334
+ NotImplementedError: If the confusion matrix is not a tensor product of single-qubit
335
+ confusion matrices for all of `qubits`.
336
+ """
337
+
338
+ # in case given as an array of bools, convert to an array of ints:
339
+ measured_bitstrings = measured_bitstrings.astype(int)
340
+
341
+ # get all of the confusion matrices
342
+ cm_all = []
343
+ for qubit in qubits:
344
+ try:
345
+ idx = self.measure_qubits.index((qubit,))
346
+ except: # pragma: no cover
347
+ raise NotImplementedError(
348
+ "The response matrix must be a tensor product of single-qu"
349
+ + f"bit response matrices, including that of qubit {qubit}."
350
+ )
351
+ cm_all.append(self.confusion_matrices[idx])
352
+
353
+ # get the correction matrices, assuming uncorrelated readout:
354
+ cminv_all = [np.linalg.inv(cm) for cm in cm_all]
355
+
356
+ # next, contract them with the single-qubit Pauli operators:
357
+ z = np.array([1, -1])
358
+ z_cminv_all = np.array([z @ cminv for cminv in cminv_all])
359
+
360
+ # finally, mitigate each bitstring:
361
+ z_mit_all_shots = np.prod(np.einsum("iji->ij", z_cminv_all[:, measured_bitstrings]), axis=0)
362
+
363
+ # return mean and statistical uncertainty:
364
+ return np.mean(z_mit_all_shots), np.std(z_mit_all_shots) / np.sqrt(len(measured_bitstrings))
365
+
301
366
  def __repr__(self) -> str:
302
367
  return (
303
368
  f"cirq.TensoredConfusionMatrices("
@@ -13,12 +13,40 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import numpy as np
16
- import cirq
17
16
  import pytest
18
17
 
18
+ import cirq
19
+ from cirq.experiments.readout_confusion_matrix import TensoredConfusionMatrices
19
20
  from cirq.experiments.single_qubit_readout_calibration_test import NoisySingleQubitReadoutSampler
20
21
 
21
22
 
23
+ def add_readout_error(
24
+ measurements: np.ndarray,
25
+ zero_errors: np.ndarray,
26
+ one_errors: np.ndarray,
27
+ rng: np.random.Generator,
28
+ ) -> np.ndarray:
29
+ """Add readout errors to measured (or simulated) bitstrings.
30
+
31
+ Args:
32
+ measurements: The bitstrings to which we will add readout errors. measurements[i,j] is the
33
+ ith bitstring, qubit j.
34
+ zero_errors: zero_errors[i] is the probability of a 0->1 readout error on qubit i.
35
+ one_errors: one_errors[i] is the probability of a 1->0 readout error on qubit i.
36
+ rng: The pseudorandom number generator to use.
37
+
38
+ Returns:
39
+ New measurements but with readout errors added.
40
+ """
41
+ num_bitstrs, n = measurements.shape
42
+ assert len(zero_errors) == len(one_errors) == n
43
+ # compute the probability that each bit is 1 after adding readout errors:
44
+ p1 = measurements * (1 - one_errors) + (1 - measurements) * zero_errors
45
+ r = rng.random((num_bitstrs, n))
46
+ noisy_measurements = r < p1
47
+ return noisy_measurements.astype(int)
48
+
49
+
22
50
  def get_expected_cm(num_qubits: int, p0: float, p1: float):
23
51
  expected_cm = np.zeros((2**num_qubits,) * 2)
24
52
  for i in range(2**num_qubits):
@@ -159,3 +187,78 @@ def test_readout_confusion_matrix_repr_and_equality():
159
187
  eq.add_equality_group(a, a)
160
188
  eq.add_equality_group(b, b)
161
189
  eq.add_equality_group(c, c)
190
+
191
+
192
+ def _sample_ghz(n: int, repetitions: int, rng: np.random.Generator) -> np.ndarray:
193
+ """Sample a GHZ state in the z basis.
194
+ Args:
195
+ n: The number of qubits.
196
+ repetitions: The number of repetitions.
197
+ rng: The pseudorandom number generator to use.
198
+ Returns:
199
+ An array of the measurement outcomes.
200
+ """
201
+ return np.tile(rng.integers(0, 2, size=repetitions), (n, 1)).T
202
+
203
+
204
+ def _add_noise_and_mitigate_ghz(
205
+ n: int,
206
+ repetitions: int,
207
+ zero_errors: np.ndarray,
208
+ one_errors: np.ndarray,
209
+ rng: np.random.Generator | None = None,
210
+ ) -> tuple[float, float, float, float]:
211
+ """Add readout error to GHZ-like bitstrings and measure <ZZZ...> with and
212
+ without readout error mitigation.
213
+ Args:
214
+ n: The number of qubits.
215
+ repetitions: The number of repetitions.
216
+ zero_errors: zero_errors[i] is the probability of a 0->1 readout error on qubit i.
217
+ one_errors: one_errors[i] is the probability of a 1->0 readout error on qubit i.
218
+ rng: The pseudorandom number generator to use.
219
+ Returns:
220
+ A tuple of:
221
+ - The mitigated expectation value of <ZZZ...>
222
+ - The statistical uncertainty of the previous output
223
+ - The unmitigated expectation value of <ZZZ...>
224
+ - The statstical uncertainty of the previous output
225
+ """
226
+ if rng is None:
227
+ rng = np.random.default_rng(0)
228
+ confusion_matrices = [
229
+ np.array([[1 - e0, e1], [e0, 1 - e1]]) for e0, e1 in zip(zero_errors, one_errors)
230
+ ]
231
+ qubits = cirq.LineQubit.range(n)
232
+ tcm = TensoredConfusionMatrices(
233
+ confusion_matrices, [[q] for q in qubits], repetitions=0, timestamp=0.0
234
+ )
235
+
236
+ measurements = _sample_ghz(n, repetitions, rng)
237
+ noisy_measurements = add_readout_error(measurements, zero_errors, one_errors, rng)
238
+ # unmitigated:
239
+ p1 = np.mean(np.sum(noisy_measurements, axis=1) % 2)
240
+ z = 1 - 2 * np.mean(p1)
241
+ dz = 2 * np.sqrt(p1 * (1 - p1) / repetitions)
242
+ # return mitigated and unmitigated:
243
+ return (*tcm.readout_mitigation_pauli_uncorrelated(qubits, noisy_measurements), z, dz)
244
+
245
+
246
+ def test_uncorrelated_readout_mitigation_pauli():
247
+ n_all = np.arange(2, 35)
248
+ z_all_mit = []
249
+ dz_all_mit = []
250
+ z_all_raw = []
251
+ dz_all_raw = []
252
+ repetitions = 10_000
253
+ for n in n_all:
254
+ e0 = np.ones(n) * 0.005
255
+ e1 = np.ones(n) * 0.03
256
+ z_mit, dz_mit, z_raw, dz_raw = _add_noise_and_mitigate_ghz(n, repetitions, e0, e1)
257
+ z_all_mit.append(z_mit)
258
+ dz_all_mit.append(dz_mit)
259
+ z_all_raw.append(z_raw)
260
+ dz_all_raw.append(dz_raw)
261
+
262
+ for n, z, dz in zip(n_all, z_all_mit, dz_all_mit):
263
+ ideal = 1.0 if n % 2 == 0 else 0.0
264
+ assert np.isclose(z, ideal, atol=4 * dz)
@@ -14,15 +14,16 @@
14
14
  """Single qubit readout experiments using parallel or isolated statistics."""
15
15
  import dataclasses
16
16
  import time
17
- from typing import Any, Dict, Iterable, List, Optional, TYPE_CHECKING
17
+ from typing import Any, cast, Dict, Iterable, List, Optional, TYPE_CHECKING
18
18
 
19
- import sympy
20
- import numpy as np
21
19
  import matplotlib.pyplot as plt
20
+ import numpy as np
21
+ import sympy
22
+
22
23
  import cirq.vis.heatmap as cirq_heatmap
23
24
  import cirq.vis.histogram as cirq_histogram
24
- from cirq.devices import grid_qubit
25
25
  from cirq import circuits, ops, study
26
+ from cirq.devices import grid_qubit
26
27
 
27
28
  if TYPE_CHECKING:
28
29
  import cirq
@@ -77,8 +78,9 @@ class SingleQubitReadoutCalibrationResult:
77
78
  """
78
79
 
79
80
  if axs is None:
80
- _, axs = plt.subplots(1, 2, dpi=200, facecolor='white', figsize=(12, 4))
81
-
81
+ _, axs_v = plt.subplots(1, 2, dpi=200, facecolor='white', figsize=(12, 4))
82
+ axs_v = cast(np.ndarray, axs_v)
83
+ axs = cast(tuple[plt.Axes, plt.Axes], (axs_v[0], axs_v[1]))
82
84
  else:
83
85
  if (
84
86
  not isinstance(axs, (tuple, list, np.ndarray))
@@ -12,9 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  from typing import Sequence
15
- import pytest
16
15
 
17
16
  import numpy as np
17
+ import pytest
18
18
 
19
19
  import cirq
20
20
 
@@ -12,16 +12,15 @@
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, Optional, Sequence, TYPE_CHECKING, cast
16
-
17
15
  import warnings
16
+ from typing import Any, cast, Optional, Sequence, TYPE_CHECKING
17
+
18
+ import numpy as np
18
19
  import pandas as pd
19
20
  import sympy
20
21
  from matplotlib import pyplot as plt
21
- import numpy as np
22
-
23
22
 
24
- from cirq import circuits, ops, study, value, _import
23
+ from cirq import _import, circuits, ops, study, value
25
24
  from cirq._compat import proper_repr
26
25
 
27
26
  if TYPE_CHECKING:
@@ -12,10 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import pytest
16
-
17
15
  import numpy as np
18
16
  import pandas as pd
17
+ import pytest
19
18
  import sympy
20
19
 
21
20
  import cirq
@@ -12,7 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  import enum
15
-
16
15
  from typing import Any, List, Optional, TYPE_CHECKING, Union
17
16
 
18
17
  import pandas as pd
@@ -12,9 +12,8 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import pytest
16
-
17
15
  import pandas as pd
16
+ import pytest
18
17
  import sympy
19
18
 
20
19
  import cirq
@@ -13,31 +13,35 @@
13
13
  # limitations under the License.
14
14
 
15
15
  """Provides functions for running and analyzing two-qubit XEB experiments."""
16
- from typing import Sequence, TYPE_CHECKING, Optional, Tuple, Dict, cast, Mapping
17
-
16
+ import functools
17
+ import itertools
18
18
  from dataclasses import dataclass
19
19
  from types import MappingProxyType
20
- import itertools
21
- import functools
20
+ from typing import Any, cast, Dict, Mapping, Optional, Sequence, Tuple, TYPE_CHECKING
22
21
 
23
- from matplotlib import pyplot as plt
24
22
  import networkx as nx
25
23
  import numpy as np
26
24
  import pandas as pd
25
+ from matplotlib import pyplot as plt
27
26
 
28
27
  from cirq import ops, value, vis
29
- from cirq.experiments.xeb_sampling import sample_2q_xeb_circuits
30
- from cirq.experiments.xeb_fitting import benchmark_2q_xeb_fidelities
31
- from cirq.experiments.xeb_fitting import fit_exponential_decays, exponential_decay
28
+ from cirq._compat import cached_method
32
29
  from cirq.experiments import random_quantum_circuit_generation as rqcg
33
30
  from cirq.experiments.qubit_characterizations import (
34
- ParallelRandomizedBenchmarkingResult,
35
31
  parallel_single_qubit_randomized_benchmarking,
32
+ ParallelRandomizedBenchmarkingResult,
36
33
  )
34
+ from cirq.experiments.xeb_fitting import (
35
+ benchmark_2q_xeb_fidelities,
36
+ exponential_decay,
37
+ fit_exponential_decays,
38
+ )
39
+ from cirq.experiments.xeb_sampling import sample_2q_xeb_circuits
37
40
  from cirq.qis import noise_utils
38
- from cirq._compat import cached_method
39
41
 
40
42
  if TYPE_CHECKING:
43
+ import multiprocessing
44
+
41
45
  import cirq
42
46
 
43
47
 
@@ -52,6 +56,46 @@ def _manhattan_distance(qubit1: 'cirq.GridQubit', qubit2: 'cirq.GridQubit') -> i
52
56
  return abs(qubit1.row - qubit2.row) + abs(qubit1.col - qubit2.col)
53
57
 
54
58
 
59
+ def qubits_and_pairs(
60
+ sampler: 'cirq.Sampler',
61
+ qubits: Optional[Sequence['cirq.GridQubit']] = None,
62
+ pairs: Optional[Sequence[tuple['cirq.GridQubit', 'cirq.GridQubit']]] = None,
63
+ ) -> Tuple[Sequence['cirq.GridQubit'], Sequence[tuple['cirq.GridQubit', 'cirq.GridQubit']]]:
64
+ """Extract qubits and pairs from sampler.
65
+
66
+
67
+ If qubits are not provided, then they are extracted from the pairs (if given) or the sampler.
68
+ If pairs are not provided then all pairs of adjacent qubits are used.
69
+
70
+ Args:
71
+ sampler: The quantum engine or simulator to run the circuits.
72
+ qubits: Optional list of qubits.
73
+ pairs: Optional list of pair to use.
74
+
75
+ Returns:
76
+ - Qubits to use.
77
+ - Pairs of qubits to use.
78
+
79
+ Raises:
80
+ ValueError: If qubits are not specified and can't be deduced from other arguments.
81
+ """
82
+ if qubits is None:
83
+ if pairs is None:
84
+ qubits = _grid_qubits_for_sampler(sampler)
85
+ if qubits is None:
86
+ raise ValueError("Couldn't determine qubits from sampler. Please specify them.")
87
+ else:
88
+ qubits_set = set(itertools.chain(*pairs))
89
+ qubits = list(qubits_set)
90
+
91
+ if pairs is None:
92
+ pairs = [
93
+ pair for pair in itertools.combinations(qubits, 2) if _manhattan_distance(*pair) == 1
94
+ ]
95
+
96
+ return qubits, pairs
97
+
98
+
55
99
  @dataclass(frozen=True)
56
100
  class TwoQubitXEBResult:
57
101
  """Results from an XEB experiment."""
@@ -143,7 +187,9 @@ class TwoQubitXEBResult:
143
187
 
144
188
  def xeb_fidelity(self, q0: 'cirq.GridQubit', q1: 'cirq.GridQubit') -> float:
145
189
  """Return the XEB fidelity of a qubit pair."""
146
- return self._record(q0, q1).layer_fid
190
+ return noise_utils.decay_constant_to_xeb_fidelity(
191
+ self._record(q0, q1).layer_fid, num_qubits=2
192
+ )
147
193
 
148
194
  def xeb_error(self, q0: 'cirq.GridQubit', q1: 'cirq.GridQubit') -> float:
149
195
  """Return the XEB error of a qubit pair."""
@@ -177,8 +223,7 @@ class TwoQubitXEBResult:
177
223
  """Return the Pauli error of all qubit pairs."""
178
224
  return {
179
225
  pair: noise_utils.decay_constant_to_pauli_error(
180
- noise_utils.xeb_fidelity_to_decay_constant(self.xeb_fidelity(*pair), num_qubits=2),
181
- num_qubits=2,
226
+ self._record(*pair).layer_fid, num_qubits=2
182
227
  )
183
228
  for pair in self.all_qubit_pairs
184
229
  }
@@ -347,19 +392,23 @@ class InferredXEBResult:
347
392
  return ax
348
393
 
349
394
 
350
- def parallel_two_qubit_xeb(
395
+ def parallel_xeb_workflow(
351
396
  sampler: 'cirq.Sampler',
352
397
  qubits: Optional[Sequence['cirq.GridQubit']] = None,
353
398
  entangling_gate: 'cirq.Gate' = ops.CZ,
354
399
  n_repetitions: int = 10**4,
355
400
  n_combinations: int = 10,
356
401
  n_circuits: int = 20,
357
- cycle_depths: Sequence[int] = tuple(np.arange(3, 100, 20)),
402
+ cycle_depths: Sequence[int] = (5, 25, 50, 100, 200, 300),
358
403
  random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
359
404
  ax: Optional[plt.Axes] = None,
405
+ pairs: Optional[Sequence[tuple['cirq.GridQubit', 'cirq.GridQubit']]] = None,
406
+ pool: Optional['multiprocessing.pool.Pool'] = None,
407
+ batch_size: int = 9,
408
+ tags: Sequence[Any] = (),
360
409
  **plot_kwargs,
361
- ) -> TwoQubitXEBResult:
362
- """A convenience method that runs the full XEB workflow.
410
+ ) -> Tuple[pd.DataFrame, Sequence['cirq.Circuit'], pd.DataFrame]:
411
+ """A utility method that runs the full XEB workflow.
363
412
 
364
413
  Args:
365
414
  sampler: The quantum engine or simulator to run the circuits.
@@ -372,24 +421,29 @@ def parallel_two_qubit_xeb(
372
421
  random_state: The random state to use.
373
422
  ax: the plt.Axes to plot the device layout on. If not given,
374
423
  no plot is created.
424
+ pairs: Pairs to use. If not specified, use all pairs between adjacent qubits.
425
+ pool: An optional multiprocessing pool.
426
+ batch_size: We call `run_batch` on the sampler, which can speed up execution in certain
427
+ environments. The number of (circuit, cycle_depth) tasks to be run in each batch
428
+ is given by this number.
429
+ tags: Tags to add to two qubit operations.
375
430
  **plot_kwargs: Arguments to be passed to 'plt.Axes.plot'.
376
431
 
377
432
  Returns:
378
- A TwoQubitXEBResult object representing the results of the experiment.
433
+ - A DataFrame with columns 'cycle_depth' and 'fidelity'.
434
+ - The circuits used to perform XEB.
435
+ - A pandas dataframe with index given by ['circuit_i', 'cycle_depth'].
436
+ Columns always include "sampled_probs". If `combinations_by_layer` is
437
+ not `None` and you are doing parallel XEB, additional metadata columns
438
+ will be attached to the returned DataFrame.
379
439
 
380
440
  Raises:
381
441
  ValueError: If qubits are not specified and the sampler has no device.
382
442
  """
383
443
  rs = value.parse_random_state(random_state)
384
444
 
385
- if qubits is None:
386
- qubits = _grid_qubits_for_sampler(sampler)
387
- if qubits is None:
388
- raise ValueError("Couldn't determine qubits from sampler. Please specify them.")
389
-
390
- graph = nx.Graph(
391
- pair for pair in itertools.combinations(qubits, 2) if _manhattan_distance(*pair) == 1
392
- )
445
+ qubits, pairs = qubits_and_pairs(sampler, qubits, pairs)
446
+ graph = nx.Graph(pairs)
393
447
 
394
448
  if ax is not None:
395
449
  nx.draw_networkx(graph, pos={q: (q.row, q.col) for q in qubits}, ax=ax)
@@ -397,7 +451,11 @@ def parallel_two_qubit_xeb(
397
451
  ax.plot(**plot_kwargs)
398
452
 
399
453
  circuit_library = rqcg.generate_library_of_2q_circuits(
400
- n_library_circuits=n_circuits, two_qubit_gate=entangling_gate, random_state=rs
454
+ n_library_circuits=n_circuits,
455
+ two_qubit_gate=entangling_gate,
456
+ random_state=rs,
457
+ max_cycle_depth=max(cycle_depths),
458
+ tags=tags,
401
459
  )
402
460
 
403
461
  combs_by_layer = rqcg.get_random_combinations_for_device(
@@ -414,12 +472,70 @@ def parallel_two_qubit_xeb(
414
472
  combinations_by_layer=combs_by_layer,
415
473
  shuffle=rs,
416
474
  repetitions=n_repetitions,
475
+ batch_size=batch_size,
417
476
  )
418
477
 
419
478
  fids = benchmark_2q_xeb_fidelities(
420
- sampled_df=sampled_df, circuits=circuit_library, cycle_depths=cycle_depths
479
+ sampled_df=sampled_df, circuits=circuit_library, cycle_depths=cycle_depths, pool=pool
421
480
  )
422
481
 
482
+ return fids, circuit_library, sampled_df
483
+
484
+
485
+ def parallel_two_qubit_xeb(
486
+ sampler: 'cirq.Sampler',
487
+ qubits: Optional[Sequence['cirq.GridQubit']] = None,
488
+ entangling_gate: 'cirq.Gate' = ops.CZ,
489
+ n_repetitions: int = 10**4,
490
+ n_combinations: int = 10,
491
+ n_circuits: int = 20,
492
+ cycle_depths: Sequence[int] = (5, 25, 50, 100, 200, 300),
493
+ random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
494
+ ax: Optional[plt.Axes] = None,
495
+ pairs: Optional[Sequence[tuple['cirq.GridQubit', 'cirq.GridQubit']]] = None,
496
+ batch_size: int = 9,
497
+ tags: Sequence[Any] = (),
498
+ **plot_kwargs,
499
+ ) -> TwoQubitXEBResult:
500
+ """A convenience method that runs the full XEB workflow.
501
+
502
+ Args:
503
+ sampler: The quantum engine or simulator to run the circuits.
504
+ qubits: Qubits under test. If none, uses all qubits on the sampler's device.
505
+ entangling_gate: The entangling gate to use.
506
+ n_repetitions: The number of repetitions to use.
507
+ n_combinations: The number of combinations to generate.
508
+ n_circuits: The number of circuits to generate.
509
+ cycle_depths: The cycle depths to use.
510
+ random_state: The random state to use.
511
+ ax: the plt.Axes to plot the device layout on. If not given,
512
+ no plot is created.
513
+ pairs: Pairs to use. If not specified, use all pairs between adjacent qubits.
514
+ batch_size: We call `run_batch` on the sampler, which can speed up execution in certain
515
+ environments. The number of (circuit, cycle_depth) tasks to be run in each batch
516
+ is given by this number.
517
+ tags: Tags to add to two qubit operations.
518
+ **plot_kwargs: Arguments to be passed to 'plt.Axes.plot'.
519
+ Returns:
520
+ A TwoQubitXEBResult object representing the results of the experiment.
521
+ Raises:
522
+ ValueError: If qubits are not specified and the sampler has no device.
523
+ """
524
+ fids, *_ = parallel_xeb_workflow(
525
+ sampler=sampler,
526
+ qubits=qubits,
527
+ pairs=pairs,
528
+ entangling_gate=entangling_gate,
529
+ n_repetitions=n_repetitions,
530
+ n_combinations=n_combinations,
531
+ n_circuits=n_circuits,
532
+ cycle_depths=cycle_depths,
533
+ random_state=random_state,
534
+ ax=ax,
535
+ batch_size=batch_size,
536
+ tags=tags,
537
+ **plot_kwargs,
538
+ )
423
539
  return TwoQubitXEBResult(fit_exponential_decays(fids))
424
540
 
425
541
 
@@ -432,9 +548,12 @@ def run_rb_and_xeb(
432
548
  np.logspace(np.log10(5), np.log10(1000), 5, dtype=int)
433
549
  ),
434
550
  entangling_gate: 'cirq.Gate' = ops.CZ,
435
- depths_xeb: Sequence[int] = tuple(np.arange(3, 100, 20)),
551
+ depths_xeb: Sequence[int] = (5, 25, 50, 100, 200, 300),
436
552
  xeb_combinations: int = 10,
437
553
  random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
554
+ pairs: Optional[Sequence[tuple['cirq.GridQubit', 'cirq.GridQubit']]] = None,
555
+ batch_size: int = 9,
556
+ tags: Sequence[Any] = (),
438
557
  ) -> InferredXEBResult:
439
558
  """A convenience method that runs both RB and XEB workflows.
440
559
 
@@ -448,6 +567,11 @@ def run_rb_and_xeb(
448
567
  depths_xeb: The cycle depths to use for XEB.
449
568
  xeb_combinations: The number of combinations to generate for XEB.
450
569
  random_state: The random state to use.
570
+ pairs: Pairs to use. If not specified, use all pairs between adjacent qubits.
571
+ batch_size: We call `run_batch` on the sampler, which can speed up execution in certain
572
+ environments. The number of (circuit, cycle_depth) tasks to be run in each batch
573
+ is given by this number.
574
+ tags: Tags to add to two qubit operations.
451
575
 
452
576
  Returns:
453
577
  An InferredXEBResult object representing the results of the experiment.
@@ -456,10 +580,7 @@ def run_rb_and_xeb(
456
580
  ValueError: If qubits are not specified and the sampler has no device.
457
581
  """
458
582
 
459
- if qubits is None:
460
- qubits = _grid_qubits_for_sampler(sampler)
461
- if qubits is None:
462
- raise ValueError("Couldn't determine qubits from sampler. Please specify them.")
583
+ qubits, pairs = qubits_and_pairs(sampler, qubits, pairs)
463
584
 
464
585
  rb = parallel_single_qubit_randomized_benchmarking(
465
586
  sampler=sampler,
@@ -472,12 +593,15 @@ def run_rb_and_xeb(
472
593
  xeb = parallel_two_qubit_xeb(
473
594
  sampler=sampler,
474
595
  qubits=qubits,
596
+ pairs=pairs,
475
597
  entangling_gate=entangling_gate,
476
598
  n_repetitions=repetitions,
477
599
  n_circuits=num_circuits,
478
600
  cycle_depths=depths_xeb,
479
601
  n_combinations=xeb_combinations,
480
602
  random_state=random_state,
603
+ batch_size=batch_size,
604
+ tags=tags,
481
605
  )
482
606
 
483
607
  return InferredXEBResult(rb, xeb)