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
@@ -14,17 +14,24 @@
14
14
 
15
15
  """Creates the abstraction for gauge compiling as a cirq transformer."""
16
16
 
17
- from typing import Callable, Tuple, Optional, Sequence, Union, List
18
17
  import abc
19
- import itertools
20
18
  import functools
21
-
19
+ import itertools
22
20
  from dataclasses import dataclass
23
- from attrs import frozen, field
24
- import numpy as np
21
+ from numbers import Real
22
+ from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union
25
23
 
24
+ import numpy as np
25
+ import sympy
26
+ from attrs import field, frozen
27
+
28
+ from cirq import circuits, ops
29
+ from cirq.protocols import unitary_protocol
30
+ from cirq.protocols.has_unitary_protocol import has_unitary
31
+ from cirq.study import sweepable
32
+ from cirq.study.sweeps import Points, Zip
26
33
  from cirq.transformers import transformer_api
27
- from cirq import ops, circuits
34
+ from cirq.transformers.analytical_decompositions import single_qubit_decompositions
28
35
 
29
36
 
30
37
  class Gauge(abc.ABC):
@@ -122,6 +129,43 @@ class SameGateGauge(Gauge):
122
129
  )
123
130
 
124
131
 
132
+ @frozen
133
+ class TwoQubitGateSymbolizer:
134
+ """Parameterizes two qubit gates with symbols.
135
+
136
+ Attributes:
137
+ symbolizer: A callable that takes a two-qubit gate and a sequence of symbols,
138
+ and returns a tuple containing the parameterized gate and a dictionary
139
+ mapping symbol names to their values.
140
+ n_symbols: The number of symbols to use for parameterization.
141
+ """
142
+
143
+ symbolizer_fn: Callable[[ops.Gate, Sequence[sympy.Symbol]], Tuple[ops.Gate, Dict[str, Real]]]
144
+ n_symbols: int
145
+
146
+ def __call__(
147
+ self, two_qubit_gate: ops.Gate, symbols: Sequence[sympy.Symbol]
148
+ ) -> Tuple[ops.Gate, Dict[str, Real]]:
149
+ """Symbolizes a two qubit gate to a parameterized gate.
150
+
151
+ Args:
152
+ two_qubit_gate: The 2 qubit gate to be symbolized.
153
+ symbols: A sequence of sympy symbols to use for parameterization.
154
+
155
+ Returns:
156
+ A tuple containing the parameterized gate and a dictionary mapping
157
+ symbol names to their values.
158
+
159
+ Raises:
160
+ ValueError: If the provided symbols do not match the expected number.
161
+ """
162
+ if len(symbols) != self.n_symbols:
163
+ raise ValueError(
164
+ f"Expect {self.n_symbols} symbols, but got {len(symbols)} symbols in {symbols}"
165
+ )
166
+ return self.symbolizer_fn(two_qubit_gate, symbols)
167
+
168
+
125
169
  def _select(choices: Sequence[Gauge], probabilites: np.ndarray, prng: np.random.Generator) -> Gauge:
126
170
  return choices[prng.choice(len(choices), p=probabilites)]
127
171
 
@@ -144,12 +188,14 @@ class GaugeSelector:
144
188
 
145
189
  @transformer_api.transformer
146
190
  class GaugeTransformer:
191
+
147
192
  def __init__(
148
193
  self,
149
194
  # target can be either a specific gate, gatefamily or gateset
150
195
  # which allows matching parametric gates.
151
196
  target: Union[ops.Gate, ops.Gateset, ops.GateFamily],
152
197
  gauge_selector: Callable[[np.random.Generator], Gauge],
198
+ two_qubit_gate_symbolizer: Optional[TwoQubitGateSymbolizer] = None,
153
199
  ) -> None:
154
200
  """Constructs a GaugeTransformer.
155
201
 
@@ -157,9 +203,11 @@ class GaugeTransformer:
157
203
  target: Target two-qubit gate, a gate-family or a gate-set of two-qubit gates.
158
204
  gauge_selector: A callable that takes a numpy random number generator
159
205
  as an argument and returns a Gauge.
206
+ two_qubit_gate_symbolizer: A symbolizer to symbolize 2 qubit gates.
160
207
  """
161
208
  self.target = ops.GateFamily(target) if isinstance(target, ops.Gate) else target
162
209
  self.gauge_selector = gauge_selector
210
+ self.two_qubit_gate_symbolizer = two_qubit_gate_symbolizer
163
211
 
164
212
  def __call__(
165
213
  self,
@@ -201,6 +249,148 @@ class GaugeTransformer:
201
249
  new_moments.extend(_build_moments(right))
202
250
  return circuits.Circuit.from_moments(*new_moments)
203
251
 
252
+ def as_sweep(
253
+ self,
254
+ circuit: circuits.AbstractCircuit,
255
+ *,
256
+ N: int,
257
+ context: Optional[transformer_api.TransformerContext] = None,
258
+ prng: Optional[np.random.Generator] = None,
259
+ ) -> Tuple[circuits.AbstractCircuit, sweepable.Sweepable]:
260
+ """Generates a parameterized circuit with *N* sets of sweepable parameters.
261
+
262
+ Args:
263
+ circuit: The input circuit to be processed by gauge compiling.
264
+ N: The number of parameter sets to generate.
265
+ context: A `cirq.TransformerContext` storing common configurable options for
266
+ the transformers.
267
+ prng: A pseudo-random number generator to select a gauge within a gauge cluster.
268
+ """
269
+
270
+ rng = np.random.default_rng() if prng is None else prng
271
+ if context is None:
272
+ context = transformer_api.TransformerContext(deep=False)
273
+ if context.deep:
274
+ raise ValueError('GaugeTransformer cannot be used with deep=True')
275
+ new_moments: List[List[ops.Operation]] = [] # Store parameterized circuits.
276
+ phxz_sid = itertools.count()
277
+ two_qubit_gate_sid = itertools.count()
278
+ # Map from "((pre|post),$qid,$moment_id)" to gate parameters.
279
+ # E.g., {(post,q1,2): {"x_exponent": "x1", "z_exponent": "z1", "axis_phase": "a1"}}
280
+ phxz_symbols_by_locs: Dict[Tuple[str, ops.Qid, int], Dict[str, sympy.Symbol]] = {}
281
+ # Map from "($q0,$q1,$moment_id)" to gate parameters.
282
+ # E.g., {(q0,q1,0): ["s0"]}.
283
+ two_qubit_gate_symbols_by_locs: Dict[Tuple[ops.Qid, ops.Qid, int], List[sympy.Symbol]] = {}
284
+
285
+ def single_qubit_next_symbol() -> Dict[str, sympy.Symbol]:
286
+ sid = next(phxz_sid)
287
+ return _parameterize_to_phxz(sid)
288
+
289
+ def two_qubit_gate_next_symbol_list(n: int) -> List[sympy.Symbol]:
290
+ """Returns symbols for 2 qubit gate parameterization."""
291
+ sid = next(two_qubit_gate_sid)
292
+ symbols: List[sympy.Symbol] = [sympy.Symbol(f"s{sid}_{sub}") for sub in range(n)]
293
+ return symbols
294
+
295
+ # Build parameterized circuit.
296
+ for moment_id, moment in enumerate(circuit):
297
+ center_moment: List[ops.Operation] = []
298
+ left_moment: List[ops.Operation] = []
299
+ right_moment: List[ops.Operation] = []
300
+ for op in moment:
301
+ if isinstance(op, ops.TaggedOperation) and set(op.tags).intersection(
302
+ context.tags_to_ignore
303
+ ):
304
+ center_moment.append(op)
305
+ continue
306
+ if op.gate is not None and op in self.target:
307
+ random_gauge = self.gauge_selector(rng).sample(op.gate, rng)
308
+ # Build symbols for 2-qubit-gates if the transformer might transform it,
309
+ # otherwise, keep it as it is.
310
+ if self.two_qubit_gate_symbolizer is not None:
311
+ symbols: list[sympy.Symbol] = two_qubit_gate_next_symbol_list(
312
+ self.two_qubit_gate_symbolizer.n_symbols
313
+ )
314
+ two_qubit_gate_symbols_by_locs[(op.qubits[0], op.qubits[1], moment_id)] = (
315
+ symbols
316
+ )
317
+ parameterized_2_qubit_gate, _ = self.two_qubit_gate_symbolizer(
318
+ random_gauge.two_qubit_gate, symbols
319
+ )
320
+ center_moment.append(parameterized_2_qubit_gate.on(*op.qubits))
321
+ else:
322
+ center_moment.append(op)
323
+ # Build symbols for the gauge, for a 2-qubit gauge, symbols will be built for
324
+ # pre/post q0/q1 and the new 2-qubit gate if the 2-qubit gate is updated in
325
+ # the gauge compiling.
326
+ for prefix, q in itertools.product(["pre", "post"], op.qubits):
327
+ xza_by_symbols = single_qubit_next_symbol() # xza in phased xz gate.
328
+ phxz_symbols_by_locs[(prefix, q, moment_id)] = xza_by_symbols
329
+ new_op = ops.PhasedXZGate(**xza_by_symbols).on(q)
330
+ if prefix == "pre":
331
+ left_moment.append(new_op)
332
+ else:
333
+ right_moment.append(new_op)
334
+ else:
335
+ center_moment.append(op)
336
+ new_moments.extend(
337
+ [moment for moment in [left_moment, center_moment, right_moment] if moment]
338
+ )
339
+
340
+ # Initialize the map from symbol names to their N values.
341
+ values_by_params: Dict[str, List[float]] = {
342
+ **{
343
+ str(symbol): []
344
+ for symbols_by_names in phxz_symbols_by_locs.values()
345
+ for symbol in symbols_by_names.values()
346
+ },
347
+ **{
348
+ str(symbol): []
349
+ for symbols in two_qubit_gate_symbols_by_locs.values()
350
+ for symbol in symbols
351
+ },
352
+ }
353
+
354
+ # Assign values for parameters via randomly chosen GaugeSelector.
355
+ for _ in range(N):
356
+ for moment_id, moment in enumerate(circuit):
357
+ for op in moment:
358
+ if isinstance(op, ops.TaggedOperation) and set(op.tags).intersection(
359
+ context.tags_to_ignore
360
+ ):
361
+ continue
362
+ if op.gate is not None and len(op.qubits) == 2 and op in self.target:
363
+ gauge = self.gauge_selector(rng).sample(op.gate, rng)
364
+
365
+ # Get the params for 2 qubit gates.
366
+ if self.two_qubit_gate_symbolizer is not None:
367
+ _, vals_by_symbols = self.two_qubit_gate_symbolizer(
368
+ gauge.two_qubit_gate,
369
+ [
370
+ *two_qubit_gate_symbols_by_locs[
371
+ (op.qubits[0], op.qubits[1], moment_id)
372
+ ]
373
+ ],
374
+ )
375
+ for symbol_str, val in vals_by_symbols.items():
376
+ values_by_params[symbol_str].append(float(val))
377
+
378
+ # Get the params of pre/post q0/q1 gates.
379
+ for pre_or_post, idx in itertools.product(["pre", "post"], [0, 1]):
380
+ gates = getattr(gauge, f"{pre_or_post}_q{idx}")
381
+ phxz_params = _gate_sequence_to_phxz_params(
382
+ gates,
383
+ phxz_symbols_by_locs[(pre_or_post, op.qubits[idx], moment_id)],
384
+ )
385
+ for key, value in phxz_params.items():
386
+ values_by_params[key].append(float(value))
387
+
388
+ sweeps: List[Points] = [
389
+ Points(key=key, points=values) for key, values in values_by_params.items()
390
+ ]
391
+
392
+ return circuits.Circuit.from_moments(*new_moments), Zip(*sweeps)
393
+
204
394
 
205
395
  def _build_moments(operation_by_qubits: List[List[ops.Operation]]) -> List[List[ops.Operation]]:
206
396
  """Builds moments from a list of operations grouped by qubits.
@@ -212,3 +402,52 @@ def _build_moments(operation_by_qubits: List[List[ops.Operation]]) -> List[List[
212
402
  for moment in itertools.zip_longest(*operation_by_qubits):
213
403
  moments.append([op for op in moment if op is not None])
214
404
  return moments
405
+
406
+
407
+ def _parameterize_to_phxz(symbol_id: int) -> Dict[str, sympy.Symbol]:
408
+ """Returns symbolized parameters for the gate."""
409
+
410
+ # Parameterize single qubit gate to parameterized PhasedXZGate.
411
+ phased_xz_params = {
412
+ "x_exponent": sympy.Symbol(f"x{symbol_id}"),
413
+ "z_exponent": sympy.Symbol(f"z{symbol_id}"),
414
+ "axis_phase_exponent": sympy.Symbol(f"a{symbol_id}"),
415
+ }
416
+ return phased_xz_params
417
+
418
+
419
+ def _gate_sequence_to_phxz_params(
420
+ gates: Tuple[ops.Gate, ...], xza_by_symbols: Dict[str, sympy.Symbol]
421
+ ) -> Dict[str, float]:
422
+ identity_gate_in_phxz = {
423
+ str(xza_by_symbols["x_exponent"]): 0.0,
424
+ str(xza_by_symbols["z_exponent"]): 0.0,
425
+ str(xza_by_symbols["axis_phase_exponent"]): 0.0,
426
+ }
427
+ if not gates:
428
+ return identity_gate_in_phxz
429
+ for gate in gates:
430
+ if not has_unitary(gate) or gate.num_qubits() != 1:
431
+ raise ValueError(
432
+ "Invalid gate sequence to be converted to PhasedXZGate."
433
+ f"Found incompatiable gate {gate} in sequence."
434
+ )
435
+ phxz = (
436
+ single_qubit_decompositions.single_qubit_matrix_to_phxz(
437
+ functools.reduce(
438
+ np.matmul, [unitary_protocol.unitary(gate) for gate in reversed(gates)]
439
+ )
440
+ )
441
+ or ops.I
442
+ )
443
+ if phxz is ops.I: # Identity gate
444
+ return identity_gate_in_phxz
445
+ # Check the gate type, needs to be a PhasedXZ gate.
446
+ if not isinstance(phxz, ops.PhasedXZGate):
447
+ raise ValueError("Failed to convert the gate sequence to a PhasedXZ gate.")
448
+ if phxz is not None:
449
+ return {
450
+ str(xza_by_symbols["x_exponent"]): phxz.x_exponent,
451
+ str(xza_by_symbols["z_exponent"]): phxz.z_exponent,
452
+ str(xza_by_symbols["axis_phase_exponent"]): phxz.axis_phase_exponent,
453
+ }
@@ -12,10 +12,23 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import pytest
15
+ import unittest.mock
16
+
16
17
  import numpy as np
18
+ import pytest
19
+ import sympy
20
+
17
21
  import cirq
18
- from cirq.transformers.gauge_compiling import GaugeTransformer, CZGaugeTransformer
22
+ from cirq.transformers.analytical_decompositions import single_qubit_decompositions
23
+ from cirq.transformers.gauge_compiling import (
24
+ ConstantGauge,
25
+ CZGaugeTransformer,
26
+ GaugeSelector,
27
+ GaugeTransformer,
28
+ SqrtCZGaugeTransformer,
29
+ TwoQubitGateSymbolizer,
30
+ )
31
+ from cirq.transformers.gauge_compiling.sqrt_cz_gauge import SqrtCZGauge
19
32
 
20
33
 
21
34
  def test_deep_transformation_not_supported():
@@ -25,10 +38,19 @@ def test_deep_transformation_not_supported():
25
38
  cirq.Circuit(), context=cirq.TransformerContext(deep=True)
26
39
  )
27
40
 
41
+ with pytest.raises(ValueError, match="cannot be used with deep=True"):
42
+ _ = GaugeTransformer(target=cirq.CZ, gauge_selector=lambda _: None).as_sweep(
43
+ cirq.Circuit(), context=cirq.TransformerContext(deep=True), N=1
44
+ )
45
+
28
46
 
29
47
  def test_ignore_tags():
30
48
  c = cirq.Circuit(cirq.CZ(*cirq.LineQubit.range(2)).with_tags('foo'))
31
49
  assert c == CZGaugeTransformer(c, context=cirq.TransformerContext(tags_to_ignore={"foo"}))
50
+ parameterized_circuit, _ = CZGaugeTransformer.as_sweep(
51
+ c, context=cirq.TransformerContext(tags_to_ignore={"foo"}), N=1
52
+ )
53
+ assert c == parameterized_circuit
32
54
 
33
55
 
34
56
  def test_target_can_be_gateset():
@@ -39,3 +61,86 @@ def test_target_can_be_gateset():
39
61
  )
40
62
  want = cirq.Circuit(cirq.Y.on_each(qs), cirq.CZ(*qs), cirq.X.on_each(qs))
41
63
  assert transformer(c, prng=np.random.default_rng(0)) == want
64
+
65
+
66
+ def test_as_sweep_multi_pre_or_multi_post():
67
+ transformer = GaugeTransformer(
68
+ target=cirq.CZ,
69
+ gauge_selector=GaugeSelector(
70
+ gauges=[
71
+ ConstantGauge(
72
+ two_qubit_gate=cirq.CZ,
73
+ pre_q0=[cirq.X, cirq.X],
74
+ post_q0=[cirq.Z],
75
+ pre_q1=[cirq.Y],
76
+ post_q1=[cirq.Y, cirq.Y, cirq.Y],
77
+ )
78
+ ]
79
+ ),
80
+ )
81
+ qs = cirq.LineQubit.range(2)
82
+ input_circuit = cirq.Circuit(cirq.CZ(*qs))
83
+ parameterized_circuit, sweeps = transformer.as_sweep(input_circuit, N=1)
84
+
85
+ for params in sweeps:
86
+ compiled_circuit = cirq.resolve_parameters(parameterized_circuit, params)
87
+ cirq.testing.assert_circuits_have_same_unitary_given_final_permutation(
88
+ input_circuit, compiled_circuit, qubit_map={q: q for q in input_circuit.all_qubits()}
89
+ )
90
+
91
+
92
+ def test_as_sweep_invalid_gauge_sequence():
93
+ transfomer = GaugeTransformer(
94
+ target=cirq.CZ,
95
+ gauge_selector=GaugeSelector(
96
+ gauges=[
97
+ ConstantGauge(
98
+ two_qubit_gate=cirq.CZ,
99
+ pre_q0=[cirq.measure],
100
+ post_q0=[cirq.Z],
101
+ pre_q1=[cirq.X],
102
+ post_q1=[cirq.Z],
103
+ )
104
+ ]
105
+ ),
106
+ )
107
+ qs = cirq.LineQubit.range(2)
108
+ c = cirq.Circuit(cirq.CZ(*qs))
109
+ with pytest.raises(ValueError, match="Invalid gate sequence to be converted to PhasedXZGate."):
110
+ transfomer.as_sweep(c, N=1)
111
+
112
+
113
+ def test_as_sweep_convert_to_phxz_failed():
114
+ qs = cirq.LineQubit.range(2)
115
+ c = cirq.Circuit(cirq.CZ(*qs))
116
+
117
+ with unittest.mock.patch.object(
118
+ single_qubit_decompositions,
119
+ "single_qubit_matrix_to_phxz",
120
+ # Return an non PhasedXZ gate, so we expect errors from as_sweep().
121
+ return_value=cirq.X,
122
+ ):
123
+ with pytest.raises(
124
+ ValueError, match="Failed to convert the gate sequence to a PhasedXZ gate."
125
+ ):
126
+ _ = CZGaugeTransformer.as_sweep(c, context=cirq.TransformerContext(), N=1)
127
+
128
+
129
+ def test_symbolize_2_qubits_gate_failed():
130
+ qs = cirq.LineQubit.range(2)
131
+ c = cirq.Circuit(cirq.CZPowGate(exponent=0.5).on(*qs))
132
+
133
+ with unittest.mock.patch.object(
134
+ SqrtCZGauge,
135
+ "sample",
136
+ # ISWAP gate is not a CZPowGate; errors are expected when symbolizing the 2-qubit gate.
137
+ return_value=ConstantGauge(two_qubit_gate=cirq.ISWAP),
138
+ ):
139
+ with pytest.raises(ValueError, match="Can't symbolize non-CZPowGate as CZ\\*\\*symbol."):
140
+ _ = SqrtCZGaugeTransformer.as_sweep(c, N=1)
141
+
142
+
143
+ def test_symbolize_2_qubits_gate_failed_unmatched_symbol_length():
144
+ symbolizer = TwoQubitGateSymbolizer(symbolizer_fn=lambda gate, _: (gate, {}), n_symbols=2)
145
+ with pytest.raises(ValueError, match="Expect 2 symbols, but got 1 symbols"):
146
+ symbolizer(cirq.CZ, [sympy.Symbol('x')])
@@ -14,12 +14,12 @@
14
14
 
15
15
 
16
16
  from unittest.mock import patch
17
- import pytest
18
17
 
19
18
  import numpy as np
19
+ import pytest
20
20
 
21
21
  import cirq
22
- from cirq.transformers.gauge_compiling import GaugeTransformer, GaugeSelector
22
+ from cirq.transformers.gauge_compiling import GaugeSelector, GaugeTransformer
23
23
 
24
24
 
25
25
  class GaugeTester:
@@ -73,6 +73,43 @@ class GaugeTester:
73
73
  else:
74
74
  _check_equivalent_with_error_message(c, nc, gauge)
75
75
 
76
+ def test_sweep(self):
77
+ qubits = cirq.LineQubit.range(3)
78
+
79
+ input_circuit = cirq.Circuit(
80
+ cirq.Moment(cirq.H(qubits[0])),
81
+ cirq.Moment(self.two_qubit_gate(*qubits[:2])),
82
+ cirq.Moment(self.two_qubit_gate(*qubits[1:])),
83
+ cirq.Moment([cirq.H(q) for q in qubits]),
84
+ cirq.Moment([cirq.measure(q) for q in qubits]),
85
+ )
86
+
87
+ n_samples = 5
88
+ parameterized_circuit, sweeps = self.gauge_transformer.as_sweep(input_circuit, N=n_samples)
89
+
90
+ # Check the parameterized circuit and N set of parameters.
91
+ assert cirq.is_parameterized(parameterized_circuit)
92
+ simulator = cirq.Simulator()
93
+ results = simulator.run_sweep(parameterized_circuit, sweeps)
94
+ assert len(results) == n_samples
95
+
96
+ # Check compilied circuits have the same unitary as the orig circuit.
97
+ for params in sweeps:
98
+ compiled_circuit = cirq.resolve_parameters(parameterized_circuit, params)
99
+ if self.must_fail:
100
+ with pytest.raises(AssertionError):
101
+ cirq.testing.assert_circuits_have_same_unitary_given_final_permutation(
102
+ input_circuit[:-1],
103
+ compiled_circuit[:-1],
104
+ qubit_map={q: q for q in input_circuit.all_qubits()},
105
+ )
106
+ break
107
+ cirq.testing.assert_circuits_have_same_unitary_given_final_permutation(
108
+ input_circuit[:-1],
109
+ compiled_circuit[:-1],
110
+ qubit_map={q: q for q in input_circuit.all_qubits()},
111
+ )
112
+
76
113
 
77
114
  def _check_equivalent_with_error_message(c: cirq.AbstractCircuit, nc: cirq.AbstractCircuit, gauge):
78
115
  try:
@@ -14,9 +14,10 @@
14
14
 
15
15
 
16
16
  import numpy as np
17
+
17
18
  import cirq
19
+ from cirq.transformers import ConstantGauge, GaugeSelector, GaugeTransformer
18
20
  from cirq.transformers.gauge_compiling.gauge_compiling_test_utils import GaugeTester
19
- from cirq.transformers import GaugeTransformer, GaugeSelector, ConstantGauge
20
21
 
21
22
 
22
23
  class ExampleGate(cirq.testing.TwoQubitGate):
@@ -26,7 +27,15 @@ class ExampleGate(cirq.testing.TwoQubitGate):
26
27
  return self.unitary
27
28
 
28
29
 
30
+ class ExampleSweepGate(cirq.testing.TwoQubitGate):
31
+ unitary = cirq.unitary(cirq.CZ)
32
+
33
+ def _unitary_(self) -> np.ndarray:
34
+ return self.unitary # pragma: no cover
35
+
36
+
29
37
  _EXAMPLE_TARGET = ExampleGate()
38
+ _EXAMPLE_SWEEP_TARGET = ExampleSweepGate()
30
39
 
31
40
  _GOOD_TRANSFORMER = GaugeTransformer(
32
41
  target=_EXAMPLE_TARGET,
@@ -16,13 +16,13 @@
16
16
 
17
17
  import numpy as np
18
18
 
19
+ from cirq import ops
19
20
  from cirq.transformers.gauge_compiling.gauge_compiling import (
20
21
  ConstantGauge,
21
22
  Gauge,
22
- GaugeTransformer,
23
23
  GaugeSelector,
24
+ GaugeTransformer,
24
25
  )
25
- from cirq import ops
26
26
 
27
27
 
28
28
  class RZRotation(Gauge):
@@ -14,12 +14,12 @@
14
14
 
15
15
  """The spin inversion gauge transformer."""
16
16
 
17
+ from cirq import ops
17
18
  from cirq.transformers.gauge_compiling.gauge_compiling import (
18
- GaugeTransformer,
19
19
  GaugeSelector,
20
+ GaugeTransformer,
20
21
  SameGateGauge,
21
22
  )
22
- from cirq import ops
23
23
 
24
24
  SpinInversionGaugeSelector = GaugeSelector(
25
25
  gauges=[
@@ -15,16 +15,20 @@
15
15
  """A Gauge transformer for CZ**0.5 and CZ**-0.5 gates."""
16
16
 
17
17
 
18
- from typing import TYPE_CHECKING
18
+ from numbers import Real
19
+ from typing import Dict, Sequence, Tuple, TYPE_CHECKING
20
+
19
21
  import numpy as np
22
+ import sympy
20
23
 
24
+ from cirq.ops import CZ, CZPowGate, Gate, Gateset, S, X
21
25
  from cirq.transformers.gauge_compiling.gauge_compiling import (
22
- GaugeTransformer,
23
- GaugeSelector,
24
26
  ConstantGauge,
25
27
  Gauge,
28
+ GaugeSelector,
29
+ GaugeTransformer,
30
+ TwoQubitGateSymbolizer,
26
31
  )
27
- from cirq.ops import CZ, S, X, Gateset
28
32
 
29
33
  if TYPE_CHECKING:
30
34
  import cirq
@@ -59,6 +63,20 @@ class SqrtCZGauge(Gauge):
59
63
  )
60
64
 
61
65
 
66
+ def _symbolize_as_cz_pow(
67
+ two_qubit_gate: Gate, symbols: Sequence[sympy.Symbol]
68
+ ) -> Tuple[Gate, Dict[str, Real]]:
69
+ """Symbolizes a CZPowGate to a parameterized CZPowGate."""
70
+
71
+ if not isinstance(two_qubit_gate, CZPowGate) or not isinstance(two_qubit_gate.exponent, Real):
72
+ raise ValueError("Can't symbolize non-CZPowGate as CZ**symbol.")
73
+ return (CZ ** symbols[0], {str(symbols[0]): two_qubit_gate.exponent})
74
+
75
+
62
76
  SqrtCZGaugeTransformer = GaugeTransformer(
63
- target=Gateset(_SQRT_CZ, _SQRT_CZ**-1), gauge_selector=GaugeSelector(gauges=[SqrtCZGauge()])
77
+ target=Gateset(_SQRT_CZ, _SQRT_CZ**-1),
78
+ gauge_selector=GaugeSelector(gauges=[SqrtCZGauge()]),
79
+ two_qubit_gate_symbolizer=TwoQubitGateSymbolizer(
80
+ symbolizer_fn=_symbolize_as_cz_pow, n_symbols=1
81
+ ),
64
82
  )
@@ -15,13 +15,14 @@
15
15
  """A Gauge transformer for SQRT_ISWAP gate."""
16
16
 
17
17
  import numpy as np
18
+
19
+ from cirq import ops
18
20
  from cirq.transformers.gauge_compiling.gauge_compiling import (
19
21
  ConstantGauge,
20
22
  Gauge,
21
- GaugeTransformer,
22
23
  GaugeSelector,
24
+ GaugeTransformer,
23
25
  )
24
- from cirq import ops
25
26
 
26
27
 
27
28
  class RZRotation(Gauge):
@@ -15,7 +15,7 @@
15
15
  """Utilities for heuristic decomposition of cirq gates."""
16
16
 
17
17
  from cirq.transformers.heuristic_decompositions.two_qubit_gate_tabulation import (
18
- TwoQubitGateTabulation,
19
- TwoQubitGateTabulationResult,
20
- two_qubit_gate_product_tabulation,
18
+ TwoQubitGateTabulation as TwoQubitGateTabulation,
19
+ TwoQubitGateTabulationResult as TwoQubitGateTabulationResult,
20
+ two_qubit_gate_product_tabulation as two_qubit_gate_product_tabulation,
21
21
  )
@@ -1,8 +1,9 @@
1
1
  # pylint: disable=wrong-or-nonexistent-copyright-notice
2
2
  import itertools
3
- from typing import Union, Sequence, Optional
3
+ from typing import Optional, Sequence, Union
4
4
 
5
5
  import numpy as np
6
+
6
7
  from cirq.value import random_state
7
8
 
8
9
  _RealArraylike = Union[np.ndarray, float]
@@ -5,9 +5,9 @@ import pytest
5
5
  import cirq
6
6
  from cirq import value
7
7
  from cirq.transformers.heuristic_decompositions.gate_tabulation_math_utils import (
8
- weyl_chamber_mesh,
9
8
  kak_vector_infidelity,
10
9
  random_qubit_unitary,
10
+ weyl_chamber_mesh,
11
11
  )
12
12
 
13
13
 
@@ -14,21 +14,21 @@
14
14
 
15
15
  """Attempt to tabulate single qubit gates required to generate a target 2Q gate
16
16
  with a product A k A."""
17
+ from dataclasses import dataclass
17
18
  from functools import reduce
18
19
  from typing import List, NamedTuple, Sequence, Tuple
19
20
 
20
- from dataclasses import dataclass
21
21
  import numpy as np
22
22
 
23
23
  import cirq
24
24
  from cirq import value
25
- from cirq._compat import proper_repr, proper_eq
25
+ from cirq._compat import proper_eq, proper_repr
26
26
  from cirq.transformers.heuristic_decompositions.gate_tabulation_math_utils import (
27
27
  kak_vector_infidelity,
28
+ kak_vector_to_unitary,
29
+ random_qubit_unitary,
28
30
  vector_kron,
29
31
  weyl_chamber_mesh,
30
- random_qubit_unitary,
31
- kak_vector_to_unitary,
32
32
  )
33
33
 
34
34
  _SingleQubitGatePair = Tuple[np.ndarray, np.ndarray]