cirq-core 1.4.1__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 +1 -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.1.dist-info → cirq_core-1.5.0.dist-info}/RECORD +586 -552
  584. {cirq_core-1.4.1.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.1.dist-info/METADATA +0 -45
  589. {cirq_core-1.4.1.dist-info → cirq_core-1.5.0.dist-info}/LICENSE +0 -0
  590. {cirq_core-1.4.1.dist-info → cirq_core-1.5.0.dist-info}/top_level.txt +0 -0
@@ -17,14 +17,14 @@ import pytest
17
17
 
18
18
  import cirq
19
19
  from cirq import value
20
+ from cirq.testing import assert_equivalent_repr, random_special_unitary
21
+ from cirq.transformers.heuristic_decompositions.gate_tabulation_math_utils import (
22
+ unitary_entanglement_fidelity,
23
+ )
20
24
  from cirq.transformers.heuristic_decompositions.two_qubit_gate_tabulation import (
21
25
  two_qubit_gate_product_tabulation,
22
26
  TwoQubitGateTabulation,
23
27
  )
24
- from cirq.transformers.heuristic_decompositions.gate_tabulation_math_utils import (
25
- unitary_entanglement_fidelity,
26
- )
27
- from cirq.testing import random_special_unitary, assert_equivalent_repr
28
28
 
29
29
  _rng = value.parse_random_state(11) # for determinism
30
30
 
@@ -0,0 +1,64 @@
1
+ # Copyright 2024 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Transformer that sorts commuting operations in increasing order of their `.qubits` tuple."""
16
+
17
+ from typing import Dict, List, Optional, TYPE_CHECKING
18
+
19
+ from cirq import circuits, protocols
20
+ from cirq.transformers import transformer_api
21
+
22
+ if TYPE_CHECKING:
23
+ import cirq
24
+
25
+
26
+ @transformer_api.transformer(add_deep_support=True)
27
+ def insertion_sort_transformer(
28
+ circuit: 'cirq.AbstractCircuit', *, context: Optional['cirq.TransformerContext'] = None
29
+ ) -> 'cirq.Circuit':
30
+ """Sorts the operations using their sorted `.qubits` property as comparison key.
31
+
32
+ Operations are swapped only if they commute.
33
+
34
+ Args:
35
+ circuit: input circuit.
36
+ context: optional TransformerContext (not used),
37
+ """
38
+ final_operations: List['cirq.Operation'] = []
39
+ qubit_index: Dict['cirq.Qid', int] = {
40
+ q: idx for idx, q in enumerate(sorted(circuit.all_qubits()))
41
+ }
42
+ cached_qubit_indices: Dict[int, List[int]] = {}
43
+ for pos, op in enumerate(circuit.all_operations()):
44
+ # here `pos` is at the append position of final_operations
45
+ if (op_qubit_indices := cached_qubit_indices.get(id(op))) is None:
46
+ op_qubit_indices = cached_qubit_indices[id(op)] = sorted(
47
+ qubit_index[q] for q in op.qubits
48
+ )
49
+ for tail_op in reversed(final_operations):
50
+ tail_qubit_indices = cached_qubit_indices[id(tail_op)]
51
+ if op_qubit_indices < tail_qubit_indices and (
52
+ # special case for zero-qubit gates
53
+ not op_qubit_indices
54
+ # check if two sorted sequences are disjoint
55
+ or op_qubit_indices[-1] < tail_qubit_indices[0]
56
+ or set(op_qubit_indices).isdisjoint(tail_qubit_indices)
57
+ # fallback to more expensive commutation check
58
+ or protocols.commutes(op, tail_op, default=False)
59
+ ):
60
+ pos -= 1
61
+ continue
62
+ break
63
+ final_operations.insert(pos, op)
64
+ return circuits.Circuit(final_operations)
@@ -0,0 +1,34 @@
1
+ # Copyright 2024 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import cirq
16
+ import cirq.transformers
17
+
18
+
19
+ def test_insertion_sort():
20
+ c = cirq.Circuit(
21
+ cirq.CZ(cirq.q(2), cirq.q(1)),
22
+ cirq.CZ(cirq.q(2), cirq.q(4)),
23
+ cirq.CZ(cirq.q(0), cirq.q(1)),
24
+ cirq.CZ(cirq.q(2), cirq.q(1)),
25
+ cirq.GlobalPhaseGate(1j).on(),
26
+ )
27
+ sorted_circuit = cirq.transformers.insertion_sort_transformer(c)
28
+ assert sorted_circuit == cirq.Circuit(
29
+ cirq.GlobalPhaseGate(1j).on(),
30
+ cirq.CZ(cirq.q(0), cirq.q(1)),
31
+ cirq.CZ(cirq.q(2), cirq.q(1)),
32
+ cirq.CZ(cirq.q(2), cirq.q(1)),
33
+ cirq.CZ(cirq.q(2), cirq.q(4)),
34
+ )
@@ -292,7 +292,20 @@ def drop_terminal_measurements(
292
292
  def flip_inversion(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
293
293
  if isinstance(op.gate, ops.MeasurementGate):
294
294
  return [
295
- ops.X(q) if b else ops.I(q) for q, b in zip(op.qubits, op.gate.full_invert_mask())
295
+ (
296
+ (ops.X if b else ops.I)
297
+ if q.dimension == 2
298
+ else (
299
+ ops.MatrixGate(
300
+ # Per SimulationState.measure(), swap 0,1 but leave other dims alone
301
+ np.eye(q.dimension)[[1, 0, *range(2, q.dimension)]],
302
+ qid_shape=(q.dimension,),
303
+ )
304
+ if b
305
+ else ops.IdentityGate(qid_shape=(q.dimension,))
306
+ )
307
+ ).on(q)
308
+ for q, b in zip(op.qubits, op.gate.full_invert_mask())
296
309
  ]
297
310
  return op
298
311
 
@@ -759,6 +759,41 @@ def test_drop_terminal():
759
759
  )
760
760
 
761
761
 
762
+ def test_drop_terminal_qudit():
763
+ q0, q1 = cirq.LineQid.range(2, dimension=3)
764
+ circuit = cirq.Circuit(
765
+ cirq.CircuitOperation(cirq.FrozenCircuit(cirq.measure(q0, q1, key='m', invert_mask=[0, 1])))
766
+ )
767
+ dropped = cirq.drop_terminal_measurements(circuit)
768
+ expected_inversion_matrix = np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1]])
769
+ cirq.testing.assert_same_circuits(
770
+ dropped,
771
+ cirq.Circuit(
772
+ cirq.CircuitOperation(
773
+ cirq.FrozenCircuit(
774
+ cirq.IdentityGate(qid_shape=(3,)).on(q0),
775
+ cirq.MatrixGate(expected_inversion_matrix, qid_shape=(3,)).on(q1),
776
+ )
777
+ )
778
+ ),
779
+ )
780
+ # Verify behavior equivalent to simulator (invert_mask swaps 0,1 but leaves 2 alone)
781
+ dropped.append(cirq.measure(q0, q1, key='m'))
782
+ sim = cirq.Simulator()
783
+ c0 = sim.simulate(circuit, initial_state=[0, 0])
784
+ d0 = sim.simulate(dropped, initial_state=[0, 0])
785
+ assert np.all(c0.measurements['m'] == [0, 1])
786
+ assert np.all(d0.measurements['m'] == [0, 1])
787
+ c1 = sim.simulate(circuit, initial_state=[1, 1])
788
+ d1 = sim.simulate(dropped, initial_state=[1, 1])
789
+ assert np.all(c1.measurements['m'] == [1, 0])
790
+ assert np.all(d1.measurements['m'] == [1, 0])
791
+ c2 = sim.simulate(circuit, initial_state=[2, 2])
792
+ d2 = sim.simulate(dropped, initial_state=[2, 2])
793
+ assert np.all(c2.measurements['m'] == [2, 2])
794
+ assert np.all(d2.measurements['m'] == [2, 2])
795
+
796
+
762
797
  def test_drop_terminal_nonterminal_error():
763
798
  q0, q1 = cirq.LineQubit.range(2)
764
799
  circuit = cirq.Circuit(
@@ -14,9 +14,9 @@
14
14
 
15
15
  """Transformer pass to merge connected components of k-qubit unitary operations."""
16
16
 
17
- from typing import cast, Optional, Callable, TYPE_CHECKING
17
+ from typing import Callable, cast, Optional, TYPE_CHECKING
18
18
 
19
- from cirq import ops, protocols, circuits
19
+ from cirq import circuits, ops, protocols
20
20
  from cirq.transformers import transformer_api, transformer_primitives
21
21
 
22
22
  if TYPE_CHECKING:
@@ -17,8 +17,8 @@
17
17
  from typing import Optional, TYPE_CHECKING
18
18
 
19
19
  from cirq import circuits, ops, protocols
20
+ from cirq.transformers import merge_k_qubit_gates, transformer_api, transformer_primitives
20
21
  from cirq.transformers.analytical_decompositions import single_qubit_decompositions
21
- from cirq.transformers import transformer_api, transformer_primitives, merge_k_qubit_gates
22
22
 
23
23
  if TYPE_CHECKING:
24
24
  import cirq
@@ -45,7 +45,7 @@ def test_merge_single_qubit_gates_to_phased_x_and_z():
45
45
  optimized=cirq.merge_single_qubit_gates_to_phased_x_and_z(c),
46
46
  expected=cirq.Circuit(
47
47
  cirq.PhasedXPowGate(phase_exponent=1)(a),
48
- cirq.Y(b) ** 0.5,
48
+ cirq.PhasedXPowGate(phase_exponent=0.5)(b) ** 0.5,
49
49
  cirq.CZ(a, b),
50
50
  (cirq.PhasedXPowGate(phase_exponent=-0.5)(a)) ** 0.5,
51
51
  cirq.measure(b, key="m"),
@@ -0,0 +1,115 @@
1
+ # Copyright 2024 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from collections.abc import Mapping
16
+ from typing import cast
17
+
18
+ import numpy as np
19
+
20
+ from cirq import circuits, ops
21
+ from cirq.transformers import transformer_api
22
+
23
+
24
+ def _gate_in_moment(gate: ops.Gate, moment: circuits.Moment) -> bool:
25
+ """Check whether `gate` is in `moment`."""
26
+ return any(op.gate == gate for op in moment)
27
+
28
+
29
+ @transformer_api.transformer
30
+ class DepolarizingNoiseTransformer:
31
+ """Add local depolarizing noise after two-qubit gates in a specified circuit. More specifically,
32
+ with probability p, append a random non-identity two-qubit Pauli operator after each specified
33
+ two-qubit gate.
34
+
35
+ Attrs:
36
+ p: The probability with which to add noise.
37
+ target_gate: Add depolarizing nose after this type of gate
38
+ """
39
+
40
+ def __init__(
41
+ self, p: float | Mapping[tuple[ops.Qid, ops.Qid], float], target_gate: ops.Gate = ops.CZ
42
+ ):
43
+ """Initialize the depolarizing noise transformer with some depolarizing probability and
44
+ target gate.
45
+
46
+ Args:
47
+ p: The depolarizing probability, either a single float or a mapping from pairs of qubits
48
+ to floats.
49
+ target_gate: The gate after which to add depolarizing noise.
50
+
51
+ Raises:
52
+ TypeError: If `p` is not either be a float or a mapping from sorted qubit pairs to
53
+ floats.
54
+ """
55
+
56
+ if not isinstance(p, (Mapping, float)):
57
+ raise TypeError( # pragma: no cover
58
+ "p must either be a float or a mapping from" # pragma: no cover
59
+ + "sorted qubit pairs to floats" # pragma: no cover
60
+ ) # pragma: no cover
61
+ self.p = p
62
+ self.p_func = (
63
+ (lambda _: p)
64
+ if isinstance(p, (int, float))
65
+ else (lambda pair: cast(Mapping, p).get(pair, 0.0))
66
+ )
67
+ self.target_gate = target_gate
68
+
69
+ def __call__(
70
+ self,
71
+ circuit: circuits.AbstractCircuit,
72
+ rng: np.random.Generator | None = None,
73
+ *,
74
+ context: transformer_api.TransformerContext | None = None,
75
+ ):
76
+ """Apply the transformer to the given circuit.
77
+
78
+ Args:
79
+ circuit: The circuit to add noise to.
80
+ context: Not used; to satisfy transformer API.
81
+
82
+ Returns:
83
+ The transformed circuit.
84
+ """
85
+ if rng is None:
86
+ rng = np.random.default_rng()
87
+ target_gate = self.target_gate
88
+
89
+ # add random Pauli gates with probability p after each of the specified gate
90
+ assert target_gate.num_qubits() == 2, "`target_gate` must be a two-qubit gate."
91
+ paulis = [ops.I, ops.X, ops.Y, ops.Z]
92
+ new_moments = []
93
+ for moment in circuit:
94
+ new_moments.append(moment)
95
+ if _gate_in_moment(target_gate, moment):
96
+ # add a new moment with the Paulis
97
+ target_pairs = {
98
+ tuple(sorted(op.qubits)) for op in moment.operations if op.gate == target_gate
99
+ }
100
+ added_moment_ops = []
101
+ for pair in target_pairs:
102
+ pair_sorted_tuple = (pair[0], pair[1])
103
+ p_i = self.p_func(pair_sorted_tuple)
104
+ apply = rng.choice([True, False], p=[p_i, 1 - p_i])
105
+ if apply:
106
+ choices = [
107
+ (pauli_a(pair[0]), pauli_b(pair[1]))
108
+ for pauli_a in paulis
109
+ for pauli_b in paulis
110
+ ][1:]
111
+ pauli_to_apply = rng.choice(np.array(choices, dtype=object))
112
+ added_moment_ops.append(pauli_to_apply)
113
+ if len(added_moment_ops) > 0:
114
+ new_moments.append(circuits.Moment(*added_moment_ops))
115
+ return circuits.Circuit.from_moments(*new_moments)
@@ -0,0 +1,54 @@
1
+ # Copyright 2024 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import numpy as np
16
+
17
+ import cirq.transformers.noise_adding as na
18
+ from cirq import circuits, devices, ops
19
+
20
+
21
+ def test_noise_adding():
22
+ qubits = devices.LineQubit.range(4)
23
+ one_layer = circuits.Circuit(ops.CZ(*qubits[:2]), ops.CZ(*qubits[2:]))
24
+ circuit = one_layer * 10
25
+
26
+ # test that p=0 does nothing
27
+ transformed_circuit_p0 = na.DepolarizingNoiseTransformer(0.0)(circuit)
28
+ assert transformed_circuit_p0 == circuit
29
+
30
+ # test that p=1 doubles the circuit depth
31
+ transformed_circuit_p1 = na.DepolarizingNoiseTransformer(1.0)(circuit)
32
+ assert len(transformed_circuit_p1) == 20
33
+
34
+ # test that we get a deterministic result when using a specific rng
35
+ rng = np.random.default_rng(0)
36
+ transformed_circuit_p0_03 = na.DepolarizingNoiseTransformer(0.03)(circuit, rng=rng)
37
+ expected_circuit = (
38
+ one_layer * 2
39
+ + circuits.Circuit(ops.I(qubits[2]), ops.Z(qubits[3]))
40
+ + one_layer * 4
41
+ + circuits.Circuit(ops.Z(qubits[0]), ops.X(qubits[1]))
42
+ + one_layer * 4
43
+ + circuits.Circuit(ops.I(qubits[2]), ops.X(qubits[3]))
44
+ )
45
+ assert transformed_circuit_p0_03 == expected_circuit
46
+
47
+ # test that supplying a dictionary for p works
48
+ transformed_circuit_p_dict = na.DepolarizingNoiseTransformer(
49
+ {tuple(qubits[:2]): 1.0, tuple(qubits[2:]): 0.0}
50
+ )(circuit)
51
+ assert len(transformed_circuit_p_dict) == 20 # depth should be doubled
52
+ assert transformed_circuit_p_dict[1::2].all_qubits() == frozenset(
53
+ qubits[:2]
54
+ ) # no single-qubit gates get added to qubits[2:]
@@ -14,7 +14,7 @@
14
14
 
15
15
  """Transformers to rewrite a circuit using gates from a given target gateset."""
16
16
 
17
- from typing import Optional, Callable, Hashable, Sequence, TYPE_CHECKING, Union
17
+ from typing import Callable, Hashable, Optional, Sequence, TYPE_CHECKING, Union
18
18
 
19
19
  from cirq import circuits
20
20
  from cirq.protocols import decompose_protocol as dp
@@ -14,10 +14,11 @@
14
14
 
15
15
  from typing import Union
16
16
 
17
+ import pytest
18
+
17
19
  import cirq
18
20
  from cirq.protocols.decompose_protocol import DecomposeResult
19
21
  from cirq.transformers.optimize_for_target_gateset import _decompose_operations_to_target_gateset
20
- import pytest
21
22
 
22
23
 
23
24
  def test_decompose_operations_raises_on_stuck():
@@ -327,7 +328,7 @@ def test_optimize_for_target_gateset_multiple_passes(max_num_passes: Union[int,
327
328
 
328
329
  @pytest.mark.parametrize('max_num_passes', [2, None])
329
330
  def test_optimize_for_target_gateset_multiple_passes_dont_preserve_moment_structure(
330
- max_num_passes: Union[int, None]
331
+ max_num_passes: Union[int, None],
331
332
  ):
332
333
  gateset = cirq.CZTargetGateset(preserve_moment_structure=False)
333
334
 
@@ -169,7 +169,7 @@ def map_clean_and_borrowable_qubits(
169
169
  # one from the original system qubits.
170
170
  allocated_map[q] = qm.qborrow(1)[0]
171
171
  else:
172
- assert False, f"Unknown temporary qubit type {q}"
172
+ assert False, f"Unknown temporary qubit type {q}" # pragma: no cover
173
173
 
174
174
  # Return the transformed operation / decomposed op-tree.
175
175
  return op.transform_qubits({**allocated_map, **trivial_map})
@@ -0,0 +1,171 @@
1
+ # Copyright 2024 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from collections.abc import Sequence
16
+ from typing import Any
17
+
18
+ import numpy as np
19
+
20
+ import cirq
21
+ from cirq.ops import SingleQubitCliffordGate
22
+ from cirq.transformers import transformer_api
23
+
24
+
25
+ @transformer_api.transformer
26
+ class RandomizedMeasurements:
27
+ """A transformer that appends a moment of random rotations from a given unitary ensemble (pauli,
28
+ clifford, cue)"""
29
+
30
+ def __init__(self, subsystem: Sequence[int] | None = None):
31
+ """Class structure for performing and analyzing a general randomized measurement protocol.
32
+ For more details on the randomized measurement toolbox see https://arxiv.org/abs/2203.11374
33
+
34
+ Args:
35
+ subsystem: The specific subsystem (e.g qubit index) to measure in random basis
36
+ rest of the qubits are measured in the computational basis
37
+ """
38
+ self.subsystem = subsystem
39
+
40
+ def __call__(
41
+ self,
42
+ circuit: "cirq.AbstractCircuit",
43
+ unitary_ensemble: str = "pauli",
44
+ rng: np.random.Generator | None = None,
45
+ *,
46
+ context: transformer_api.TransformerContext | None = None,
47
+ ) -> "cirq.Circuit":
48
+ """Apply the transformer to the given circuit. Given an input circuit returns
49
+ a new circuit with the pre-measurement unitaries and measurements gates added.
50
+ to the qubits in the subsystem provided.If no subsystem is specified in the
51
+ construction of this class it defaults to measuring all the qubits in the
52
+ randomized bases.
53
+
54
+ Args:
55
+ circuit: The circuit to add randomized measurements to.
56
+ unitary_ensemble: Choice of unitary ensemble (pauli/clifford/cue(circular
57
+ unitary ensemble))
58
+ context: Not used; to satisfy transformer API.
59
+ rng: Random number generator.
60
+
61
+ Returns:
62
+ A circuit with pre-measurement unitaries and measurements added
63
+ """
64
+
65
+ all_qubits = sorted(circuit.all_qubits())
66
+ if self.subsystem is None:
67
+ subsystem_qubits = all_qubits
68
+ else:
69
+ subsystem_qubits = [all_qubits[s] for s in self.subsystem]
70
+ if rng is None:
71
+ rng = np.random.default_rng()
72
+
73
+ pre_measurement_moment = self.random_single_qubit_unitary_moment(
74
+ unitary_ensemble, subsystem_qubits, rng
75
+ )
76
+
77
+ return cirq.Circuit.from_moments(
78
+ *circuit.moments, pre_measurement_moment, cirq.M(*subsystem_qubits, key="m")
79
+ )
80
+
81
+ def random_single_qubit_unitary_moment(
82
+ self, unitary_ensemble: str, qubits: Sequence[Any], rng: np.random.Generator
83
+ ) -> "cirq.Moment":
84
+ """Outputs the cirq moment associated with the pre-measurement rotations.
85
+
86
+ Args:
87
+ unitary_ensemble: clifford, pauli, cue
88
+ qubits: List of qubits
89
+ rng: Random number generator to be used in sampling.
90
+
91
+ Returns:
92
+ The cirq moment associated with the pre-measurement rotations
93
+
94
+ Raises:
95
+ ValueError: When unitary_ensemble is not one of "cue", "pauli" or "clifford"
96
+ """
97
+
98
+ if unitary_ensemble.lower() == "pauli":
99
+ unitaries = [_pauli_basis_rotation(rng) for _ in range(len(qubits))]
100
+
101
+ elif unitary_ensemble.lower() == "clifford":
102
+ unitaries = [_single_qubit_clifford(rng) for _ in range(len(qubits))]
103
+
104
+ elif unitary_ensemble.lower() == "cue":
105
+ unitaries = [_single_qubit_cue(rng) for _ in range(len(qubits))]
106
+
107
+ else:
108
+ raise ValueError("Only pauli, clifford and cue unitaries are available")
109
+
110
+ op_list: list[cirq.Operation] = []
111
+
112
+ for idx, unitary in enumerate(unitaries):
113
+ op_list.append(unitary.on(qubits[idx]))
114
+
115
+ return cirq.Moment.from_ops(*op_list)
116
+
117
+
118
+ def _pauli_basis_rotation(rng: np.random.Generator) -> "cirq.Gate":
119
+ """Randomly generate a Pauli basis rotation.
120
+
121
+ Args:
122
+ rng: Random number generator
123
+
124
+ Returns:
125
+ cirq gate
126
+ """
127
+ basis_idx = rng.choice(np.arange(3))
128
+
129
+ if basis_idx == 0:
130
+ gate: "cirq.Gate" = cirq.Ry(rads=-np.pi / 2)
131
+ elif basis_idx == 1:
132
+ gate = cirq.Rx(rads=np.pi / 2)
133
+ else:
134
+ gate = cirq.I
135
+ return gate
136
+
137
+
138
+ def _single_qubit_clifford(rng: np.random.Generator) -> "cirq.Gate":
139
+ """Randomly generate a single-qubit Clifford rotation.
140
+
141
+ Args:
142
+ rng: Random number generator
143
+
144
+ Returns:
145
+ cirq gate
146
+ """
147
+
148
+ # there are 24 distinct single-qubit Clifford gates
149
+ clifford_idx = rng.choice(np.arange(24))
150
+
151
+ return SingleQubitCliffordGate.to_phased_xz_gate(
152
+ SingleQubitCliffordGate.all_single_qubit_cliffords[clifford_idx]
153
+ )
154
+
155
+
156
+ def _single_qubit_cue(rng: np.random.Generator) -> "cirq.Gate":
157
+ """Randomly generate a CUE gate.
158
+
159
+ Args:
160
+ rng: Random number generator
161
+
162
+ Returns:
163
+ cirq gate
164
+ """
165
+
166
+ # phasedxz parameters are distinct between -1 and +1
167
+ x_exponent, z_exponent, axis_phase_exponent = 1 - 2 * rng.random(size=3)
168
+
169
+ return cirq.PhasedXZGate(
170
+ x_exponent=x_exponent, z_exponent=z_exponent, axis_phase_exponent=axis_phase_exponent
171
+ )
@@ -0,0 +1,68 @@
1
+ # Copyright 2024 The Cirq Developers
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import pytest
16
+
17
+ import cirq
18
+ import cirq.transformers.randomized_measurements as rand_meas
19
+
20
+
21
+ def test_randomized_measurements_appends_two_moments_on_returned_circuit():
22
+ # Create a 4-qubit circuit
23
+ q0, q1, q2, q3 = cirq.LineQubit.range(4)
24
+ circuit_pre = cirq.Circuit(
25
+ [cirq.H(q0), cirq.CNOT(q0, q1), cirq.CNOT(q1, q2), cirq.CNOT(q2, q3)]
26
+ )
27
+ num_moments_pre = len(circuit_pre.moments)
28
+
29
+ # Append randomized measurements to subsystem
30
+ unitary_ensembles = ['pauli', 'clifford', 'cue']
31
+ for u in unitary_ensembles:
32
+ circuit_post = rand_meas.RandomizedMeasurements()(circuit_pre, unitary_ensemble=u)
33
+ num_moments_post = len(circuit_post.moments)
34
+ assert num_moments_post == num_moments_pre + 2
35
+
36
+
37
+ def test_append_randomized_measurements_leaves_qubits_not_in_specified_subsystem_unchanged():
38
+ # Create a 4-qubit circuit
39
+ q0, q1, q2, q3 = cirq.LineQubit.range(4)
40
+ circuit = cirq.Circuit([cirq.H(q0), cirq.CNOT(q0, q1), cirq.CNOT(q1, q2), cirq.CNOT(q2, q3)])
41
+
42
+ # Append randomized measurements to subsystem
43
+ circuit = rand_meas.RandomizedMeasurements(subsystem=(0, 1))(circuit)
44
+ # assert latter subsystems were not changed.
45
+ assert circuit.operation_at(q2, 4) is None
46
+ assert circuit.operation_at(q3, 4) is None
47
+
48
+
49
+ def test_append_randomized_measurements_leaves_qubits_not_in_noncontinuous_subsystem_unchanged():
50
+ # Create a 4-qubit circuit
51
+ q0, q1, q2, q3 = cirq.LineQubit.range(4)
52
+ circuit = cirq.Circuit([cirq.H(q0), cirq.CNOT(q0, q1), cirq.CNOT(q1, q2), cirq.CNOT(q2, q3)])
53
+
54
+ # Append randomized measurements to subsystem
55
+ circuit = rand_meas.RandomizedMeasurements(subsystem=(0, 2))(circuit)
56
+
57
+ # assert latter subsystems were not changed.
58
+ assert circuit.operation_at(q1, 4) is None
59
+ assert circuit.operation_at(q3, 4) is None
60
+
61
+
62
+ def test_exception():
63
+ q0, q1, q2, q3 = cirq.LineQubit.range(4)
64
+ circuit = cirq.Circuit([cirq.H(q0), cirq.CNOT(q0, q1), cirq.CNOT(q1, q2), cirq.CNOT(q2, q3)])
65
+
66
+ # Append randomized measurements to subsystem
67
+ with pytest.raises(ValueError):
68
+ rand_meas.RandomizedMeasurements()(circuit, unitary_ensemble="coe")