cirq-core 1.7.0.dev20250825174419__py3-none-any.whl → 1.7.0.dev20251203004401__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.
Files changed (426) hide show
  1. cirq/__init__.py +1 -0
  2. cirq/_compat.py +3 -2
  3. cirq/_compat_test.py +16 -15
  4. cirq/_doc.py +4 -3
  5. cirq/_import.py +2 -1
  6. cirq/_version.py +1 -1
  7. cirq/_version_test.py +1 -1
  8. cirq/circuits/_bucket_priority_queue.py +2 -1
  9. cirq/circuits/circuit.py +19 -17
  10. cirq/circuits/circuit_operation.py +2 -1
  11. cirq/circuits/circuit_operation_test.py +19 -0
  12. cirq/circuits/circuit_test.py +31 -12
  13. cirq/circuits/frozen_circuit.py +3 -2
  14. cirq/circuits/moment.py +3 -15
  15. cirq/circuits/optimization_pass.py +2 -1
  16. cirq/circuits/qasm_output.py +39 -10
  17. cirq/circuits/qasm_output_test.py +51 -2
  18. cirq/circuits/text_diagram_drawer.py +2 -1
  19. cirq/contrib/acquaintance/bipartite.py +2 -1
  20. cirq/contrib/acquaintance/devices.py +1 -1
  21. cirq/contrib/acquaintance/executor.py +4 -5
  22. cirq/contrib/acquaintance/executor_test.py +2 -1
  23. cirq/contrib/acquaintance/gates.py +2 -1
  24. cirq/contrib/acquaintance/gates_test.py +1 -1
  25. cirq/contrib/acquaintance/inspection_utils.py +2 -1
  26. cirq/contrib/acquaintance/mutation_utils.py +2 -1
  27. cirq/contrib/acquaintance/optimizers.py +2 -1
  28. cirq/contrib/acquaintance/permutation.py +2 -1
  29. cirq/contrib/acquaintance/permutation_test.py +1 -1
  30. cirq/contrib/acquaintance/shift.py +2 -1
  31. cirq/contrib/acquaintance/shift_swap_network.py +2 -1
  32. cirq/contrib/acquaintance/strategies/complete.py +3 -2
  33. cirq/contrib/acquaintance/strategies/cubic.py +2 -1
  34. cirq/contrib/acquaintance/strategies/quartic_paired.py +2 -1
  35. cirq/contrib/acquaintance/strategies/quartic_paired_test.py +1 -1
  36. cirq/contrib/acquaintance/testing.py +2 -1
  37. cirq/contrib/acquaintance/topological_sort.py +2 -1
  38. cirq/contrib/bayesian_network/bayesian_network_gate.py +3 -2
  39. cirq/contrib/circuitdag/circuit_dag.py +4 -2
  40. cirq/contrib/custom_simulators/custom_state_simulator.py +2 -1
  41. cirq/contrib/custom_simulators/custom_state_simulator_test.py +1 -1
  42. cirq/contrib/graph_device/graph_device.py +2 -1
  43. cirq/contrib/graph_device/graph_device_test.py +2 -1
  44. cirq/contrib/graph_device/hypergraph.py +2 -1
  45. cirq/contrib/graph_device/uniform_graph_device.py +2 -1
  46. cirq/contrib/json.py +14 -2
  47. cirq/contrib/json_test_data/BayesianNetworkGate.json +10 -0
  48. cirq/contrib/json_test_data/BayesianNetworkGate.repr +3 -0
  49. cirq/contrib/json_test_data/QuantumVolumeResult.json +169 -0
  50. cirq/contrib/json_test_data/QuantumVolumeResult.repr +22 -0
  51. cirq/contrib/json_test_data/SwapPermutationGate.json +3 -0
  52. cirq/contrib/json_test_data/SwapPermutationGate.repr +1 -0
  53. cirq/contrib/json_test_data/spec.py +0 -2
  54. cirq/contrib/noise_models/noise_models.py +2 -1
  55. cirq/contrib/paulistring/clifford_optimize.py +20 -2
  56. cirq/contrib/paulistring/optimize.py +1 -1
  57. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +146 -35
  58. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +81 -178
  59. cirq/contrib/paulistring/recombine.py +5 -2
  60. cirq/contrib/paulistring/separate.py +1 -1
  61. cirq/contrib/qasm_import/_lexer.py +6 -1
  62. cirq/contrib/qasm_import/_lexer_test.py +1 -1
  63. cirq/contrib/qasm_import/_parser.py +24 -8
  64. cirq/contrib/qasm_import/_parser_test.py +44 -6
  65. cirq/contrib/qcircuit/qcircuit_pdf_test.py +6 -9
  66. cirq/contrib/quantikz/__init__.py +21 -0
  67. cirq/contrib/quantikz/circuit_to_latex_quantikz.py +680 -0
  68. cirq/contrib/quantikz/circuit_to_latex_quantikz_test.py +253 -0
  69. cirq/contrib/quantikz/circuit_to_latex_render.py +424 -0
  70. cirq/contrib/quantikz/circuit_to_latex_render_test.py +44 -0
  71. cirq/contrib/quantum_volume/quantum_volume.py +2 -1
  72. cirq/contrib/quimb/density_matrix.py +1 -1
  73. cirq/contrib/quimb/grid_circuits.py +2 -1
  74. cirq/contrib/quimb/grid_circuits_test.py +1 -1
  75. cirq/contrib/quimb/mps_simulator.py +4 -3
  76. cirq/contrib/quimb/state_vector.py +2 -1
  77. cirq/contrib/quirk/export_to_quirk.py +2 -1
  78. cirq/contrib/quirk/linearize_circuit.py +1 -1
  79. cirq/contrib/quirk/quirk_gate.py +2 -1
  80. cirq/contrib/routing/device.py +1 -1
  81. cirq/contrib/routing/greedy.py +2 -1
  82. cirq/contrib/routing/initialization.py +2 -1
  83. cirq/contrib/routing/router.py +2 -1
  84. cirq/contrib/routing/swap_network.py +2 -1
  85. cirq/contrib/routing/utils.py +2 -1
  86. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +7 -5
  87. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py +6 -6
  88. cirq/devices/device.py +2 -1
  89. cirq/devices/grid_device_metadata.py +2 -1
  90. cirq/devices/grid_qubit.py +7 -6
  91. cirq/devices/insertion_noise_model.py +2 -1
  92. cirq/devices/line_qubit.py +2 -1
  93. cirq/devices/named_topologies.py +2 -1
  94. cirq/devices/noise_model.py +2 -1
  95. cirq/devices/noise_model_test.py +1 -1
  96. cirq/devices/noise_properties.py +2 -1
  97. cirq/devices/superconducting_qubits_noise_properties_test.py +2 -1
  98. cirq/devices/thermal_noise_model.py +2 -1
  99. cirq/experiments/__init__.py +2 -0
  100. cirq/experiments/benchmarking/parallel_xeb.py +2 -1
  101. cirq/experiments/benchmarking/parallel_xeb_test.py +1 -1
  102. cirq/experiments/fidelity_estimation.py +2 -1
  103. cirq/experiments/fidelity_estimation_test.py +1 -1
  104. cirq/experiments/ghz_2d.py +150 -0
  105. cirq/experiments/ghz_2d_test.py +155 -0
  106. cirq/experiments/n_qubit_tomography.py +2 -1
  107. cirq/experiments/n_qubit_tomography_test.py +1 -1
  108. cirq/experiments/purity_estimation.py +1 -1
  109. cirq/experiments/qubit_characterizations.py +33 -4
  110. cirq/experiments/qubit_characterizations_test.py +16 -0
  111. cirq/experiments/random_quantum_circuit_generation.py +2 -1
  112. cirq/experiments/random_quantum_circuit_generation_test.py +2 -1
  113. cirq/experiments/readout_confusion_matrix.py +2 -1
  114. cirq/experiments/readout_confusion_matrix_test.py +1 -1
  115. cirq/experiments/single_qubit_readout_calibration.py +2 -1
  116. cirq/experiments/single_qubit_readout_calibration_test.py +1 -1
  117. cirq/experiments/t1_decay_experiment.py +2 -1
  118. cirq/experiments/two_qubit_xeb.py +2 -1
  119. cirq/experiments/two_qubit_xeb_test.py +1 -1
  120. cirq/experiments/xeb_fitting.py +2 -1
  121. cirq/experiments/xeb_fitting_test.py +1 -1
  122. cirq/experiments/xeb_sampling.py +5 -3
  123. cirq/experiments/xeb_sampling_test.py +1 -1
  124. cirq/experiments/xeb_simulation.py +2 -1
  125. cirq/experiments/xeb_simulation_test.py +2 -1
  126. cirq/experiments/z_phase_calibration.py +2 -1
  127. cirq/experiments/z_phase_calibration_test.py +18 -3
  128. cirq/interop/quirk/cells/__init__.py +1 -2
  129. cirq/interop/quirk/cells/all_cells.py +2 -1
  130. cirq/interop/quirk/cells/arithmetic_cells.py +2 -1
  131. cirq/interop/quirk/cells/cell.py +2 -1
  132. cirq/interop/quirk/cells/composite_cell.py +2 -1
  133. cirq/interop/quirk/cells/composite_cell_test.py +1 -1
  134. cirq/interop/quirk/cells/control_cells.py +2 -1
  135. cirq/interop/quirk/cells/frequency_space_cells.py +1 -1
  136. cirq/interop/quirk/cells/ignored_cells.py +1 -1
  137. cirq/interop/quirk/cells/input_cells.py +2 -1
  138. cirq/interop/quirk/cells/input_rotation_cells.py +2 -1
  139. cirq/interop/quirk/cells/measurement_cells.py +2 -1
  140. cirq/interop/quirk/cells/parse.py +2 -11
  141. cirq/interop/quirk/cells/qubit_permutation_cells.py +2 -1
  142. cirq/interop/quirk/cells/scalar_cells.py +2 -1
  143. cirq/interop/quirk/cells/single_qubit_rotation_cells.py +2 -1
  144. cirq/interop/quirk/cells/swap_cell.py +2 -1
  145. cirq/interop/quirk/cells/unsupported_cells.py +1 -1
  146. cirq/interop/quirk/url_to_circuit.py +2 -1
  147. cirq/json_resolver_cache.py +0 -2
  148. cirq/linalg/decompositions.py +6 -2
  149. cirq/linalg/decompositions_test.py +1 -0
  150. cirq/linalg/diagonalize.py +1 -1
  151. cirq/linalg/predicates.py +2 -1
  152. cirq/linalg/tolerance.py +2 -1
  153. cirq/linalg/transformations.py +3 -2
  154. cirq/ops/arithmetic_operation.py +4 -3
  155. cirq/ops/arithmetic_operation_test.py +1 -1
  156. cirq/ops/boolean_hamiltonian.py +4 -3
  157. cirq/ops/classically_controlled_operation.py +11 -11
  158. cirq/ops/classically_controlled_operation_test.py +26 -2
  159. cirq/ops/clifford_gate.py +3 -2
  160. cirq/ops/clifford_gate_test.py +1 -2
  161. cirq/ops/common_channels.py +2 -1
  162. cirq/ops/common_gates.py +3 -2
  163. cirq/ops/control_values.py +2 -1
  164. cirq/ops/controlled_gate.py +3 -2
  165. cirq/ops/controlled_gate_test.py +2 -1
  166. cirq/ops/controlled_operation.py +3 -2
  167. cirq/ops/controlled_operation_test.py +2 -1
  168. cirq/ops/dense_pauli_string.py +44 -81
  169. cirq/ops/dense_pauli_string_test.py +21 -0
  170. cirq/ops/diagonal_gate.py +3 -2
  171. cirq/ops/eigen_gate.py +9 -7
  172. cirq/ops/fourier_transform.py +3 -2
  173. cirq/ops/fourier_transform_test.py +2 -4
  174. cirq/ops/fsim_gate.py +3 -2
  175. cirq/ops/gate_operation.py +23 -12
  176. cirq/ops/gateset.py +22 -2
  177. cirq/ops/global_phase_op.py +3 -2
  178. cirq/ops/greedy_qubit_manager.py +2 -1
  179. cirq/ops/identity.py +2 -1
  180. cirq/ops/kraus_channel.py +2 -1
  181. cirq/ops/linear_combinations.py +12 -17
  182. cirq/ops/linear_combinations_test.py +23 -1
  183. cirq/ops/matrix_gates.py +2 -1
  184. cirq/ops/measure_util.py +8 -6
  185. cirq/ops/measurement_gate.py +2 -1
  186. cirq/ops/mixed_unitary_channel.py +2 -1
  187. cirq/ops/named_qubit.py +2 -2
  188. cirq/ops/op_tree.py +2 -1
  189. cirq/ops/parallel_gate.py +3 -2
  190. cirq/ops/parity_gates.py +2 -1
  191. cirq/ops/parity_gates_test.py +35 -0
  192. cirq/ops/pauli_interaction_gate.py +2 -1
  193. cirq/ops/pauli_measurement_gate.py +2 -1
  194. cirq/ops/pauli_string.py +37 -57
  195. cirq/ops/pauli_string_phasor.py +6 -5
  196. cirq/ops/pauli_string_raw_types.py +2 -1
  197. cirq/ops/pauli_string_test.py +49 -6
  198. cirq/ops/pauli_sum_exponential.py +2 -1
  199. cirq/ops/permutation_gate.py +2 -1
  200. cirq/ops/phased_iswap_gate.py +3 -2
  201. cirq/ops/phased_x_gate.py +5 -4
  202. cirq/ops/phased_x_z_gate.py +12 -5
  203. cirq/ops/projector.py +2 -1
  204. cirq/ops/qubit_manager.py +2 -1
  205. cirq/ops/qubit_order.py +2 -1
  206. cirq/ops/qubit_order_or_list.py +1 -1
  207. cirq/ops/random_gate_channel.py +3 -2
  208. cirq/ops/raw_types.py +33 -16
  209. cirq/ops/raw_types_test.py +4 -3
  210. cirq/ops/state_preparation_channel.py +2 -1
  211. cirq/ops/three_qubit_gates.py +3 -2
  212. cirq/ops/two_qubit_diagonal_gate.py +3 -2
  213. cirq/ops/uniform_superposition_gate.py +2 -1
  214. cirq/ops/wait_gate.py +10 -4
  215. cirq/protocols/act_on_protocol.py +2 -1
  216. cirq/protocols/act_on_protocol_test.py +2 -1
  217. cirq/protocols/apply_channel_protocol.py +2 -1
  218. cirq/protocols/apply_mixture_protocol.py +2 -1
  219. cirq/protocols/apply_mixture_protocol_test.py +2 -1
  220. cirq/protocols/apply_unitary_protocol.py +2 -1
  221. cirq/protocols/apply_unitary_protocol_test.py +2 -0
  222. cirq/protocols/approximate_equality_protocol.py +2 -1
  223. cirq/protocols/circuit_diagram_info_protocol.py +2 -1
  224. cirq/protocols/control_key_protocol.py +7 -0
  225. cirq/protocols/decompose_protocol.py +2 -12
  226. cirq/protocols/has_stabilizer_effect_protocol.py +1 -1
  227. cirq/protocols/has_stabilizer_effect_protocol_test.py +11 -9
  228. cirq/protocols/has_unitary_protocol_test.py +3 -3
  229. cirq/protocols/hash_from_pickle_test.py +2 -2
  230. cirq/protocols/inverse_protocol.py +2 -1
  231. cirq/protocols/json_serialization.py +5 -4
  232. cirq/protocols/json_serialization_test.py +31 -31
  233. cirq/protocols/kraus_protocol.py +4 -3
  234. cirq/protocols/kraus_protocol_test.py +7 -7
  235. cirq/protocols/measurement_key_protocol.py +32 -8
  236. cirq/protocols/mixture_protocol.py +3 -2
  237. cirq/protocols/mixture_protocol_test.py +7 -7
  238. cirq/protocols/mul_protocol_test.py +4 -4
  239. cirq/protocols/phase_protocol.py +13 -4
  240. cirq/protocols/pow_protocol.py +2 -1
  241. cirq/protocols/pow_protocol_test.py +5 -5
  242. cirq/protocols/qasm.py +2 -1
  243. cirq/protocols/qid_shape_protocol.py +2 -1
  244. cirq/protocols/resolve_parameters.py +17 -15
  245. cirq/protocols/trace_distance_bound.py +2 -1
  246. cirq/protocols/unitary_protocol.py +21 -21
  247. cirq/protocols/unitary_protocol_test.py +31 -19
  248. cirq/qis/channels.py +1 -1
  249. cirq/qis/channels_test.py +1 -1
  250. cirq/qis/clifford_tableau.py +16 -15
  251. cirq/qis/clifford_tableau_test.py +17 -17
  252. cirq/qis/entropy.py +3 -3
  253. cirq/qis/entropy_test.py +1 -1
  254. cirq/qis/quantum_state_representation.py +2 -1
  255. cirq/qis/states.py +7 -2
  256. cirq/qis/states_test.py +54 -54
  257. cirq/sim/classical_simulator.py +25 -14
  258. cirq/sim/classical_simulator_test.py +85 -30
  259. cirq/sim/clifford/clifford_simulator.py +7 -6
  260. cirq/sim/clifford/clifford_simulator_test.py +51 -50
  261. cirq/sim/clifford/clifford_tableau_simulation_state.py +2 -1
  262. cirq/sim/clifford/stabilizer_ch_form_simulation_state.py +2 -1
  263. cirq/sim/clifford/stabilizer_sampler.py +1 -1
  264. cirq/sim/clifford/stabilizer_simulation_state.py +2 -1
  265. cirq/sim/clifford/stabilizer_state_ch_form.py +16 -15
  266. cirq/sim/clifford/stabilizer_state_ch_form_test.py +0 -1
  267. cirq/sim/density_matrix_simulation_state.py +7 -6
  268. cirq/sim/density_matrix_simulator.py +3 -2
  269. cirq/sim/density_matrix_simulator_test.py +94 -84
  270. cirq/sim/density_matrix_utils.py +2 -1
  271. cirq/sim/density_matrix_utils_test.py +1 -1
  272. cirq/sim/mux.py +35 -8
  273. cirq/sim/mux_test.py +39 -26
  274. cirq/sim/simulation_product_state.py +2 -1
  275. cirq/sim/simulation_product_state_test.py +8 -7
  276. cirq/sim/simulation_state.py +6 -5
  277. cirq/sim/simulation_state_base.py +3 -2
  278. cirq/sim/simulation_state_test.py +7 -6
  279. cirq/sim/simulation_utils.py +2 -1
  280. cirq/sim/simulator.py +4 -3
  281. cirq/sim/simulator_base.py +2 -1
  282. cirq/sim/simulator_base_test.py +51 -36
  283. cirq/sim/simulator_test.py +41 -36
  284. cirq/sim/sparse_simulator.py +3 -2
  285. cirq/sim/sparse_simulator_test.py +92 -82
  286. cirq/sim/state_vector.py +5 -6
  287. cirq/sim/state_vector_simulation_state.py +10 -9
  288. cirq/sim/state_vector_simulator.py +2 -1
  289. cirq/sim/state_vector_simulator_test.py +9 -9
  290. cirq/sim/state_vector_test.py +40 -39
  291. cirq/study/__init__.py +1 -0
  292. cirq/study/flatten_expressions.py +2 -1
  293. cirq/study/resolver.py +31 -18
  294. cirq/study/resolver_test.py +1 -1
  295. cirq/study/result.py +2 -1
  296. cirq/study/result_test.py +20 -20
  297. cirq/study/sweepable.py +2 -1
  298. cirq/study/sweepable_test.py +20 -20
  299. cirq/study/sweeps.py +26 -1
  300. cirq/study/sweeps_test.py +67 -43
  301. cirq/testing/_compat_test_data/__init__.py +3 -3
  302. cirq/testing/circuit_compare.py +2 -1
  303. cirq/testing/circuit_compare_test.py +16 -14
  304. cirq/testing/consistent_act_on_test.py +1 -1
  305. cirq/testing/consistent_channels.py +2 -2
  306. cirq/testing/consistent_controlled_gate_op.py +2 -2
  307. cirq/testing/consistent_controlled_gate_op_test.py +2 -1
  308. cirq/testing/consistent_decomposition.py +4 -2
  309. cirq/testing/consistent_phase_by.py +1 -1
  310. cirq/testing/consistent_protocols.py +2 -1
  311. cirq/testing/consistent_protocols_test.py +3 -3
  312. cirq/testing/consistent_qasm.py +4 -3
  313. cirq/testing/consistent_qasm_test.py +3 -3
  314. cirq/testing/consistent_resolve_parameters.py +1 -1
  315. cirq/testing/consistent_unitary.py +1 -1
  316. cirq/testing/consistent_unitary_test.py +1 -1
  317. cirq/testing/deprecation.py +1 -1
  318. cirq/testing/devices.py +3 -2
  319. cirq/testing/equals_tester.py +4 -3
  320. cirq/testing/equivalent_basis_map.py +4 -2
  321. cirq/testing/json.py +3 -2
  322. cirq/testing/lin_alg_utils.py +1 -1
  323. cirq/testing/logs.py +1 -1
  324. cirq/testing/op_tree.py +1 -1
  325. cirq/testing/order_tester.py +2 -2
  326. cirq/testing/pytest_utils.py +2 -1
  327. cirq/testing/random_circuit.py +2 -1
  328. cirq/testing/random_circuit_test.py +2 -1
  329. cirq/testing/repr_pretty_tester.py +3 -3
  330. cirq/transformers/__init__.py +1 -0
  331. cirq/transformers/_connected_component.py +231 -0
  332. cirq/transformers/_connected_component_test.py +200 -0
  333. cirq/transformers/align_test.py +13 -13
  334. cirq/transformers/analytical_decompositions/clifford_decomposition.py +8 -7
  335. cirq/transformers/analytical_decompositions/clifford_decomposition_test.py +5 -5
  336. cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +11 -10
  337. cirq/transformers/analytical_decompositions/controlled_gate_decomposition_test.py +6 -6
  338. cirq/transformers/analytical_decompositions/cphase_to_fsim.py +3 -2
  339. cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +11 -10
  340. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +8 -7
  341. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +17 -20
  342. cirq/transformers/analytical_decompositions/single_qubit_decompositions_test.py +33 -27
  343. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry_test.py +1 -1
  344. cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +1 -1
  345. cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +12 -11
  346. cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +5 -2
  347. cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +3 -3
  348. cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +2 -1
  349. cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +2 -1
  350. cirq/transformers/analytical_decompositions/two_qubit_to_ms_test.py +2 -2
  351. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +2 -1
  352. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap_test.py +32 -30
  353. cirq/transformers/drop_negligible_operations_test.py +7 -7
  354. cirq/transformers/dynamical_decoupling.py +185 -112
  355. cirq/transformers/dynamical_decoupling_test.py +195 -201
  356. cirq/transformers/eject_phased_paulis.py +2 -1
  357. cirq/transformers/eject_phased_paulis_test.py +3 -2
  358. cirq/transformers/eject_z.py +5 -3
  359. cirq/transformers/eject_z_test.py +23 -25
  360. cirq/transformers/expand_composite.py +3 -2
  361. cirq/transformers/expand_composite_test.py +14 -14
  362. cirq/transformers/gauge_compiling/__init__.py +13 -0
  363. cirq/transformers/gauge_compiling/gauge_compiling.py +3 -2
  364. cirq/transformers/gauge_compiling/gauge_compiling_test.py +14 -12
  365. cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +3 -3
  366. cirq/transformers/gauge_compiling/idle_moments_gauge.py +225 -0
  367. cirq/transformers/gauge_compiling/idle_moments_gauge_test.py +193 -0
  368. cirq/transformers/gauge_compiling/multi_moment_cphase_gauge.py +242 -0
  369. cirq/transformers/gauge_compiling/multi_moment_cphase_gauge_test.py +243 -0
  370. cirq/transformers/gauge_compiling/multi_moment_gauge_compiling.py +151 -0
  371. cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +2 -1
  372. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +1 -1
  373. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils_test.py +6 -6
  374. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +3 -2
  375. cirq/transformers/measurement_transformers.py +2 -1
  376. cirq/transformers/measurement_transformers_test.py +45 -39
  377. cirq/transformers/merge_k_qubit_gates.py +2 -1
  378. cirq/transformers/merge_k_qubit_gates_test.py +1 -1
  379. cirq/transformers/merge_single_qubit_gates.py +9 -5
  380. cirq/transformers/merge_single_qubit_gates_test.py +22 -22
  381. cirq/transformers/noise_adding_test.py +2 -2
  382. cirq/transformers/optimize_for_target_gateset.py +2 -1
  383. cirq/transformers/optimize_for_target_gateset_test.py +11 -9
  384. cirq/transformers/qubit_management_transformers_test.py +6 -2
  385. cirq/transformers/routing/mapping_manager.py +2 -1
  386. cirq/transformers/routing/route_circuit_cqc.py +2 -1
  387. cirq/transformers/stratify.py +2 -1
  388. cirq/transformers/symbolize.py +2 -1
  389. cirq/transformers/tag_transformers.py +2 -1
  390. cirq/transformers/target_gatesets/compilation_target_gateset.py +2 -1
  391. cirq/transformers/target_gatesets/cz_gateset.py +2 -1
  392. cirq/transformers/target_gatesets/cz_gateset_test.py +1 -1
  393. cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +2 -1
  394. cirq/transformers/transformer_api.py +2 -1
  395. cirq/transformers/transformer_primitives.py +271 -145
  396. cirq/transformers/transformer_primitives_test.py +185 -1
  397. cirq/value/abc_alt.py +2 -1
  398. cirq/value/classical_data.py +2 -1
  399. cirq/value/condition.py +2 -1
  400. cirq/value/digits.py +9 -2
  401. cirq/value/duration.py +6 -5
  402. cirq/value/linear_dict.py +4 -9
  403. cirq/value/measurement_key.py +2 -1
  404. cirq/value/periodic_value.py +3 -2
  405. cirq/value/product_state.py +2 -1
  406. cirq/value/value_equality_attr.py +2 -1
  407. cirq/vis/density_matrix.py +1 -1
  408. cirq/vis/heatmap.py +2 -1
  409. cirq/vis/histogram.py +2 -1
  410. cirq/vis/state_histogram.py +2 -1
  411. cirq/work/collector.py +2 -1
  412. cirq/work/observable_grouping.py +2 -1
  413. cirq/work/observable_measurement.py +2 -1
  414. cirq/work/observable_measurement_data.py +2 -1
  415. cirq/work/observable_measurement_test.py +1 -1
  416. cirq/work/observable_readout_calibration.py +2 -1
  417. cirq/work/observable_readout_calibration_test.py +1 -1
  418. cirq/work/observable_settings.py +2 -1
  419. cirq/work/sampler.py +2 -1
  420. cirq/work/sampler_test.py +1 -1
  421. {cirq_core-1.7.0.dev20250825174419.dist-info → cirq_core-1.7.0.dev20251203004401.dist-info}/METADATA +5 -6
  422. {cirq_core-1.7.0.dev20250825174419.dist-info → cirq_core-1.7.0.dev20251203004401.dist-info}/RECORD +425 -406
  423. cirq/contrib/json_test.py +0 -33
  424. {cirq_core-1.7.0.dev20250825174419.dist-info → cirq_core-1.7.0.dev20251203004401.dist-info}/WHEEL +0 -0
  425. {cirq_core-1.7.0.dev20250825174419.dist-info → cirq_core-1.7.0.dev20251203004401.dist-info}/licenses/LICENSE +0 -0
  426. {cirq_core-1.7.0.dev20250825174419.dist-info → cirq_core-1.7.0.dev20251203004401.dist-info}/top_level.txt +0 -0
@@ -14,8 +14,9 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ from collections.abc import Collection, Sequence, Set
17
18
  from types import EllipsisType, NotImplementedType
18
- from typing import AbstractSet, Any, Collection, Sequence, TYPE_CHECKING
19
+ from typing import Any, TYPE_CHECKING
19
20
 
20
21
  import numpy as np
21
22
 
@@ -261,7 +262,7 @@ class ControlledOperation(raw_types.Operation):
261
262
  def _is_parameterized_(self) -> bool:
262
263
  return protocols.is_parameterized(self.sub_operation)
263
264
 
264
- def _parameter_names_(self) -> AbstractSet[str]:
265
+ def _parameter_names_(self) -> Set[str]:
265
266
  return protocols.parameter_names(self.sub_operation)
266
267
 
267
268
  def _resolve_parameters_(
@@ -16,8 +16,9 @@ from __future__ import annotations
16
16
 
17
17
  import itertools
18
18
  import re
19
+ from collections.abc import Sequence
19
20
  from types import EllipsisType, NotImplementedType
20
- from typing import cast, Sequence
21
+ from typing import cast
21
22
 
22
23
  import numpy as np
23
24
  import pytest
@@ -16,19 +16,9 @@ from __future__ import annotations
16
16
 
17
17
  import abc
18
18
  import numbers
19
+ from collections.abc import Callable, Iterable, Iterator, Sequence, Set
19
20
  from types import NotImplementedType
20
- from typing import (
21
- AbstractSet,
22
- Any,
23
- Callable,
24
- cast,
25
- Iterable,
26
- Iterator,
27
- overload,
28
- Self,
29
- Sequence,
30
- TYPE_CHECKING,
31
- )
21
+ from typing import Any, cast, overload, Self, TYPE_CHECKING
32
22
 
33
23
  import numpy as np
34
24
  import sympy
@@ -187,7 +177,7 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
187
177
  def _is_parameterized_(self) -> bool:
188
178
  return protocols.is_parameterized(self.coefficient)
189
179
 
190
- def _parameter_names_(self) -> AbstractSet[str]:
180
+ def _parameter_names_(self) -> Set[str]:
191
181
  return protocols.parameter_names(self.coefficient)
192
182
 
193
183
  def _resolve_parameters_(self, resolver: cirq.ParamResolver, recursive: bool) -> Self:
@@ -247,35 +237,25 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
247
237
 
248
238
  def __mul__(self, other):
249
239
  concrete_class = type(self)
250
- if isinstance(other, BaseDensePauliString):
251
- if isinstance(other, MutableDensePauliString):
252
- concrete_class = MutableDensePauliString
253
- max_len = max(len(self.pauli_mask), len(other.pauli_mask))
254
- min_len = min(len(self.pauli_mask), len(other.pauli_mask))
255
- new_mask = np.zeros(max_len, dtype=np.uint8)
256
- new_mask[: len(self.pauli_mask)] ^= self.pauli_mask
257
- new_mask[: len(other.pauli_mask)] ^= other.pauli_mask
258
- tweak = _vectorized_pauli_mul_phase(
259
- self.pauli_mask[:min_len], other.pauli_mask[:min_len]
260
- )
261
- return concrete_class(
262
- pauli_mask=new_mask, coefficient=self.coefficient * other.coefficient * tweak
263
- )
264
-
265
240
  if isinstance(other, (sympy.Basic, numbers.Number)):
266
241
  new_coef = protocols.mul(self.coefficient, other, default=None)
267
242
  if new_coef is None:
268
243
  return NotImplemented
269
244
  return concrete_class(pauli_mask=self.pauli_mask, coefficient=new_coef)
270
245
 
271
- split = _attempt_value_to_pauli_index(other)
272
- if split is not None:
273
- p, i = split
274
- mask = np.copy(self.pauli_mask)
275
- mask[i] ^= p
246
+ if (other_dps := _try_interpret_as_dps(other)) is not None:
247
+ if isinstance(other_dps, MutableDensePauliString):
248
+ concrete_class = MutableDensePauliString
249
+ max_len = max(len(self.pauli_mask), len(other_dps.pauli_mask))
250
+ min_len = min(len(self.pauli_mask), len(other_dps.pauli_mask))
251
+ new_mask = np.zeros(max_len, dtype=np.uint8)
252
+ new_mask[: len(self.pauli_mask)] ^= self.pauli_mask
253
+ new_mask[: len(other_dps.pauli_mask)] ^= other_dps.pauli_mask
254
+ tweak = _vectorized_pauli_mul_phase(
255
+ self.pauli_mask[:min_len], other_dps.pauli_mask[:min_len]
256
+ )
276
257
  return concrete_class(
277
- pauli_mask=mask,
278
- coefficient=self.coefficient * _vectorized_pauli_mul_phase(self.pauli_mask[i], p),
258
+ pauli_mask=new_mask, coefficient=self.coefficient * other_dps.coefficient * tweak
279
259
  )
280
260
 
281
261
  return NotImplemented
@@ -284,15 +264,8 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
284
264
  if isinstance(other, (sympy.Basic, numbers.Number)):
285
265
  return self.__mul__(other)
286
266
 
287
- split = _attempt_value_to_pauli_index(other)
288
- if split is not None:
289
- p, i = split
290
- mask = np.copy(self.pauli_mask)
291
- mask[i] ^= p
292
- return type(self)(
293
- pauli_mask=mask,
294
- coefficient=self.coefficient * _vectorized_pauli_mul_phase(p, self.pauli_mask[i]),
295
- )
267
+ if other := _try_interpret_as_dps(other):
268
+ return other.__mul__(self)
296
269
 
297
270
  return NotImplemented
298
271
 
@@ -369,18 +342,11 @@ class BaseDensePauliString(raw_types.Gate, metaclass=abc.ABCMeta):
369
342
  )
370
343
 
371
344
  def _commutes_(self, other: Any, *, atol: float = 1e-8) -> bool | NotImplementedType | None:
372
- if isinstance(other, BaseDensePauliString):
373
- n = min(len(self.pauli_mask), len(other.pauli_mask))
374
- phase = _vectorized_pauli_mul_phase(self.pauli_mask[:n], other.pauli_mask[:n])
345
+ if (other_dps := _try_interpret_as_dps(other)) is not None:
346
+ n = min(len(self.pauli_mask), len(other_dps.pauli_mask))
347
+ phase = _vectorized_pauli_mul_phase(self.pauli_mask[:n], other_dps.pauli_mask[:n])
375
348
  return phase == 1 or phase == -1
376
349
 
377
- # Single qubit Pauli operation.
378
- split = _attempt_value_to_pauli_index(other)
379
- if split is not None:
380
- p1, i = split
381
- p2 = self.pauli_mask[i]
382
- return (p1 or p2) == (p2 or p1)
383
-
384
350
  return NotImplemented
385
351
 
386
352
  def frozen(self) -> DensePauliString:
@@ -518,20 +484,6 @@ class MutableDensePauliString(BaseDensePauliString):
518
484
  return NotImplemented
519
485
 
520
486
  def __imul__(self, other):
521
- if isinstance(other, BaseDensePauliString):
522
- if len(other) > len(self):
523
- raise ValueError(
524
- "The receiving dense pauli string is smaller than "
525
- "the dense pauli string being multiplied into it.\n"
526
- f"self={repr(self)}\n"
527
- f"other={repr(other)}"
528
- )
529
- self_mask = self.pauli_mask[: len(other.pauli_mask)]
530
- self._coefficient *= _vectorized_pauli_mul_phase(self_mask, other.pauli_mask)
531
- self._coefficient *= other.coefficient
532
- self_mask ^= other.pauli_mask
533
- return self
534
-
535
487
  if isinstance(other, (sympy.Basic, numbers.Number)):
536
488
  new_coef = protocols.mul(self.coefficient, other, default=None)
537
489
  if new_coef is None:
@@ -539,11 +491,18 @@ class MutableDensePauliString(BaseDensePauliString):
539
491
  self._coefficient = new_coef if isinstance(new_coef, sympy.Basic) else complex(new_coef)
540
492
  return self
541
493
 
542
- split = _attempt_value_to_pauli_index(other)
543
- if split is not None:
544
- p, i = split
545
- self._coefficient *= _vectorized_pauli_mul_phase(self.pauli_mask[i], p)
546
- self.pauli_mask[i] ^= p
494
+ if (other_dps := _try_interpret_as_dps(other)) is not None:
495
+ if len(other_dps) > len(self):
496
+ raise ValueError(
497
+ "The receiving dense pauli string is smaller than "
498
+ "the dense pauli string being multiplied into it.\n"
499
+ f"self={repr(self)}\n"
500
+ f"other={repr(other)}"
501
+ )
502
+ self_mask = self.pauli_mask[: len(other_dps.pauli_mask)]
503
+ self._coefficient *= _vectorized_pauli_mul_phase(self_mask, other_dps.pauli_mask)
504
+ self._coefficient *= other_dps.coefficient
505
+ self_mask ^= other_dps.pauli_mask
547
506
  return self
548
507
 
549
508
  return NotImplemented
@@ -613,23 +572,27 @@ def _as_pauli_mask(val: Iterable[cirq.PAULI_GATE_LIKE] | np.ndarray) -> np.ndarr
613
572
  return np.array([_pauli_index(v) for v in val], dtype=np.uint8)
614
573
 
615
574
 
616
- def _attempt_value_to_pauli_index(v: cirq.Operation) -> tuple[int, int] | None:
617
- if not isinstance(v, raw_types.Operation):
618
- return None
575
+ def _try_interpret_as_dps(v: cirq.Operation) -> BaseDensePauliString | None:
576
+ if isinstance(v, BaseDensePauliString):
577
+ return v
619
578
 
620
- if not isinstance(v.gate, pauli_gates.Pauli):
621
- return None # pragma: no cover
579
+ if (ps := pauli_string._try_interpret_as_pauli_string(v)) is None:
580
+ return None
622
581
 
623
- q = v.qubits[0]
624
582
  from cirq import devices
625
583
 
626
- if not isinstance(q, devices.LineQubit):
584
+ if not all(isinstance(q, devices.LineQubit) for q in ps.qubits):
627
585
  raise ValueError(
628
586
  'Got a Pauli operation, but it was applied to a qubit type '
629
587
  'other than `cirq.LineQubit` so its dense index is ambiguous.\n'
630
588
  f'v={repr(v)}.'
631
589
  )
632
- return pauli_string.PAULI_GATE_LIKE_TO_INDEX_MAP[v.gate], q.x
590
+
591
+ pauli_mask = np.zeros(max((q.x + 1 for q in ps.qubits), default=0), dtype=np.uint8)
592
+ for q in ps.qubits:
593
+ pauli_mask[q.x] = pauli_string.PAULI_GATE_LIKE_TO_INDEX_MAP[ps[q]]
594
+
595
+ return DensePauliString(pauli_mask)
633
596
 
634
597
 
635
598
  def _vectorized_pauli_mul_phase(lhs: int | np.ndarray, rhs: int | np.ndarray) -> complex:
@@ -173,6 +173,10 @@ def test_mul() -> None:
173
173
  with pytest.raises(ValueError, match='other than `cirq.LineQubit'):
174
174
  _ = f('III') * cirq.X(cirq.NamedQubit('tmp'))
175
175
 
176
+ # Parity operations.
177
+ assert f('IXYZ') * cirq.XX(*cirq.LineQubit.range(1, 3)) == -1j * f('IIZZ')
178
+ assert cirq.XX(*cirq.LineQubit.range(1, 3)) * f('IXYZ') == 1j * f('IIZZ')
179
+
176
180
  # Mixed types.
177
181
  m = cirq.MutableDensePauliString
178
182
  assert m('X') * m('Z') == -1j * m('Y')
@@ -187,6 +191,10 @@ def test_mul() -> None:
187
191
  assert f('I') * f('III') == f('III')
188
192
  assert f('X') * f('XXX') == f('IXX')
189
193
  assert f('XXX') * f('X') == f('IXX')
194
+ assert f('X') * cirq.Y(cirq.LineQubit(2)) == f('XIY')
195
+ assert f('XY') * cirq.YY(*cirq.LineQubit.range(1, 3)) == f('XIY')
196
+ assert cirq.X(cirq.LineQubit(2)) * f('Y') == f('YIX')
197
+ assert cirq.XX(*cirq.LineQubit.range(1, 3)) * f('YX') == f('YIX')
190
198
 
191
199
  with pytest.raises(TypeError):
192
200
  _ = f('I') * object()
@@ -235,8 +243,15 @@ def test_imul() -> None:
235
243
  p *= cirq.X(cirq.LineQubit(1))
236
244
  assert p == m('IZI')
237
245
 
246
+ p *= cirq.ZZ(*cirq.LineQubit.range(1, 3))
247
+ assert p == m('IIZ')
248
+
238
249
  with pytest.raises(ValueError, match='smaller than'):
239
250
  p *= f('XXXXXXXXXXXX')
251
+ with pytest.raises(ValueError, match='smaller than'):
252
+ p *= cirq.X(cirq.LineQubit(3))
253
+ with pytest.raises(ValueError, match='smaller than'):
254
+ p *= cirq.XX(*cirq.LineQubit.range(2, 4))
240
255
  with pytest.raises(TypeError):
241
256
  p *= object()
242
257
 
@@ -507,6 +522,12 @@ def test_commutes() -> None:
507
522
  assert cirq.commutes(f('IIIXII'), cirq.X(cirq.LineQubit(2)))
508
523
  assert not cirq.commutes(f('IIIXII'), cirq.Z(cirq.LineQubit(3)))
509
524
  assert cirq.commutes(f('IIIXII'), cirq.Z(cirq.LineQubit(2)))
525
+ assert cirq.commutes(f('IIIXII'), cirq.X(cirq.LineQubit(3)) ** 3)
526
+ assert cirq.commutes(f('IIIXII'), cirq.X(cirq.LineQubit(2)) ** 3)
527
+ assert not cirq.commutes(f('IIIXII'), cirq.Z(cirq.LineQubit(3)) ** 3)
528
+ assert cirq.commutes(f('IIIXII'), cirq.Z(cirq.LineQubit(2)) ** 3)
529
+ assert cirq.commutes(f('X'), cirq.Z(cirq.LineQubit(10)))
530
+ assert cirq.commutes(cirq.Z(cirq.LineQubit(10)), f('X'))
510
531
 
511
532
  assert cirq.commutes(f('XX'), "test", default=NotImplemented) is NotImplemented
512
533
 
cirq/ops/diagonal_gate.py CHANGED
@@ -20,7 +20,8 @@ passed as a list.
20
20
 
21
21
  from __future__ import annotations
22
22
 
23
- from typing import AbstractSet, Any, Iterator, Sequence, TYPE_CHECKING
23
+ from collections.abc import Iterator, Sequence, Set
24
+ from typing import Any, TYPE_CHECKING
24
25
 
25
26
  import numpy as np
26
27
  import sympy
@@ -95,7 +96,7 @@ class DiagonalGate(raw_types.Gate):
95
96
  def _is_parameterized_(self) -> bool:
96
97
  return any(protocols.is_parameterized(angle) for angle in self._diag_angles_radians)
97
98
 
98
- def _parameter_names_(self) -> AbstractSet[str]:
99
+ def _parameter_names_(self) -> Set[str]:
99
100
  return {
100
101
  name for angle in self._diag_angles_radians for name in protocols.parameter_names(angle)
101
102
  }
cirq/ops/eigen_gate.py CHANGED
@@ -18,8 +18,9 @@ import abc
18
18
  import fractions
19
19
  import math
20
20
  import numbers
21
+ from collections.abc import Iterable, Set
21
22
  from types import NotImplementedType
22
- from typing import AbstractSet, Any, cast, Iterable, NamedTuple, TYPE_CHECKING
23
+ from typing import Any, cast, NamedTuple, TYPE_CHECKING
23
24
 
24
25
  import numpy as np
25
26
  import sympy
@@ -341,16 +342,17 @@ class EigenGate(raw_types.Gate):
341
342
  def _is_parameterized_(self) -> bool:
342
343
  return protocols.is_parameterized(self._exponent)
343
344
 
344
- def _parameter_names_(self) -> AbstractSet[str]:
345
+ def _parameter_names_(self) -> Set[str]:
345
346
  return protocols.parameter_names(self._exponent)
346
347
 
347
348
  def _resolve_parameters_(self, resolver: cirq.ParamResolver, recursive: bool) -> EigenGate:
348
349
  exponent = resolver.value_of(self._exponent, recursive)
349
- if isinstance(exponent, numbers.Complex):
350
- if isinstance(exponent, numbers.Real):
351
- exponent = float(exponent)
352
- else:
353
- raise ValueError(f'Complex exponent {exponent} not supported for EigenGate')
350
+ # Note that int/float checking is purposely done first,
351
+ # since numbers instance checking is somewhat slow.
352
+ if isinstance(exponent, (int, float)) or isinstance(exponent, numbers.Real): # noqa: SIM101
353
+ exponent = float(exponent)
354
+ elif isinstance(exponent, numbers.Complex):
355
+ raise ValueError(f'Complex exponent {exponent} not supported for EigenGate')
354
356
  return self._with_exponent(exponent=exponent)
355
357
 
356
358
  def _equal_up_to_global_phase_(self, other, atol):
@@ -14,7 +14,8 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- from typing import AbstractSet, Any
17
+ from collections.abc import Set
18
+ from typing import Any
18
19
 
19
20
  import numpy as np
20
21
  import sympy
@@ -163,7 +164,7 @@ class PhaseGradientGate(raw_types.Gate):
163
164
  def _is_parameterized_(self) -> bool:
164
165
  return cirq.is_parameterized(self.exponent)
165
166
 
166
- def _parameter_names_(self) -> AbstractSet[str]:
167
+ def _parameter_names_(self) -> Set[str]:
167
168
  return cirq.parameter_names(self.exponent)
168
169
 
169
170
  def _resolve_parameters_(
@@ -107,9 +107,7 @@ def test_qft() -> None:
107
107
 
108
108
  arr = np.array([[1, 1, 1, 1], [1, -1j, -1, 1j], [1, -1, 1, -1], [1, 1j, -1, -1j]]) / 2
109
109
  np.testing.assert_allclose(
110
- cirq.unitary(cirq.qft(*cirq.LineQubit.range(2)) ** -1), # type: ignore[operator]
111
- arr, # type: ignore[arg-type]
112
- atol=1e-8,
110
+ cirq.unitary(cirq.qft(*cirq.LineQubit.range(2)) ** -1), arr, atol=1e-8
113
111
  )
114
112
 
115
113
  for k in range(4):
@@ -121,7 +119,7 @@ def test_qft() -> None:
121
119
 
122
120
  def test_inverse() -> None:
123
121
  a, b, c = cirq.LineQubit.range(3)
124
- assert cirq.qft(a, b, c, inverse=True) == cirq.qft(a, b, c) ** -1 # type: ignore[operator]
122
+ assert cirq.qft(a, b, c, inverse=True) == cirq.qft(a, b, c) ** -1
125
123
  assert cirq.qft(a, b, c, inverse=True, without_reverse=True) == cirq.inverse(
126
124
  cirq.qft(a, b, c, without_reverse=True)
127
125
  )
cirq/ops/fsim_gate.py CHANGED
@@ -26,7 +26,8 @@ from __future__ import annotations
26
26
 
27
27
  import cmath
28
28
  import math
29
- from typing import AbstractSet, Any, Iterator
29
+ from collections.abc import Iterator, Set
30
+ from typing import Any
30
31
 
31
32
  import numpy as np
32
33
  import sympy
@@ -125,7 +126,7 @@ class FSimGate(gate_features.InterchangeableQubitsGate, raw_types.Gate):
125
126
  def _is_parameterized_(self) -> bool:
126
127
  return cirq.is_parameterized(self.theta) or cirq.is_parameterized(self.phi)
127
128
 
128
- def _parameter_names_(self) -> AbstractSet[str]:
129
+ def _parameter_names_(self) -> Set[str]:
129
130
  return cirq.parameter_names(self.theta) | cirq.parameter_names(self.phi)
130
131
 
131
132
  def _has_unitary_(self):
@@ -16,20 +16,12 @@
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
+ import numbers
19
20
  import re
20
21
  import warnings
22
+ from collections.abc import Collection, Mapping, Sequence, Set
21
23
  from types import NotImplementedType
22
- from typing import (
23
- AbstractSet,
24
- Any,
25
- cast,
26
- Collection,
27
- Mapping,
28
- Self,
29
- Sequence,
30
- TYPE_CHECKING,
31
- TypeVar,
32
- )
24
+ from typing import Any, cast, Self, TYPE_CHECKING, TypeVar
33
25
 
34
26
  from cirq import ops, protocols, value
35
27
  from cirq.ops import control_values as cv, gate_features, raw_types
@@ -269,7 +261,7 @@ class GateOperation(raw_types.Operation):
269
261
  return getter()
270
262
  return NotImplemented
271
263
 
272
- def _parameter_names_(self) -> AbstractSet[str]:
264
+ def _parameter_names_(self) -> Set[str]:
273
265
  getter = getattr(self.gate, '_parameter_names_', None)
274
266
  if getter is not None:
275
267
  return getter()
@@ -331,6 +323,25 @@ class GateOperation(raw_types.Operation):
331
323
  def __rmul__(self, other: Any) -> Any:
332
324
  return self.gate._rmul_with_qubits(self._qubits, other)
333
325
 
326
+ def __add__(self, other):
327
+ if not isinstance(other, (ops.Operation, numbers.Number)):
328
+ return NotImplemented
329
+ return 1 * self + other
330
+
331
+ def __radd__(self, other):
332
+ return other + 1 * self
333
+
334
+ def __sub__(self, other):
335
+ if not isinstance(other, (ops.Operation, numbers.Number)):
336
+ return NotImplemented
337
+ return 1 * self - other
338
+
339
+ def __rsub__(self, other):
340
+ return other + -self
341
+
342
+ def __neg__(self):
343
+ return -1 * self
344
+
334
345
  def _qasm_(self, args: protocols.QasmArgs) -> str | None:
335
346
  if isinstance(self.gate, ops.GlobalPhaseGate):
336
347
  warnings.warn(
cirq/ops/gateset.py CHANGED
@@ -16,7 +16,8 @@
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
- from typing import Any, Callable, cast, Hashable, Iterable, TYPE_CHECKING
19
+ from collections.abc import Callable, Hashable, Iterable
20
+ from typing import Any, cast, TYPE_CHECKING
20
21
 
21
22
  from cirq import protocols, value
22
23
  from cirq.ops import global_phase_op, op_tree, raw_types
@@ -340,6 +341,7 @@ class Gateset:
340
341
  self._unroll_circuit_op = unroll_circuit_op
341
342
  self._instance_gate_families: dict[raw_types.Gate, GateFamily] = {}
342
343
  self._type_gate_families: dict[type[raw_types.Gate], GateFamily] = {}
344
+ self._gate_families_with_tags: list[GateFamily] = []
343
345
  self._gates_repr_str = ", ".join([_gate_str(g, repr) for g in gates])
344
346
  unique_gate_list: list[GateFamily] = list(
345
347
  dict.fromkeys(g if isinstance(g, GateFamily) else GateFamily(gate=g) for g in gates)
@@ -351,6 +353,12 @@ class Gateset:
351
353
  self._instance_gate_families[g.gate] = g
352
354
  else:
353
355
  self._type_gate_families[g.gate] = g
356
+ else:
357
+ if isinstance(g.gate, raw_types.Gate):
358
+ self._gate_families_with_tags.append(g)
359
+ else:
360
+ # Instance checks are faster, so test them first.
361
+ self._gate_families_with_tags.insert(0, g)
354
362
  self._unique_gate_list = unique_gate_list
355
363
  self._gates = frozenset(unique_gate_list)
356
364
 
@@ -422,6 +430,7 @@ class Gateset:
422
430
  g = item if isinstance(item, raw_types.Gate) else item.gate
423
431
  assert g is not None, f'`item`: {item} must be a gate or have a valid `item.gate`'
424
432
 
433
+ # Check "type" based GateFamily since isinstance is fast
425
434
  for gate_mro_type in type(g).mro():
426
435
  if gate_mro_type in self._type_gate_families:
427
436
  assert item in self._type_gate_families[gate_mro_type], (
@@ -430,6 +439,7 @@ class Gateset:
430
439
  )
431
440
  return True
432
441
 
442
+ # Check exact instance equality next
433
443
  if g in self._instance_gate_families:
434
444
  assert item in self._instance_gate_families[g], (
435
445
  f"{item} instance matches {self._instance_gate_families[g]} but "
@@ -437,7 +447,17 @@ class Gateset:
437
447
  )
438
448
  return True
439
449
 
440
- return any(item in gate_family for gate_family in self._gates)
450
+ # Check other GateFamilies next
451
+ if any(item in gate_family for gate_family in self._gate_families_with_tags):
452
+ return True
453
+
454
+ # Lastly, do a final exhaustive check to make sure this is not equivalent
455
+ # to another type of gate. This will catch things like:
456
+ # cirq.XPowGate(exponent=0) in cirq.GateFamily(cirq.I)
457
+ return any(
458
+ item in gate_family
459
+ for gate_family in self._gates.difference(self._gate_families_with_tags)
460
+ )
441
461
 
442
462
  def validate(self, circuit_or_optree: cirq.AbstractCircuit | op_tree.OP_TREE) -> bool:
443
463
  """Validates gates forming `circuit_or_optree` should be contained in Gateset.
@@ -15,8 +15,9 @@
15
15
 
16
16
  from __future__ import annotations
17
17
 
18
+ from collections.abc import Collection, Sequence, Set
18
19
  from types import NotImplementedType
19
- from typing import AbstractSet, Any, cast, Collection, Sequence
20
+ from typing import Any, cast
20
21
 
21
22
  import numpy as np
22
23
  import sympy
@@ -83,7 +84,7 @@ class GlobalPhaseGate(raw_types.Gate):
83
84
  def _is_parameterized_(self) -> bool:
84
85
  return protocols.is_parameterized(self.coefficient)
85
86
 
86
- def _parameter_names_(self) -> AbstractSet[str]:
87
+ def _parameter_names_(self) -> Set[str]:
87
88
  return protocols.parameter_names(self.coefficient)
88
89
 
89
90
  def _resolve_parameters_(
@@ -14,7 +14,8 @@
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
- from typing import Iterable, TYPE_CHECKING
17
+ from collections.abc import Iterable
18
+ from typing import TYPE_CHECKING
18
19
 
19
20
  from cirq.ops import named_qubit, qid_util, qubit_manager
20
21
 
cirq/ops/identity.py CHANGED
@@ -16,8 +16,9 @@
16
16
  from __future__ import annotations
17
17
 
18
18
  import numbers
19
+ from collections.abc import Sequence
19
20
  from types import NotImplementedType
20
- from typing import Any, Sequence, TYPE_CHECKING
21
+ from typing import Any, TYPE_CHECKING
21
22
 
22
23
  import numpy as np
23
24
  import sympy
cirq/ops/kraus_channel.py CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any, Iterable, Mapping, TYPE_CHECKING
5
+ from collections.abc import Iterable, Mapping
6
+ from typing import Any, TYPE_CHECKING
6
7
 
7
8
  import numpy as np
8
9
 
@@ -16,7 +16,8 @@ from __future__ import annotations
16
16
 
17
17
  import numbers
18
18
  from collections import defaultdict
19
- from typing import AbstractSet, Any, Iterable, Mapping, TYPE_CHECKING, Union
19
+ from collections.abc import Iterable, Mapping, Set
20
+ from typing import Any, TYPE_CHECKING, Union
20
21
 
21
22
  import numpy as np
22
23
  import sympy
@@ -136,7 +137,7 @@ class LinearCombinationOfGates(value.LinearDict[raw_types.Gate]):
136
137
  def _is_parameterized_(self) -> bool:
137
138
  return any(protocols.is_parameterized(item) for item in self.items())
138
139
 
139
- def _parameter_names_(self) -> AbstractSet[str]:
140
+ def _parameter_names_(self) -> Set[str]:
140
141
  return {name for item in self.items() for name in protocols.parameter_names(item)}
141
142
 
142
143
  def _resolve_parameters_(
@@ -253,7 +254,7 @@ class LinearCombinationOfOperations(value.LinearDict[raw_types.Operation]):
253
254
  def _is_parameterized_(self) -> bool:
254
255
  return any(protocols.is_parameterized(item) for item in self.items())
255
256
 
256
- def _parameter_names_(self) -> AbstractSet[str]:
257
+ def _parameter_names_(self) -> Set[str]:
257
258
  return {name for item in self.items() for name in protocols.parameter_names(item)}
258
259
 
259
260
  def _resolve_parameters_(
@@ -742,14 +743,12 @@ class PauliSum:
742
743
  return len(self._linear_dict)
743
744
 
744
745
  def __iadd__(self, other):
746
+ if isinstance(other, raw_types.Operation):
747
+ other = pauli_string._try_interpret_as_pauli_string(other)
745
748
  if isinstance(other, numbers.Complex):
746
749
  other = PauliSum.from_pauli_strings([PauliString(coefficient=other)])
747
750
  elif isinstance(other, PauliString):
748
751
  other = PauliSum.from_pauli_strings([other])
749
- elif isinstance(other, raw_types.Operation) and isinstance(
750
- other.gate, identity.IdentityGate
751
- ):
752
- other = PauliSum.from_pauli_strings([PauliString()])
753
752
 
754
753
  if not isinstance(other, PauliSum):
755
754
  return NotImplemented
@@ -758,10 +757,9 @@ class PauliSum:
758
757
  return self
759
758
 
760
759
  def __add__(self, other):
761
- if not isinstance(other, (numbers.Complex, PauliString, PauliSum, raw_types.Operation)):
762
- return NotImplemented
763
760
  result = self.copy()
764
- result += other
761
+ if result.__iadd__(other) is NotImplemented:
762
+ return NotImplemented
765
763
  return result
766
764
 
767
765
  def __radd__(self, other):
@@ -771,14 +769,12 @@ class PauliSum:
771
769
  return -self.__sub__(other)
772
770
 
773
771
  def __isub__(self, other):
772
+ if isinstance(other, raw_types.Operation):
773
+ other = pauli_string._try_interpret_as_pauli_string(other)
774
774
  if isinstance(other, numbers.Complex):
775
775
  other = PauliSum.from_pauli_strings([PauliString(coefficient=other)])
776
776
  elif isinstance(other, PauliString):
777
777
  other = PauliSum.from_pauli_strings([other])
778
- elif isinstance(other, raw_types.Operation) and isinstance(
779
- other.gate, identity.IdentityGate
780
- ):
781
- other = PauliSum.from_pauli_strings([PauliString()])
782
778
 
783
779
  if not isinstance(other, PauliSum):
784
780
  return NotImplemented
@@ -787,10 +783,9 @@ class PauliSum:
787
783
  return self
788
784
 
789
785
  def __sub__(self, other):
790
- if not isinstance(other, (numbers.Complex, PauliString, PauliSum, raw_types.Operation)):
791
- return NotImplemented
792
786
  result = self.copy()
793
- result -= other
787
+ if result.__isub__(other) is NotImplemented:
788
+ return NotImplemented
794
789
  return result
795
790
 
796
791
  def __neg__(self):