cirq-core 1.4.0.dev20240529225110__py3-none-any.whl → 1.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cirq-core might be problematic. Click here for more details.

Files changed (590) hide show
  1. cirq/__init__.py +587 -569
  2. cirq/_compat.py +9 -0
  3. cirq/_compat_test.py +11 -9
  4. cirq/_import.py +7 -8
  5. cirq/_version.py +31 -1
  6. cirq/_version_test.py +1 -1
  7. cirq/circuits/__init__.py +15 -9
  8. cirq/circuits/_block_diagram_drawer.py +1 -2
  9. cirq/circuits/_block_diagram_drawer_test.py +3 -3
  10. cirq/circuits/_box_drawing_character_data.py +0 -1
  11. cirq/circuits/_box_drawing_character_data_test.py +2 -2
  12. cirq/circuits/_bucket_priority_queue.py +0 -1
  13. cirq/circuits/_bucket_priority_queue_test.py +1 -1
  14. cirq/circuits/circuit.py +336 -234
  15. cirq/circuits/circuit_operation.py +102 -52
  16. cirq/circuits/circuit_operation_test.py +85 -4
  17. cirq/circuits/circuit_test.py +101 -32
  18. cirq/circuits/frozen_circuit.py +36 -32
  19. cirq/circuits/insert_strategy.py +10 -0
  20. cirq/circuits/insert_strategy_test.py +20 -0
  21. cirq/circuits/moment.py +79 -80
  22. cirq/circuits/moment_test.py +105 -2
  23. cirq/circuits/optimization_pass.py +15 -15
  24. cirq/circuits/optimization_pass_test.py +8 -9
  25. cirq/circuits/qasm_output.py +64 -33
  26. cirq/circuits/qasm_output_test.py +63 -2
  27. cirq/circuits/text_diagram_drawer.py +26 -56
  28. cirq/circuits/text_diagram_drawer_test.py +5 -4
  29. cirq/contrib/__init__.py +2 -2
  30. cirq/contrib/acquaintance/__init__.py +44 -29
  31. cirq/contrib/acquaintance/bipartite.py +8 -7
  32. cirq/contrib/acquaintance/bipartite_test.py +11 -1
  33. cirq/contrib/acquaintance/devices.py +5 -4
  34. cirq/contrib/acquaintance/devices_test.py +5 -1
  35. cirq/contrib/acquaintance/executor.py +18 -21
  36. cirq/contrib/acquaintance/executor_test.py +3 -2
  37. cirq/contrib/acquaintance/gates.py +36 -27
  38. cirq/contrib/acquaintance/gates_test.py +1 -1
  39. cirq/contrib/acquaintance/inspection_utils.py +10 -9
  40. cirq/contrib/acquaintance/inspection_utils_test.py +6 -1
  41. cirq/contrib/acquaintance/mutation_utils.py +10 -10
  42. cirq/contrib/acquaintance/optimizers.py +7 -6
  43. cirq/contrib/acquaintance/optimizers_test.py +1 -1
  44. cirq/contrib/acquaintance/permutation.py +22 -21
  45. cirq/contrib/acquaintance/permutation_test.py +1 -1
  46. cirq/contrib/acquaintance/shift.py +8 -6
  47. cirq/contrib/acquaintance/shift_swap_network.py +6 -4
  48. cirq/contrib/acquaintance/strategies/__init__.py +9 -3
  49. cirq/contrib/acquaintance/strategies/complete.py +4 -3
  50. cirq/contrib/acquaintance/strategies/cubic.py +5 -3
  51. cirq/contrib/acquaintance/strategies/quartic_paired.py +8 -6
  52. cirq/contrib/acquaintance/topological_sort.py +4 -2
  53. cirq/contrib/bayesian_network/__init__.py +3 -1
  54. cirq/contrib/bayesian_network/bayesian_network_gate.py +5 -3
  55. cirq/contrib/circuitdag/__init__.py +1 -1
  56. cirq/contrib/circuitdag/circuit_dag.py +24 -24
  57. cirq/contrib/circuitdag/circuit_dag_test.py +1 -1
  58. cirq/contrib/custom_simulators/custom_state_simulator.py +10 -8
  59. cirq/contrib/custom_simulators/custom_state_simulator_test.py +15 -11
  60. cirq/contrib/graph_device/__init__.py +8 -8
  61. cirq/contrib/graph_device/graph_device.py +8 -8
  62. cirq/contrib/graph_device/graph_device_test.py +0 -1
  63. cirq/contrib/graph_device/hypergraph_test.py +1 -0
  64. cirq/contrib/json.py +1 -2
  65. cirq/contrib/json_test.py +2 -2
  66. cirq/contrib/noise_models/__init__.py +5 -6
  67. cirq/contrib/noise_models/noise_models.py +8 -6
  68. cirq/contrib/paulistring/__init__.py +22 -10
  69. cirq/contrib/paulistring/clifford_optimize.py +1 -1
  70. cirq/contrib/paulistring/clifford_optimize_test.py +0 -1
  71. cirq/contrib/paulistring/clifford_target_gateset.py +15 -12
  72. cirq/contrib/paulistring/optimize.py +2 -2
  73. cirq/contrib/paulistring/optimize_test.py +0 -1
  74. cirq/contrib/paulistring/pauli_string_dag_test.py +0 -1
  75. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +379 -0
  76. cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +523 -0
  77. cirq/contrib/paulistring/pauli_string_optimize.py +3 -1
  78. cirq/contrib/paulistring/pauli_string_optimize_test.py +1 -3
  79. cirq/contrib/paulistring/recombine.py +2 -2
  80. cirq/contrib/paulistring/recombine_test.py +2 -2
  81. cirq/contrib/paulistring/separate.py +3 -4
  82. cirq/contrib/qasm_import/__init__.py +2 -2
  83. cirq/contrib/qasm_import/_lexer.py +21 -26
  84. cirq/contrib/qasm_import/_lexer_test.py +90 -6
  85. cirq/contrib/qasm_import/_parser.py +238 -47
  86. cirq/contrib/qasm_import/_parser_test.py +514 -59
  87. cirq/contrib/qasm_import/qasm_test.py +1 -1
  88. cirq/contrib/qcircuit/__init__.py +6 -4
  89. cirq/contrib/qcircuit/qcircuit_diagram.py +5 -2
  90. cirq/contrib/qcircuit/qcircuit_pdf.py +1 -2
  91. cirq/{experiments/grid_parallel_two_qubit_xeb_test.py → contrib/qcircuit/qcircuit_pdf_test.py} +13 -12
  92. cirq/contrib/qcircuit/qcircuit_test.py +1 -1
  93. cirq/contrib/quantum_volume/__init__.py +7 -7
  94. cirq/contrib/quantum_volume/quantum_volume.py +6 -11
  95. cirq/contrib/quantum_volume/quantum_volume_test.py +3 -1
  96. cirq/contrib/quimb/__init__.py +16 -13
  97. cirq/contrib/quimb/density_matrix.py +1 -1
  98. cirq/contrib/quimb/mps_simulator.py +27 -28
  99. cirq/contrib/quimb/mps_simulator_test.py +5 -0
  100. cirq/contrib/quimb/state_vector.py +3 -10
  101. cirq/contrib/quirk/__init__.py +1 -1
  102. cirq/contrib/quirk/export_to_quirk.py +3 -3
  103. cirq/contrib/routing/__init__.py +12 -9
  104. cirq/contrib/routing/device.py +1 -1
  105. cirq/contrib/routing/device_test.py +1 -2
  106. cirq/contrib/routing/greedy.py +7 -5
  107. cirq/contrib/routing/greedy_test.py +5 -3
  108. cirq/contrib/routing/initialization.py +3 -1
  109. cirq/contrib/routing/initialization_test.py +1 -1
  110. cirq/contrib/routing/swap_network.py +6 -6
  111. cirq/contrib/routing/utils.py +6 -4
  112. cirq/contrib/routing/utils_test.py +1 -2
  113. cirq/{type_workarounds.py → contrib/shuffle_circuits/__init__.py} +5 -10
  114. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +250 -0
  115. cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py +363 -0
  116. cirq/contrib/svg/__init__.py +1 -1
  117. cirq/contrib/svg/svg.py +12 -10
  118. cirq/contrib/svg/svg_test.py +3 -2
  119. cirq/devices/__init__.py +34 -25
  120. cirq/devices/device.py +16 -12
  121. cirq/devices/device_test.py +1 -0
  122. cirq/devices/grid_device_metadata.py +16 -12
  123. cirq/devices/grid_device_metadata_test.py +2 -1
  124. cirq/devices/grid_qubit.py +31 -26
  125. cirq/devices/grid_qubit_test.py +30 -1
  126. cirq/devices/insertion_noise_model.py +6 -6
  127. cirq/devices/insertion_noise_model_test.py +1 -1
  128. cirq/devices/line_qubit.py +28 -20
  129. cirq/devices/line_qubit_test.py +26 -0
  130. cirq/devices/named_topologies.py +12 -10
  131. cirq/devices/named_topologies_test.py +5 -4
  132. cirq/devices/noise_model.py +29 -33
  133. cirq/devices/noise_properties.py +2 -2
  134. cirq/devices/noise_properties_test.py +2 -2
  135. cirq/devices/noise_utils.py +3 -3
  136. cirq/devices/superconducting_qubits_noise_properties.py +2 -2
  137. cirq/devices/superconducting_qubits_noise_properties_test.py +3 -3
  138. cirq/devices/thermal_noise_model.py +2 -1
  139. cirq/devices/unconstrained_device.py +1 -1
  140. cirq/devices/unconstrained_device_test.py +6 -0
  141. cirq/experiments/__init__.py +51 -34
  142. cirq/experiments/qubit_characterizations.py +17 -15
  143. cirq/experiments/qubit_characterizations_test.py +4 -6
  144. cirq/experiments/random_quantum_circuit_generation.py +10 -9
  145. cirq/experiments/random_quantum_circuit_generation_test.py +21 -4
  146. cirq/experiments/readout_confusion_matrix.py +73 -8
  147. cirq/experiments/readout_confusion_matrix_test.py +104 -1
  148. cirq/experiments/single_qubit_readout_calibration.py +8 -6
  149. cirq/experiments/single_qubit_readout_calibration_test.py +1 -1
  150. cirq/experiments/t1_decay_experiment.py +4 -5
  151. cirq/experiments/t1_decay_experiment_test.py +1 -2
  152. cirq/experiments/t2_decay_experiment.py +0 -1
  153. cirq/experiments/t2_decay_experiment_test.py +1 -2
  154. cirq/experiments/two_qubit_xeb.py +157 -33
  155. cirq/experiments/two_qubit_xeb_test.py +38 -22
  156. cirq/experiments/xeb_fitting.py +99 -19
  157. cirq/experiments/xeb_fitting_test.py +64 -25
  158. cirq/experiments/xeb_sampling.py +14 -18
  159. cirq/experiments/xeb_simulation.py +4 -3
  160. cirq/experiments/xeb_simulation_test.py +20 -14
  161. cirq/experiments/z_phase_calibration.py +368 -0
  162. cirq/experiments/z_phase_calibration_test.py +241 -0
  163. cirq/interop/__init__.py +4 -1
  164. cirq/interop/quirk/__init__.py +7 -4
  165. cirq/interop/quirk/cells/__init__.py +17 -6
  166. cirq/interop/quirk/cells/arithmetic_cells.py +8 -8
  167. cirq/interop/quirk/cells/arithmetic_cells_test.py +1 -1
  168. cirq/interop/quirk/cells/cell.py +6 -6
  169. cirq/interop/quirk/cells/composite_cell.py +5 -5
  170. cirq/interop/quirk/cells/composite_cell_test.py +1 -1
  171. cirq/interop/quirk/cells/control_cells.py +1 -1
  172. cirq/interop/quirk/cells/frequency_space_cells.py +2 -2
  173. cirq/interop/quirk/cells/ignored_cells.py +1 -1
  174. cirq/interop/quirk/cells/input_cells.py +1 -1
  175. cirq/interop/quirk/cells/input_cells_test.py +1 -1
  176. cirq/interop/quirk/cells/input_rotation_cells.py +1 -1
  177. cirq/interop/quirk/cells/input_rotation_cells_test.py +1 -1
  178. cirq/interop/quirk/cells/measurement_cells.py +1 -1
  179. cirq/interop/quirk/cells/parse.py +8 -7
  180. cirq/interop/quirk/cells/parse_test.py +2 -2
  181. cirq/interop/quirk/cells/single_qubit_rotation_cells.py +1 -1
  182. cirq/interop/quirk/cells/swap_cell_test.py +1 -1
  183. cirq/interop/quirk/cells/unsupported_cells.py +1 -1
  184. cirq/interop/quirk/url_to_circuit.py +7 -7
  185. cirq/interop/quirk/url_to_circuit_test.py +1 -1
  186. cirq/ion/__init__.py +4 -2
  187. cirq/json_resolver_cache.py +15 -7
  188. cirq/linalg/__init__.py +62 -51
  189. cirq/linalg/combinators.py +4 -4
  190. cirq/linalg/combinators_test.py +4 -1
  191. cirq/linalg/decompositions.py +15 -40
  192. cirq/linalg/decompositions_test.py +16 -22
  193. cirq/linalg/diagonalize.py +1 -1
  194. cirq/linalg/diagonalize_test.py +1 -1
  195. cirq/linalg/operator_spaces.py +20 -4
  196. cirq/linalg/operator_spaces_test.py +15 -2
  197. cirq/linalg/predicates.py +3 -3
  198. cirq/linalg/predicates_test.py +1 -0
  199. cirq/linalg/tolerance.py +2 -2
  200. cirq/linalg/transformations.py +30 -12
  201. cirq/linalg/transformations_test.py +13 -0
  202. cirq/neutral_atoms/__init__.py +2 -2
  203. cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py +0 -1
  204. cirq/ops/__init__.py +172 -132
  205. cirq/ops/arithmetic_operation.py +2 -2
  206. cirq/ops/arithmetic_operation_test.py +2 -2
  207. cirq/ops/boolean_hamiltonian.py +3 -2
  208. cirq/ops/classically_controlled_operation.py +39 -12
  209. cirq/ops/classically_controlled_operation_test.py +147 -1
  210. cirq/ops/clifford_gate.py +38 -36
  211. cirq/ops/clifford_gate_test.py +75 -1
  212. cirq/ops/common_channels.py +16 -45
  213. cirq/ops/common_channels_test.py +10 -0
  214. cirq/ops/common_gate_families.py +1 -1
  215. cirq/ops/common_gate_families_test.py +1 -0
  216. cirq/ops/common_gates.py +48 -49
  217. cirq/ops/common_gates_test.py +18 -2
  218. cirq/ops/control_values.py +3 -3
  219. cirq/ops/control_values_test.py +2 -1
  220. cirq/ops/controlled_gate.py +36 -23
  221. cirq/ops/controlled_gate_test.py +70 -3
  222. cirq/ops/controlled_operation.py +6 -5
  223. cirq/ops/controlled_operation_test.py +7 -3
  224. cirq/ops/dense_pauli_string.py +11 -11
  225. cirq/ops/diagonal_gate.py +2 -2
  226. cirq/ops/diagonal_gate_test.py +1 -0
  227. cirq/ops/eigen_gate.py +16 -36
  228. cirq/ops/eigen_gate_test.py +60 -10
  229. cirq/ops/fourier_transform.py +1 -3
  230. cirq/ops/fourier_transform_test.py +2 -1
  231. cirq/ops/fsim_gate.py +42 -3
  232. cirq/ops/fsim_gate_test.py +21 -0
  233. cirq/ops/gate_operation.py +8 -8
  234. cirq/ops/gate_operation_test.py +4 -2
  235. cirq/ops/gateset_test.py +11 -2
  236. cirq/ops/global_phase_op.py +8 -7
  237. cirq/ops/global_phase_op_test.py +1 -1
  238. cirq/ops/greedy_qubit_manager_test.py +5 -0
  239. cirq/ops/identity.py +14 -4
  240. cirq/ops/identity_test.py +24 -0
  241. cirq/ops/kraus_channel.py +1 -0
  242. cirq/ops/kraus_channel_test.py +3 -1
  243. cirq/ops/linear_combinations.py +27 -21
  244. cirq/ops/linear_combinations_test.py +23 -4
  245. cirq/ops/matrix_gates.py +24 -8
  246. cirq/ops/measure_util.py +2 -2
  247. cirq/ops/measurement_gate.py +7 -4
  248. cirq/ops/measurement_gate_test.py +2 -1
  249. cirq/ops/mixed_unitary_channel.py +1 -0
  250. cirq/ops/mixed_unitary_channel_test.py +3 -1
  251. cirq/ops/named_qubit.py +8 -1
  252. cirq/ops/op_tree.py +3 -30
  253. cirq/ops/op_tree_test.py +4 -0
  254. cirq/ops/parallel_gate.py +2 -3
  255. cirq/ops/parallel_gate_test.py +2 -1
  256. cirq/ops/parity_gates.py +7 -8
  257. cirq/ops/parity_gates_test.py +1 -0
  258. cirq/ops/pauli_gates.py +5 -11
  259. cirq/ops/pauli_gates_test.py +1 -0
  260. cirq/ops/pauli_interaction_gate.py +11 -5
  261. cirq/ops/pauli_interaction_gate_test.py +2 -3
  262. cirq/ops/pauli_measurement_gate.py +6 -5
  263. cirq/ops/pauli_measurement_gate_test.py +1 -0
  264. cirq/ops/pauli_string.py +115 -130
  265. cirq/ops/pauli_string_phasor.py +21 -20
  266. cirq/ops/pauli_string_phasor_test.py +13 -3
  267. cirq/ops/pauli_string_raw_types.py +1 -0
  268. cirq/ops/pauli_string_test.py +192 -55
  269. cirq/ops/pauli_sum_exponential.py +3 -4
  270. cirq/ops/pauli_sum_exponential_test.py +0 -1
  271. cirq/ops/permutation_gate.py +2 -2
  272. cirq/ops/permutation_gate_test.py +1 -1
  273. cirq/ops/phased_iswap_gate.py +6 -7
  274. cirq/ops/phased_iswap_gate_test.py +21 -5
  275. cirq/ops/phased_x_gate.py +11 -25
  276. cirq/ops/phased_x_gate_test.py +19 -3
  277. cirq/ops/phased_x_z_gate.py +12 -11
  278. cirq/ops/projector.py +4 -5
  279. cirq/ops/qubit_manager.py +2 -1
  280. cirq/ops/qubit_manager_test.py +2 -1
  281. cirq/ops/qubit_order.py +1 -1
  282. cirq/ops/random_gate_channel.py +1 -1
  283. cirq/ops/random_gate_channel_test.py +0 -6
  284. cirq/ops/raw_types.py +146 -50
  285. cirq/ops/raw_types_test.py +37 -3
  286. cirq/ops/state_preparation_channel.py +2 -2
  287. cirq/ops/state_preparation_channel_test.py +2 -1
  288. cirq/ops/swap_gates.py +9 -4
  289. cirq/ops/three_qubit_gates.py +8 -8
  290. cirq/ops/three_qubit_gates_test.py +1 -0
  291. cirq/ops/two_qubit_diagonal_gate.py +4 -3
  292. cirq/ops/uniform_superposition_gate.py +4 -4
  293. cirq/ops/uniform_superposition_gate_test.py +1 -0
  294. cirq/ops/wait_gate.py +6 -8
  295. cirq/protocols/__init__.py +135 -83
  296. cirq/protocols/act_on_protocol.py +1 -1
  297. cirq/protocols/act_on_protocol_test.py +1 -1
  298. cirq/protocols/apply_channel_protocol.py +3 -3
  299. cirq/protocols/apply_mixture_protocol.py +15 -9
  300. cirq/protocols/apply_mixture_protocol_test.py +11 -0
  301. cirq/protocols/apply_unitary_protocol.py +2 -2
  302. cirq/protocols/apply_unitary_protocol_test.py +2 -1
  303. cirq/protocols/approximate_equality_protocol.py +7 -8
  304. cirq/protocols/approximate_equality_protocol_test.py +3 -1
  305. cirq/protocols/circuit_diagram_info_protocol.py +8 -6
  306. cirq/protocols/circuit_diagram_info_protocol_test.py +5 -0
  307. cirq/protocols/commutes_protocol.py +6 -6
  308. cirq/protocols/control_key_protocol.py +1 -1
  309. cirq/protocols/decompose_protocol.py +4 -5
  310. cirq/protocols/decompose_protocol_test.py +2 -1
  311. cirq/protocols/equal_up_to_global_phase_protocol.py +3 -3
  312. cirq/protocols/equal_up_to_global_phase_protocol_test.py +7 -0
  313. cirq/protocols/has_stabilizer_effect_protocol.py +5 -5
  314. cirq/protocols/has_unitary_protocol.py +1 -1
  315. cirq/protocols/has_unitary_protocol_test.py +8 -7
  316. cirq/protocols/hash_from_pickle_test.py +120 -0
  317. cirq/protocols/inverse_protocol.py +1 -1
  318. cirq/protocols/json_serialization.py +14 -1
  319. cirq/protocols/json_serialization_test.py +28 -7
  320. cirq/protocols/json_test_data/BitMaskKeyCondition.json +86 -0
  321. cirq/protocols/json_test_data/BitMaskKeyCondition.repr +7 -0
  322. cirq/protocols/json_test_data/Concat.json +19 -0
  323. cirq/protocols/json_test_data/Concat.repr +1 -0
  324. cirq/protocols/json_test_data/README.md +4 -2
  325. cirq/protocols/json_test_data/SympyCondition.json +60 -15
  326. cirq/protocols/json_test_data/SympyCondition.repr +4 -1
  327. cirq/protocols/json_test_data/_InverseCompositeGate.json +10 -0
  328. cirq/protocols/json_test_data/_InverseCompositeGate.repr +1 -0
  329. cirq/protocols/json_test_data/__init__.py +1 -1
  330. cirq/protocols/json_test_data/sympy.And.json +13 -0
  331. cirq/protocols/json_test_data/sympy.And.repr +1 -0
  332. cirq/protocols/json_test_data/sympy.Indexed.json +18 -0
  333. cirq/protocols/json_test_data/sympy.Indexed.repr +1 -0
  334. cirq/protocols/json_test_data/sympy.IndexedBase.json +9 -0
  335. cirq/protocols/json_test_data/sympy.IndexedBase.repr +1 -0
  336. cirq/protocols/json_test_data/sympy.Not.json +9 -0
  337. cirq/protocols/json_test_data/sympy.Not.repr +1 -0
  338. cirq/protocols/json_test_data/sympy.Or.json +13 -0
  339. cirq/protocols/json_test_data/sympy.Or.repr +1 -0
  340. cirq/protocols/json_test_data/sympy.Xor.json +13 -0
  341. cirq/protocols/json_test_data/sympy.Xor.repr +1 -0
  342. cirq/protocols/kraus_protocol.py +8 -8
  343. cirq/protocols/kraus_protocol_test.py +0 -1
  344. cirq/protocols/measurement_key_protocol.py +1 -1
  345. cirq/protocols/measurement_key_protocol_test.py +7 -7
  346. cirq/protocols/mixture_protocol.py +6 -4
  347. cirq/protocols/mixture_protocol_test.py +21 -13
  348. cirq/protocols/pauli_expansion_protocol.py +1 -0
  349. cirq/protocols/pow_protocol.py +1 -1
  350. cirq/protocols/qasm.py +25 -6
  351. cirq/protocols/qasm_test.py +17 -0
  352. cirq/protocols/qid_shape_protocol.py +2 -2
  353. cirq/protocols/resolve_parameters.py +2 -3
  354. cirq/protocols/resolve_parameters_test.py +2 -1
  355. cirq/protocols/trace_distance_bound.py +1 -1
  356. cirq/protocols/trace_distance_bound_test.py +1 -0
  357. cirq/protocols/unitary_protocol.py +3 -3
  358. cirq/protocols/unitary_protocol_test.py +1 -1
  359. cirq/qis/__init__.py +48 -35
  360. cirq/qis/channels_test.py +0 -9
  361. cirq/qis/clifford_tableau.py +46 -26
  362. cirq/qis/clifford_tableau_test.py +2 -1
  363. cirq/qis/entropy.py +115 -0
  364. cirq/qis/entropy_test.py +43 -0
  365. cirq/qis/measures.py +5 -4
  366. cirq/qis/measures_test.py +7 -0
  367. cirq/qis/noise_utils_test.py +4 -4
  368. cirq/qis/quantum_state_representation.py +1 -1
  369. cirq/qis/states.py +7 -7
  370. cirq/sim/__init__.py +55 -37
  371. cirq/sim/classical_simulator.py +7 -6
  372. cirq/sim/classical_simulator_test.py +3 -1
  373. cirq/sim/clifford/__init__.py +17 -9
  374. cirq/sim/clifford/clifford_simulator.py +5 -4
  375. cirq/sim/clifford/clifford_simulator_test.py +32 -9
  376. cirq/sim/clifford/clifford_tableau_simulation_state.py +1 -1
  377. cirq/sim/clifford/stabilizer_simulation_state.py +1 -1
  378. cirq/sim/clifford/stabilizer_state_ch_form.py +4 -3
  379. cirq/sim/density_matrix_simulator.py +3 -2
  380. cirq/sim/density_matrix_simulator_test.py +12 -4
  381. cirq/sim/density_matrix_utils.py +1 -1
  382. cirq/sim/mux.py +2 -2
  383. cirq/sim/simulation_state.py +4 -5
  384. cirq/sim/simulation_state_base.py +2 -2
  385. cirq/sim/simulation_state_test.py +1 -1
  386. cirq/sim/simulation_utils.py +3 -1
  387. cirq/sim/simulation_utils_test.py +2 -3
  388. cirq/sim/simulator.py +7 -6
  389. cirq/sim/simulator_base.py +5 -5
  390. cirq/sim/simulator_test.py +14 -3
  391. cirq/sim/sparse_simulator.py +4 -3
  392. cirq/sim/sparse_simulator_test.py +17 -9
  393. cirq/sim/state_vector.py +2 -2
  394. cirq/sim/state_vector_simulation_state_test.py +1 -1
  395. cirq/sim/state_vector_simulator.py +4 -4
  396. cirq/sim/state_vector_test.py +27 -32
  397. cirq/study/__init__.py +27 -21
  398. cirq/study/flatten_expressions.py +5 -6
  399. cirq/study/flatten_expressions_test.py +1 -1
  400. cirq/study/resolver.py +14 -11
  401. cirq/study/resolver_test.py +10 -1
  402. cirq/study/result.py +3 -3
  403. cirq/study/sweepable.py +15 -9
  404. cirq/study/sweepable_test.py +27 -0
  405. cirq/study/sweeps.py +65 -10
  406. cirq/study/sweeps_test.py +123 -0
  407. cirq/testing/__init__.py +86 -57
  408. cirq/testing/_compat_test_data/module_a/__init__.py +2 -2
  409. cirq/testing/_compat_test_data/module_a/sub/subsub/__init__.py +1 -1
  410. cirq/testing/circuit_compare.py +3 -4
  411. cirq/testing/circuit_compare_test.py +7 -8
  412. cirq/testing/consistent_act_on.py +3 -3
  413. cirq/testing/consistent_channels_test.py +2 -1
  414. cirq/testing/consistent_controlled_gate_op.py +3 -2
  415. cirq/testing/consistent_controlled_gate_op_test.py +2 -3
  416. cirq/testing/consistent_decomposition.py +1 -1
  417. cirq/testing/consistent_decomposition_test.py +1 -2
  418. cirq/testing/consistent_pauli_expansion_test.py +1 -1
  419. cirq/testing/consistent_phase_by.py +1 -1
  420. cirq/testing/consistent_phase_by_test.py +1 -2
  421. cirq/testing/consistent_protocols.py +11 -11
  422. cirq/testing/consistent_protocols_test.py +4 -5
  423. cirq/testing/consistent_qasm.py +8 -12
  424. cirq/testing/consistent_qasm_test.py +1 -1
  425. cirq/testing/consistent_resolve_parameters.py +2 -1
  426. cirq/testing/consistent_specified_has_unitary_test.py +1 -1
  427. cirq/testing/consistent_unitary.py +3 -1
  428. cirq/testing/consistent_unitary_test.py +3 -3
  429. cirq/testing/devices.py +1 -1
  430. cirq/testing/devices_test.py +1 -0
  431. cirq/testing/equals_tester.py +2 -4
  432. cirq/testing/equals_tester_test.py +6 -5
  433. cirq/testing/equivalent_basis_map.py +1 -0
  434. cirq/testing/equivalent_basis_map_test.py +0 -1
  435. cirq/testing/gate_features_test.py +5 -0
  436. cirq/testing/json.py +4 -4
  437. cirq/testing/lin_alg_utils_test.py +1 -1
  438. cirq/testing/order_tester.py +1 -1
  439. cirq/testing/order_tester_test.py +1 -1
  440. cirq/testing/pytest_utils.py +57 -0
  441. cirq/testing/pytest_utils_test.py +35 -0
  442. cirq/testing/random_circuit.py +2 -2
  443. cirq/testing/random_circuit_test.py +2 -2
  444. cirq/testing/routing_devices_test.py +2 -1
  445. cirq/testing/sample_circuits.py +1 -1
  446. cirq/testing/sample_gates.py +5 -4
  447. cirq/testing/sample_gates_test.py +2 -2
  448. cirq/transformers/__init__.py +101 -82
  449. cirq/transformers/align.py +12 -1
  450. cirq/transformers/align_test.py +13 -0
  451. cirq/transformers/analytical_decompositions/__init__.py +27 -24
  452. cirq/transformers/analytical_decompositions/clifford_decomposition.py +2 -1
  453. cirq/transformers/analytical_decompositions/clifford_decomposition_test.py +1 -1
  454. cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +1 -1
  455. cirq/transformers/analytical_decompositions/controlled_gate_decomposition_test.py +2 -0
  456. cirq/transformers/analytical_decompositions/cphase_to_fsim.py +1 -1
  457. cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +1 -1
  458. cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +2 -2
  459. cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +4 -4
  460. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +99 -24
  461. cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +105 -14
  462. cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +1 -1
  463. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry.py +1 -1
  464. cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry_test.py +1 -0
  465. cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +3 -4
  466. cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +1 -1
  467. cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +2 -1
  468. cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +2 -1
  469. cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +5 -6
  470. cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +2 -2
  471. cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +1 -1
  472. cirq/transformers/analytical_decompositions/two_qubit_to_fsim_test.py +1 -2
  473. cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +2 -2
  474. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +2 -2
  475. cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap_test.py +2 -1
  476. cirq/transformers/drop_empty_moments.py +1 -0
  477. cirq/transformers/drop_negligible_operations.py +1 -0
  478. cirq/transformers/dynamical_decoupling.py +255 -43
  479. cirq/transformers/dynamical_decoupling_test.py +730 -17
  480. cirq/transformers/eject_phased_paulis.py +29 -15
  481. cirq/transformers/eject_phased_paulis_test.py +3 -8
  482. cirq/transformers/eject_z.py +3 -2
  483. cirq/transformers/eject_z_test.py +3 -3
  484. cirq/transformers/gauge_compiling/__init__.py +25 -9
  485. cirq/transformers/gauge_compiling/cphase_gauge.py +146 -0
  486. cirq/transformers/gauge_compiling/cphase_gauge_test.py +42 -0
  487. cirq/transformers/gauge_compiling/cz_gauge.py +4 -4
  488. cirq/transformers/gauge_compiling/gauge_compiling.py +245 -6
  489. cirq/transformers/gauge_compiling/gauge_compiling_test.py +107 -2
  490. cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +39 -2
  491. cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +10 -1
  492. cirq/transformers/gauge_compiling/iswap_gauge.py +2 -2
  493. cirq/transformers/gauge_compiling/spin_inversion_gauge.py +2 -2
  494. cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +23 -5
  495. cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +3 -2
  496. cirq/transformers/heuristic_decompositions/__init__.py +3 -3
  497. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +2 -1
  498. cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils_test.py +1 -1
  499. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +4 -4
  500. cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation_test.py +4 -4
  501. cirq/transformers/insertion_sort.py +64 -0
  502. cirq/transformers/insertion_sort_test.py +34 -0
  503. cirq/transformers/measurement_transformers.py +14 -1
  504. cirq/transformers/measurement_transformers_test.py +35 -0
  505. cirq/transformers/merge_k_qubit_gates.py +2 -2
  506. cirq/transformers/merge_single_qubit_gates.py +1 -1
  507. cirq/transformers/merge_single_qubit_gates_test.py +1 -1
  508. cirq/transformers/noise_adding.py +115 -0
  509. cirq/transformers/noise_adding_test.py +54 -0
  510. cirq/transformers/optimize_for_target_gateset.py +1 -1
  511. cirq/transformers/optimize_for_target_gateset_test.py +3 -2
  512. cirq/transformers/qubit_management_transformers.py +1 -1
  513. cirq/transformers/randomized_measurements.py +171 -0
  514. cirq/transformers/randomized_measurements_test.py +68 -0
  515. cirq/transformers/routing/__init__.py +14 -5
  516. cirq/transformers/routing/initial_mapper.py +1 -1
  517. cirq/transformers/routing/initial_mapper_test.py +1 -0
  518. cirq/transformers/routing/line_initial_mapper.py +3 -2
  519. cirq/transformers/routing/mapping_manager.py +2 -2
  520. cirq/transformers/routing/mapping_manager_test.py +2 -2
  521. cirq/transformers/routing/route_circuit_cqc.py +3 -2
  522. cirq/transformers/routing/route_circuit_cqc_test.py +2 -1
  523. cirq/transformers/routing/visualize_routed_circuit.py +1 -0
  524. cirq/transformers/routing/visualize_routed_circuit_test.py +1 -0
  525. cirq/transformers/stratify.py +2 -2
  526. cirq/transformers/synchronize_terminal_measurements.py +2 -1
  527. cirq/transformers/target_gatesets/__init__.py +7 -5
  528. cirq/transformers/target_gatesets/compilation_target_gateset.py +16 -3
  529. cirq/transformers/target_gatesets/compilation_target_gateset_test.py +2 -0
  530. cirq/transformers/target_gatesets/cz_gateset.py +5 -1
  531. cirq/transformers/target_gatesets/cz_gateset_test.py +23 -2
  532. cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +1 -1
  533. cirq/transformers/target_gatesets/sqrt_iswap_gateset_test.py +3 -2
  534. cirq/transformers/transformer_api.py +5 -4
  535. cirq/transformers/transformer_api_test.py +11 -3
  536. cirq/transformers/transformer_primitives.py +9 -31
  537. cirq/transformers/transformer_primitives_test.py +6 -5
  538. cirq/value/__init__.py +51 -30
  539. cirq/value/abc_alt.py +1 -2
  540. cirq/value/angle.py +2 -0
  541. cirq/value/classical_data.py +1 -0
  542. cirq/value/condition.py +149 -3
  543. cirq/value/condition_test.py +254 -0
  544. cirq/value/digits.py +1 -1
  545. cirq/value/duration.py +4 -4
  546. cirq/value/duration_test.py +2 -1
  547. cirq/value/linear_dict.py +85 -24
  548. cirq/value/linear_dict_test.py +94 -3
  549. cirq/value/measurement_key.py +9 -2
  550. cirq/value/periodic_value.py +2 -3
  551. cirq/value/periodic_value_test.py +5 -0
  552. cirq/value/probability.py +1 -0
  553. cirq/value/random_state.py +1 -1
  554. cirq/value/timestamp.py +2 -4
  555. cirq/value/timestamp_test.py +2 -1
  556. cirq/value/type_alias.py +2 -2
  557. cirq/value/value_equality_attr.py +14 -2
  558. cirq/value/value_equality_attr_test.py +1 -1
  559. cirq/vis/__init__.py +9 -6
  560. cirq/vis/density_matrix.py +1 -1
  561. cirq/vis/density_matrix_test.py +2 -5
  562. cirq/vis/heatmap.py +49 -12
  563. cirq/vis/heatmap_test.py +168 -4
  564. cirq/vis/histogram.py +1 -1
  565. cirq/vis/histogram_test.py +1 -2
  566. cirq/vis/state_histogram.py +7 -5
  567. cirq/vis/state_histogram_test.py +2 -2
  568. cirq/work/__init__.py +19 -13
  569. cirq/work/collector.py +2 -2
  570. cirq/work/observable_grouping.py +2 -2
  571. cirq/work/observable_measurement.py +3 -3
  572. cirq/work/observable_measurement_data.py +5 -2
  573. cirq/work/observable_measurement_test.py +8 -8
  574. cirq/work/observable_readout_calibration.py +2 -2
  575. cirq/work/observable_readout_calibration_test.py +2 -1
  576. cirq/work/observable_settings.py +8 -7
  577. cirq/work/observable_settings_test.py +3 -2
  578. cirq/work/pauli_sum_collector.py +1 -1
  579. cirq/work/sampler.py +8 -20
  580. cirq/work/sampler_test.py +4 -3
  581. cirq/work/zeros_sampler.py +1 -1
  582. cirq_core-1.5.0.dist-info/METADATA +125 -0
  583. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/RECORD +586 -552
  584. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/WHEEL +1 -1
  585. cirq/experiments/grid_parallel_two_qubit_xeb.py +0 -62
  586. cirq/protocols/json_test_data/GridParallelXEBMetadata.json +0 -119
  587. cirq/protocols/json_test_data/GridParallelXEBMetadata.repr +0 -1
  588. cirq_core-1.4.0.dev20240529225110.dist-info/METADATA +0 -50
  589. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/LICENSE +0 -0
  590. {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/top_level.txt +0 -0
cirq/ops/common_gates.py CHANGED
@@ -25,12 +25,13 @@ Each of these are implemented as EigenGates, which means that they can be
25
25
  raised to a power (i.e. cirq.H**0.5). See the definition in EigenGate.
26
26
  """
27
27
 
28
+ from types import NotImplementedType
28
29
  from typing import (
29
30
  Any,
30
31
  cast,
31
32
  Collection,
32
- List,
33
33
  Dict,
34
+ List,
34
35
  Optional,
35
36
  Sequence,
36
37
  Tuple,
@@ -45,12 +46,9 @@ import cirq
45
46
  from cirq import protocols, value
46
47
  from cirq._compat import proper_repr
47
48
  from cirq._doc import document
48
- from cirq.ops import controlled_gate, eigen_gate, gate_features, raw_types, control_values as cv
49
-
50
- from cirq.type_workarounds import NotImplementedType
51
-
52
- from cirq.ops.swap_gates import ISWAP, SWAP, ISwapPowGate, SwapPowGate
49
+ from cirq.ops import control_values as cv, controlled_gate, eigen_gate, gate_features, raw_types
53
50
  from cirq.ops.measurement_gate import MeasurementGate
51
+ from cirq.ops.swap_gates import ISWAP, ISwapPowGate, SWAP, SwapPowGate
54
52
 
55
53
  if TYPE_CHECKING:
56
54
  import cirq
@@ -179,7 +177,7 @@ class XPowGate(eigen_gate.EigenGate):
179
177
  return SingleQubitCliffordGate.X.on(*qubits)
180
178
  if self.exponent % 2 == 1.5:
181
179
  return SingleQubitCliffordGate.X_nsqrt.on(*qubits)
182
- return NotImplemented
180
+ return NotImplemented # pragma: no cover
183
181
 
184
182
  def _trace_distance_bound_(self) -> Optional[float]:
185
183
  if self._is_parameterized_() or self._dimension != 2:
@@ -260,11 +258,12 @@ class XPowGate(eigen_gate.EigenGate):
260
258
  return result
261
259
 
262
260
  def _pauli_expansion_(self) -> value.LinearDict[str]:
263
- if protocols.is_parameterized(self) or self._dimension != 2:
264
- return NotImplemented
261
+ if self._dimension != 2:
262
+ return NotImplemented # pragma: no cover
265
263
  phase = 1j ** (2 * self._exponent * (self._global_shift + 0.5))
266
- angle = np.pi * self._exponent / 2
267
- return value.LinearDict({'I': phase * np.cos(angle), 'X': -1j * phase * np.sin(angle)})
264
+ lib = sympy if protocols.is_parameterized(self) else np
265
+ angle = lib.pi * self._exponent / 2
266
+ return value.LinearDict({'I': phase * lib.cos(angle), 'X': -1j * phase * lib.sin(angle)})
268
267
 
269
268
  def _circuit_diagram_info_(
270
269
  self, args: 'cirq.CircuitDiagramInfoArgs'
@@ -274,7 +273,7 @@ class XPowGate(eigen_gate.EigenGate):
274
273
  )
275
274
 
276
275
  def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
277
- args.validate_version('2.0')
276
+ args.validate_version('2.0', '3.0')
278
277
  if self._global_shift == 0:
279
278
  if self._exponent == 1:
280
279
  return args.format('x {0};\n', qubits[0])
@@ -290,9 +289,7 @@ class XPowGate(eigen_gate.EigenGate):
290
289
 
291
290
  def _phase_by_(self, phase_turns, qubit_index):
292
291
  """See `cirq.SupportsPhase`."""
293
- return cirq.ops.phased_x_gate.PhasedXPowGate(
294
- exponent=self._exponent, phase_exponent=phase_turns * 2
295
- )
292
+ return _phased_x_or_pauli_gate(exponent=self._exponent, phase_exponent=phase_turns * 2)
296
293
 
297
294
  def _has_stabilizer_effect_(self) -> Optional[bool]:
298
295
  if self._is_parameterized_() or self._dimension != 2:
@@ -327,12 +324,6 @@ class XPowGate(eigen_gate.EigenGate):
327
324
  d['dimension'] = self.dimension
328
325
  return d
329
326
 
330
- def _value_equality_values_(self):
331
- return (*super()._value_equality_values_(), self._dimension)
332
-
333
- def _value_equality_approximate_values_(self):
334
- return (*super()._value_equality_approximate_values_(), self._dimension)
335
-
336
327
 
337
328
  class Rx(XPowGate):
338
329
  r"""A gate with matrix $e^{-i X t/2}$ that rotates around the X axis of the Bloch sphere by $t$.
@@ -376,7 +367,7 @@ class Rx(XPowGate):
376
367
  return f'cirq.Rx(rads={proper_repr(self._rads)})'
377
368
 
378
369
  def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
379
- args.validate_version('2.0')
370
+ args.validate_version('2.0', '3.0')
380
371
  return args.format('rx({0:half_turns}) {1};\n', self._exponent, qubits[0])
381
372
 
382
373
  def _json_dict_(self) -> Dict[str, Any]:
@@ -452,7 +443,7 @@ class YPowGate(eigen_gate.EigenGate):
452
443
  return SingleQubitCliffordGate.Y.on(*qubits)
453
444
  if self.exponent % 2 == 1.5:
454
445
  return SingleQubitCliffordGate.Y_nsqrt.on(*qubits)
455
- return NotImplemented
446
+ return NotImplemented # pragma: no cover
456
447
 
457
448
  def _eigen_components(self) -> List[Tuple[float, np.ndarray]]:
458
449
  return [
@@ -466,11 +457,10 @@ class YPowGate(eigen_gate.EigenGate):
466
457
  return abs(np.sin(self._exponent * 0.5 * np.pi))
467
458
 
468
459
  def _pauli_expansion_(self) -> value.LinearDict[str]:
469
- if protocols.is_parameterized(self):
470
- return NotImplemented
471
460
  phase = 1j ** (2 * self._exponent * (self._global_shift + 0.5))
472
- angle = np.pi * self._exponent / 2
473
- return value.LinearDict({'I': phase * np.cos(angle), 'Y': -1j * phase * np.sin(angle)})
461
+ lib = sympy if protocols.is_parameterized(self) else np
462
+ angle = lib.pi * self._exponent / 2
463
+ return value.LinearDict({'I': phase * lib.cos(angle), 'Y': -1j * phase * lib.sin(angle)})
474
464
 
475
465
  def _circuit_diagram_info_(
476
466
  self, args: 'cirq.CircuitDiagramInfoArgs'
@@ -480,7 +470,7 @@ class YPowGate(eigen_gate.EigenGate):
480
470
  )
481
471
 
482
472
  def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
483
- args.validate_version('2.0')
473
+ args.validate_version('2.0', '3.0')
484
474
  if self._exponent == 1 and self.global_shift != -0.5:
485
475
  return args.format('y {0};\n', qubits[0])
486
476
 
@@ -492,7 +482,7 @@ class YPowGate(eigen_gate.EigenGate):
492
482
 
493
483
  def _phase_by_(self, phase_turns, qubit_index):
494
484
  """See `cirq.SupportsPhase`."""
495
- return cirq.ops.phased_x_gate.PhasedXPowGate(
485
+ return _phased_x_or_pauli_gate(
496
486
  exponent=self._exponent, phase_exponent=0.5 + phase_turns * 2
497
487
  )
498
488
 
@@ -562,7 +552,7 @@ class Ry(YPowGate):
562
552
  return f'cirq.Ry(rads={proper_repr(self._rads)})'
563
553
 
564
554
  def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
565
- args.validate_version('2.0')
555
+ args.validate_version('2.0', '3.0')
566
556
  return args.format('ry({0:half_turns}) {1};\n', self._exponent, qubits[0])
567
557
 
568
558
  def _json_dict_(self) -> Dict[str, Any]:
@@ -658,7 +648,7 @@ class ZPowGate(eigen_gate.EigenGate):
658
648
  return SingleQubitCliffordGate.Z.on(*qubits)
659
649
  if self.exponent % 2 == 1.5:
660
650
  return SingleQubitCliffordGate.Z_nsqrt.on(*qubits)
661
- return NotImplemented
651
+ return NotImplemented # pragma: no cover
662
652
 
663
653
  def in_su2(self) -> 'Rz':
664
654
  """Returns an equal-up-global-phase gate from the group SU2."""
@@ -766,11 +756,12 @@ class ZPowGate(eigen_gate.EigenGate):
766
756
  return abs(np.sin(self._exponent * 0.5 * np.pi))
767
757
 
768
758
  def _pauli_expansion_(self) -> value.LinearDict[str]:
769
- if protocols.is_parameterized(self) or self._dimension != 2:
770
- return NotImplemented
759
+ if self._dimension != 2:
760
+ return NotImplemented # pragma: no cover
771
761
  phase = 1j ** (2 * self._exponent * (self._global_shift + 0.5))
772
- angle = np.pi * self._exponent / 2
773
- return value.LinearDict({'I': phase * np.cos(angle), 'Z': -1j * phase * np.sin(angle)})
762
+ lib = sympy if protocols.is_parameterized(self) else np
763
+ angle = lib.pi * self._exponent / 2
764
+ return value.LinearDict({'I': phase * lib.cos(angle), 'Z': -1j * phase * lib.sin(angle)})
774
765
 
775
766
  def _phase_by_(self, phase_turns: float, qubit_index: int):
776
767
  return self
@@ -793,7 +784,7 @@ class ZPowGate(eigen_gate.EigenGate):
793
784
  return protocols.CircuitDiagramInfo(wire_symbols=('Z',), exponent=e)
794
785
 
795
786
  def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
796
- args.validate_version('2.0')
787
+ args.validate_version('2.0', '3.0')
797
788
 
798
789
  if self.global_shift == 0:
799
790
  if self._exponent == 1:
@@ -863,12 +854,6 @@ class ZPowGate(eigen_gate.EigenGate):
863
854
  d['dimension'] = self.dimension
864
855
  return d
865
856
 
866
- def _value_equality_values_(self):
867
- return (*super()._value_equality_values_(), self._dimension)
868
-
869
- def _value_equality_approximate_values_(self):
870
- return (*super()._value_equality_approximate_values_(), self._dimension)
871
-
872
857
 
873
858
  class Rz(ZPowGate):
874
859
  r"""A gate with matrix $e^{-i Z t/2}$ that rotates around the Z axis of the Bloch sphere by $t$.
@@ -912,7 +897,7 @@ class Rz(ZPowGate):
912
897
  return f'cirq.Rz(rads={proper_repr(self._rads)})'
913
898
 
914
899
  def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
915
- args.validate_version('2.0')
900
+ args.validate_version('2.0', '3.0')
916
901
  return args.format('rz({0:half_turns}) {1};\n', self._exponent, qubits[0])
917
902
 
918
903
  def _json_dict_(self) -> Dict[str, Any]:
@@ -983,7 +968,7 @@ class HPowGate(eigen_gate.EigenGate):
983
968
  return SingleQubitCliffordGate.H.on(*qubits)
984
969
  if self.exponent % 2 == 0:
985
970
  return []
986
- return NotImplemented
971
+ return NotImplemented # pragma: no cover
987
972
 
988
973
  def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> Optional[np.ndarray]:
989
974
  if self._exponent != 1:
@@ -1018,7 +1003,7 @@ class HPowGate(eigen_gate.EigenGate):
1018
1003
  )
1019
1004
 
1020
1005
  def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
1021
- args.validate_version('2.0')
1006
+ args.validate_version('2.0', '3.0')
1022
1007
  if self._exponent == 0:
1023
1008
  return args.format('id {0};\n', qubits[0])
1024
1009
  elif self._exponent == 1 and self._global_shift == 0:
@@ -1081,7 +1066,7 @@ class CZPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
1081
1066
  return PauliInteractionGate.CZ.on(*qubits)
1082
1067
  if self.exponent % 2 == 0:
1083
1068
  return []
1084
- return NotImplemented
1069
+ return NotImplemented # pragma: no cover
1085
1070
 
1086
1071
  def _eigen_components(self) -> List[Tuple[float, np.ndarray]]:
1087
1072
  return [(0, np.diag([1, 1, 1, 0])), (1, np.diag([0, 0, 0, 1]))]
@@ -1206,7 +1191,7 @@ class CZPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
1206
1191
  def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
1207
1192
  if self._exponent != 1:
1208
1193
  return None # Don't have an equivalent gate in QASM
1209
- args.validate_version('2.0')
1194
+ args.validate_version('2.0', '3.0')
1210
1195
  return args.format('cz {0},{1};\n', qubits[0], qubits[1])
1211
1196
 
1212
1197
  def _has_stabilizer_effect_(self) -> Optional[bool]:
@@ -1276,7 +1261,7 @@ class CXPowGate(eigen_gate.EigenGate):
1276
1261
  return PauliInteractionGate.CNOT.on(*qubits)
1277
1262
  if self.exponent % 2 == 0:
1278
1263
  return []
1279
- return NotImplemented
1264
+ return NotImplemented # pragma: no cover
1280
1265
 
1281
1266
  def _decompose_(self, qubits):
1282
1267
  c, t = qubits
@@ -1407,7 +1392,7 @@ class CXPowGate(eigen_gate.EigenGate):
1407
1392
  def _qasm_(self, args: 'cirq.QasmArgs', qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
1408
1393
  if self._exponent != 1:
1409
1394
  return None # Don't have an equivalent gate in QASM
1410
- args.validate_version('2.0')
1395
+ args.validate_version('2.0', '3.0')
1411
1396
  return args.format('cx {0},{1};\n', qubits[0], qubits[1])
1412
1397
 
1413
1398
  def _has_stabilizer_effect_(self) -> Optional[bool]:
@@ -1555,3 +1540,17 @@ document(
1555
1540
  $$
1556
1541
  """,
1557
1542
  )
1543
+
1544
+
1545
+ def _phased_x_or_pauli_gate(
1546
+ exponent: Union[float, sympy.Expr], phase_exponent: Union[float, sympy.Expr]
1547
+ ) -> Union['cirq.PhasedXPowGate', 'cirq.XPowGate', 'cirq.YPowGate']:
1548
+ """Return PhasedXPowGate or X or Y gate if equivalent at the given phase_exponent."""
1549
+ if not isinstance(phase_exponent, sympy.Expr) or phase_exponent.is_constant():
1550
+ half_turns = value.canonicalize_half_turns(float(phase_exponent))
1551
+ match half_turns:
1552
+ case 0.0:
1553
+ return XPowGate(exponent=exponent)
1554
+ case 0.5:
1555
+ return YPowGate(exponent=exponent)
1556
+ return cirq.ops.PhasedXPowGate(exponent=exponent, phase_exponent=phase_exponent)
@@ -245,11 +245,12 @@ def test_rot_gates_eq():
245
245
  eq.add_equality_group(cirq.YPowGate(), cirq.YPowGate(exponent=1), cirq.Y)
246
246
  eq.add_equality_group(cirq.ZPowGate(), cirq.ZPowGate(exponent=1), cirq.Z)
247
247
  eq.add_equality_group(
248
- cirq.ZPowGate(exponent=1, global_shift=-0.5), cirq.ZPowGate(exponent=5, global_shift=-0.5)
248
+ cirq.ZPowGate(exponent=1, global_shift=-0.5),
249
+ cirq.ZPowGate(exponent=5, global_shift=-0.5),
250
+ cirq.ZPowGate(exponent=5, global_shift=-0.1),
249
251
  )
250
252
  eq.add_equality_group(cirq.ZPowGate(exponent=3, global_shift=-0.5))
251
253
  eq.add_equality_group(cirq.ZPowGate(exponent=1, global_shift=-0.1))
252
- eq.add_equality_group(cirq.ZPowGate(exponent=5, global_shift=-0.1))
253
254
  eq.add_equality_group(
254
255
  cirq.CNotPowGate(), cirq.CXPowGate(), cirq.CNotPowGate(exponent=1), cirq.CNOT
255
256
  )
@@ -307,6 +308,11 @@ def test_h_str():
307
308
  assert str(cirq.H**0.5) == 'H**0.5'
308
309
 
309
310
 
311
+ def test_phase_exponent():
312
+ assert cirq.XPowGate(exponent=0.5).phase_exponent == 0.0
313
+ assert cirq.YPowGate(exponent=0.5).phase_exponent == 0.5
314
+
315
+
310
316
  def test_x_act_on_tableau():
311
317
  with pytest.raises(TypeError, match="Failed to act"):
312
318
  cirq.act_on(cirq.X, ExampleSimulationState(), qubits=())
@@ -1300,3 +1306,13 @@ def test_wrong_dims():
1300
1306
 
1301
1307
  with pytest.raises(ValueError, match='Wrong shape'):
1302
1308
  _ = cirq.Z.on(cirq.LineQid(0, dimension=3))
1309
+
1310
+
1311
+ @pytest.mark.parametrize('gate_type', [cirq.XPowGate, cirq.YPowGate, cirq.ZPowGate])
1312
+ @pytest.mark.parametrize('exponent', [sympy.Symbol('s'), sympy.Symbol('s') * 2])
1313
+ def test_parameterized_pauli_expansion(gate_type, exponent):
1314
+ gate = gate_type(exponent=exponent)
1315
+ pauli = cirq.pauli_expansion(gate)
1316
+ gate_resolved = cirq.resolve_parameters(gate, {'s': 0.5})
1317
+ pauli_resolved = cirq.resolve_parameters(pauli, {'s': 0.5})
1318
+ assert cirq.approx_eq(pauli_resolved, cirq.pauli_expansion(gate_resolved))
@@ -12,9 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  import abc
15
- from functools import cached_property
16
- from typing import Collection, Tuple, TYPE_CHECKING, Any, Dict, Iterator, Optional, Sequence, Union
17
15
  import itertools
16
+ from functools import cached_property
17
+ from typing import Any, Collection, Dict, Iterator, Optional, Sequence, Tuple, TYPE_CHECKING, Union
18
18
 
19
19
  from cirq import protocols, value
20
20
 
@@ -275,7 +275,7 @@ class SumOfProducts(AbstractControlValues):
275
275
 
276
276
  if len(self._conjunctions) == 1:
277
277
  # Use a simpler diagram if there's only 1 term.
278
- return protocols.CircuitDiagramInfo(
278
+ return protocols.CircuitDiagramInfo( # pragma: no cover
279
279
  wire_symbols=["@" if x == 1 else f"({x})" for x in self._conjunctions[0]]
280
280
  )
281
281
 
@@ -12,9 +12,10 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- import cirq
16
15
  import pytest
17
16
 
17
+ import cirq
18
+
18
19
 
19
20
  def test_init_sum_of_products_raises():
20
21
  # data shouldn't be empty.
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from types import NotImplementedType
15
16
  from typing import (
16
17
  AbstractSet,
17
18
  Any,
@@ -21,21 +22,21 @@ from typing import (
21
22
  Optional,
22
23
  Sequence,
23
24
  Tuple,
24
- Union,
25
25
  TYPE_CHECKING,
26
+ Union,
26
27
  )
27
28
 
28
29
  import numpy as np
29
30
 
30
- from cirq import protocols, value, _import
31
+ from cirq import _import, protocols, value
31
32
  from cirq.ops import (
32
- raw_types,
33
+ control_values as cv,
33
34
  controlled_operation as cop,
35
+ diagonal_gate as dg,
36
+ global_phase_op as gp,
34
37
  op_tree,
35
- matrix_gates,
36
- control_values as cv,
38
+ raw_types,
37
39
  )
38
- from cirq.type_workarounds import NotImplementedType
39
40
 
40
41
  if TYPE_CHECKING:
41
42
  import cirq
@@ -157,13 +158,13 @@ class ControlledGate(raw_types.Gate):
157
158
  def _decompose_with_context_(
158
159
  self, qubits: Tuple['cirq.Qid', ...], context: Optional['cirq.DecompositionContext'] = None
159
160
  ) -> Union[None, NotImplementedType, 'cirq.OP_TREE']:
161
+ control_qubits = list(qubits[: self.num_controls()])
160
162
  if (
161
163
  protocols.has_unitary(self.sub_gate)
162
164
  and protocols.num_qubits(self.sub_gate) == 1
163
165
  and self._qid_shape_() == (2,) * len(self._qid_shape_())
164
166
  and isinstance(self.control_values, cv.ProductOfSums)
165
167
  ):
166
- control_qubits = list(qubits[: self.num_controls()])
167
168
  invert_ops: List['cirq.Operation'] = []
168
169
  for cvals, cqbit in zip(self.control_values, qubits[: self.num_controls()]):
169
170
  if set(cvals) == {0}:
@@ -174,11 +175,20 @@ class ControlledGate(raw_types.Gate):
174
175
  protocols.unitary(self.sub_gate), control_qubits, qubits[-1]
175
176
  )
176
177
  return invert_ops + decomposed_ops + invert_ops
177
-
178
+ if isinstance(self.sub_gate, gp.GlobalPhaseGate):
179
+ # A controlled global phase is a diagonal gate, where each active control value index
180
+ # is set equal to the phase angle.
181
+ shape = self.control_qid_shape
182
+ if protocols.is_parameterized(self.sub_gate) or set(shape) != {2}:
183
+ # Could work in theory, but DiagonalGate decompose does not support them.
184
+ return NotImplemented
185
+ angle = np.angle(complex(self.sub_gate.coefficient))
186
+ rads = np.zeros(shape=shape)
187
+ for hot in self.control_values.expand():
188
+ rads[hot] = angle
189
+ return dg.DiagonalGate(diag_angles_radians=[*rads.flatten()]).on(*qubits)
178
190
  if isinstance(self.sub_gate, common_gates.CZPowGate):
179
- z_sub_gate = common_gates.ZPowGate(
180
- exponent=self.sub_gate.exponent, global_shift=self.sub_gate.global_shift
181
- )
191
+ z_sub_gate = common_gates.ZPowGate(exponent=self.sub_gate.exponent)
182
192
  num_controls = self.num_controls() + 1
183
193
  control_values = self.control_values & cv.ProductOfSums(((1,),))
184
194
  control_qid_shape = self.control_qid_shape + (2,)
@@ -197,15 +207,18 @@ class ControlledGate(raw_types.Gate):
197
207
  )
198
208
  )
199
209
  if self != controlled_z:
200
- return protocols.decompose_once_with_qubits(
201
- controlled_z, qubits, NotImplemented, context=context
202
- )
203
-
204
- if isinstance(self.sub_gate, matrix_gates.MatrixGate):
205
- # Default decompositions of 2/3 qubit `cirq.MatrixGate` ignores global phase, which is
206
- # local phase in the controlled variant and hence cannot be ignored.
207
- return NotImplemented
208
-
210
+ result = controlled_z.on(*qubits)
211
+ if self.sub_gate.global_shift == 0:
212
+ return result
213
+ # Reconstruct the controlled global shift of the subgate.
214
+ total_shift = self.sub_gate.exponent * self.sub_gate.global_shift
215
+ phase_gate = gp.GlobalPhaseGate(1j ** (2 * total_shift))
216
+ controlled_phase_op = phase_gate.controlled(
217
+ num_controls=self.num_controls(),
218
+ control_values=self.control_values,
219
+ control_qid_shape=self.control_qid_shape,
220
+ ).on(*control_qubits)
221
+ return [result, controlled_phase_op]
209
222
  result = protocols.decompose_once_with_qubits(
210
223
  self.sub_gate,
211
224
  qubits[self.num_controls() :],
@@ -255,7 +268,7 @@ class ControlledGate(raw_types.Gate):
255
268
  def _has_mixture_(self) -> bool:
256
269
  return protocols.has_mixture(self.sub_gate)
257
270
 
258
- def _mixture_(self) -> Union[np.ndarray, NotImplementedType]:
271
+ def _mixture_(self) -> Union[Sequence[tuple[float, np.ndarray]], NotImplementedType]:
259
272
  qubits = line_qubit.LineQid.for_gate(self)
260
273
  op = self.sub_gate.on(*qubits[self.num_controls() :])
261
274
  c_op = cop.ControlledOperation(qubits[: self.num_controls()], op, self.control_values)
@@ -294,7 +307,7 @@ class ControlledGate(raw_types.Gate):
294
307
  return None
295
308
  u = protocols.unitary(self.sub_gate, default=None)
296
309
  if u is None:
297
- return NotImplemented
310
+ return NotImplemented # pragma: no cover
298
311
  angle_list = np.append(np.angle(np.linalg.eigvals(u)), 0)
299
312
  return protocols.trace_distance_from_angle_list(angle_list)
300
313
 
@@ -328,7 +341,7 @@ class ControlledGate(raw_types.Gate):
328
341
  return str(self.control_values) + str(self.sub_gate)
329
342
 
330
343
  def __repr__(self) -> str:
331
- if self.num_controls() == 1 and self.control_values.is_trivial:
344
+ if self.control_qid_shape == (2,) and self.control_values.is_trivial:
332
345
  return f'cirq.ControlledGate(sub_gate={self.sub_gate!r})'
333
346
 
334
347
  if self.control_values.is_trivial and set(self.control_qid_shape) == {2}:
@@ -12,14 +12,14 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from typing import Union, Tuple, cast
15
+ from types import NotImplementedType
16
+ from typing import Any, cast, Optional, Sequence, Tuple, Union
16
17
 
17
18
  import numpy as np
18
19
  import pytest
19
20
  import sympy
20
21
 
21
22
  import cirq
22
- from cirq.type_workarounds import NotImplementedType
23
23
 
24
24
 
25
25
  class GateUsingWorkspaceForApplyUnitary(cirq.testing.SingleQubitGate):
@@ -408,6 +408,11 @@ def test_unitary():
408
408
  ),
409
409
  True,
410
410
  ),
411
+ (cirq.GlobalPhaseGate(-1), True),
412
+ (cirq.GlobalPhaseGate(1j**0.7), True),
413
+ (cirq.GlobalPhaseGate(sympy.Symbol("s")), False),
414
+ (cirq.CZPowGate(exponent=1.2, global_shift=0.3), True),
415
+ (cirq.CZPowGate(exponent=sympy.Symbol("s"), global_shift=0.3), False),
411
416
  # Single qudit gate with dimension 4.
412
417
  (cirq.MatrixGate(np.kron(*(cirq.unitary(cirq.H),) * 2), qid_shape=(4,)), False),
413
418
  (cirq.MatrixGate(cirq.testing.random_unitary(4, random_state=1234)), False),
@@ -420,11 +425,73 @@ def test_unitary():
420
425
  ],
421
426
  )
422
427
  def test_controlled_gate_is_consistent(gate: cirq.Gate, should_decompose_to_target):
423
- cgate = cirq.ControlledGate(gate)
428
+ _test_controlled_gate_is_consistent(gate, should_decompose_to_target)
429
+
430
+
431
+ @pytest.mark.parametrize(
432
+ 'gate',
433
+ [
434
+ cirq.I,
435
+ cirq.GlobalPhaseGate(1),
436
+ cirq.GlobalPhaseGate(-1),
437
+ cirq.GlobalPhaseGate(1j),
438
+ cirq.GlobalPhaseGate(1j**0.7),
439
+ cirq.Z,
440
+ cirq.ZPowGate(exponent=1.2, global_shift=0.3),
441
+ cirq.CZ,
442
+ cirq.CZPowGate(exponent=1.2, global_shift=0.3),
443
+ cirq.CCZ,
444
+ cirq.CCZPowGate(exponent=1.2, global_shift=0.3),
445
+ cirq.X,
446
+ cirq.XPowGate(exponent=1.2, global_shift=0.3),
447
+ cirq.CX,
448
+ cirq.CXPowGate(exponent=1.2, global_shift=0.3),
449
+ cirq.CCX,
450
+ cirq.CCXPowGate(exponent=1.2, global_shift=0.3),
451
+ ],
452
+ )
453
+ @pytest.mark.parametrize(
454
+ 'control_qid_shape, control_values, should_decompose_to_target',
455
+ [
456
+ ([2, 2], None, True),
457
+ ([2, 2], xor_control_values, False),
458
+ ([3], None, False),
459
+ ([3, 4], xor_control_values, False),
460
+ ],
461
+ )
462
+ def test_nontrivial_controlled_gate_is_consistent(
463
+ gate: cirq.Gate,
464
+ control_qid_shape: Sequence[int],
465
+ control_values: Any,
466
+ should_decompose_to_target: bool,
467
+ ):
468
+ _test_controlled_gate_is_consistent(
469
+ gate, should_decompose_to_target, control_qid_shape, control_values
470
+ )
471
+
472
+
473
+ def _test_controlled_gate_is_consistent(
474
+ gate: cirq.Gate,
475
+ should_decompose_to_target: bool,
476
+ control_qid_shape: Optional[Sequence[int]] = None,
477
+ control_values: Any = None,
478
+ ):
479
+ cgate = cirq.ControlledGate(
480
+ gate, control_qid_shape=control_qid_shape, control_values=control_values
481
+ )
424
482
  cirq.testing.assert_implements_consistent_protocols(cgate)
425
483
  cirq.testing.assert_decompose_ends_at_default_gateset(
426
484
  cgate, ignore_known_gates=not should_decompose_to_target
427
485
  )
486
+ # The above only decompose once, which doesn't check that the sub-gate's phase is handled.
487
+ # We need to check full decomposition here.
488
+ if not cirq.is_parameterized(gate):
489
+ shape = cirq.qid_shape(cgate)
490
+ qids = cirq.LineQid.for_qid_shape(shape)
491
+ decomposed = cirq.decompose(cgate.on(*qids))
492
+ first_op = cirq.IdentityGate(qid_shape=shape).on(*qids) # To ensure same qid order
493
+ circuit = cirq.Circuit(first_op, *decomposed)
494
+ np.testing.assert_allclose(cirq.unitary(cgate), cirq.unitary(circuit), atol=1e-13)
428
495
 
429
496
 
430
497
  def test_pow_inverse():
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ from types import NotImplementedType
15
16
  from typing import (
16
17
  AbstractSet,
17
18
  Any,
@@ -21,24 +22,23 @@ from typing import (
21
22
  Optional,
22
23
  Sequence,
23
24
  Tuple,
24
- Union,
25
25
  TYPE_CHECKING,
26
+ Union,
26
27
  )
27
28
 
28
29
  import numpy as np
29
30
 
30
31
  from cirq import protocols, qis, value
31
32
  from cirq.ops import (
32
- controlled_gate,
33
33
  common_gates,
34
+ control_values as cv,
35
+ controlled_gate,
34
36
  eigen_gate,
35
37
  gate_operation,
36
38
  matrix_gates,
37
39
  op_tree,
38
40
  raw_types,
39
- control_values as cv,
40
41
  )
41
- from cirq.type_workarounds import NotImplementedType
42
42
 
43
43
  if TYPE_CHECKING:
44
44
  import cirq
@@ -212,6 +212,7 @@ class ControlledOperation(raw_types.Operation):
212
212
  hasattr(self._sub_operation, "gate")
213
213
  and len(self._controls) == 1
214
214
  and self.control_values == cv.ProductOfSums(((1,),))
215
+ and all(q.dimension == 2 for q in self.qubits)
215
216
  ):
216
217
  gate = self.sub_operation.gate
217
218
  if (
@@ -296,7 +297,7 @@ class ControlledOperation(raw_types.Operation):
296
297
  return None
297
298
  u = protocols.unitary(self.sub_operation, default=None)
298
299
  if u is None:
299
- return NotImplemented
300
+ return NotImplemented # pragma: no cover
300
301
  angle_list = np.append(np.angle(np.linalg.eigvals(u)), 0)
301
302
  return protocols.trace_distance_from_angle_list(angle_list)
302
303
 
@@ -14,6 +14,7 @@
14
14
 
15
15
  import itertools
16
16
  import re
17
+ from types import NotImplementedType
17
18
  from typing import cast, Tuple, Union
18
19
 
19
20
  import numpy as np
@@ -22,7 +23,6 @@ import sympy
22
23
 
23
24
  import cirq
24
25
  from cirq import protocols
25
- from cirq.type_workarounds import NotImplementedType
26
26
 
27
27
 
28
28
  class GateUsingWorkspaceForApplyUnitary(cirq.testing.SingleQubitGate):
@@ -159,7 +159,7 @@ def test_str():
159
159
  return ()
160
160
 
161
161
  def with_qubits(self, *new_qubits: cirq.Qid):
162
- pass
162
+ return self
163
163
 
164
164
  def __str__(self):
165
165
  return "Op(q2)"
@@ -170,7 +170,11 @@ def test_str():
170
170
  assert str(cirq.ControlledOperation([c1, c2], SingleQubitOp())) == "CC(c1, c2, Op(q2))"
171
171
 
172
172
  assert (
173
- str(cirq.ControlledOperation([c1, c2.with_dimension(3)], SingleQubitOp()))
173
+ str(
174
+ cirq.ControlledOperation(
175
+ [c1, c2.with_dimension(3)], SingleQubitOp().with_qubits(cirq.q(1))
176
+ )
177
+ )
174
178
  == "CC(c1, c2 (d=3), Op(q2))"
175
179
  )
176
180