qiskit 1.3.0b1__cp39-abi3-win32.whl → 1.3.0rc2__cp39-abi3-win32.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 (360) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/__init__.py +20 -1
  3. qiskit/_accelerate.pyd +0 -0
  4. qiskit/assembler/assemble_schedules.py +2 -0
  5. qiskit/circuit/__init__.py +44 -1
  6. qiskit/circuit/_standard_gates_commutations.py +585 -0
  7. qiskit/circuit/barrier.py +2 -0
  8. qiskit/circuit/controlflow/builder.py +3 -3
  9. qiskit/circuit/controlflow/if_else.py +13 -5
  10. qiskit/circuit/controlflow/while_loop.py +10 -2
  11. qiskit/circuit/delay.py +20 -3
  12. qiskit/circuit/equivalence.py +13 -214
  13. qiskit/circuit/gate.py +3 -1
  14. qiskit/circuit/instruction.py +32 -11
  15. qiskit/circuit/instructionset.py +2 -0
  16. qiskit/circuit/library/__init__.py +110 -14
  17. qiskit/circuit/library/arithmetic/__init__.py +9 -2
  18. qiskit/circuit/library/arithmetic/adders/__init__.py +1 -0
  19. qiskit/circuit/library/arithmetic/adders/adder.py +154 -2
  20. qiskit/circuit/library/arithmetic/adders/cdkm_ripple_carry_adder.py +20 -56
  21. qiskit/circuit/library/arithmetic/adders/draper_qft_adder.py +14 -1
  22. qiskit/circuit/library/arithmetic/adders/vbe_ripple_carry_adder.py +21 -91
  23. qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +1 -1
  24. qiskit/circuit/library/arithmetic/multipliers/__init__.py +1 -0
  25. qiskit/circuit/library/arithmetic/multipliers/hrs_cumulative_multiplier.py +8 -1
  26. qiskit/circuit/library/arithmetic/multipliers/multiplier.py +94 -3
  27. qiskit/circuit/library/arithmetic/multipliers/rg_qft_multiplier.py +8 -1
  28. qiskit/circuit/library/arithmetic/weighted_adder.py +1 -1
  29. qiskit/circuit/library/basis_change/qft.py +20 -38
  30. qiskit/circuit/library/blueprintcircuit.py +64 -0
  31. qiskit/circuit/library/boolean_logic/__init__.py +4 -4
  32. qiskit/circuit/library/boolean_logic/inner_product.py +81 -4
  33. qiskit/circuit/library/boolean_logic/quantum_and.py +107 -4
  34. qiskit/circuit/library/boolean_logic/quantum_or.py +107 -3
  35. qiskit/circuit/library/boolean_logic/quantum_xor.py +97 -3
  36. qiskit/circuit/library/data_preparation/__init__.py +6 -3
  37. qiskit/circuit/library/data_preparation/{z_feature_map.py → _z_feature_map.py} +45 -34
  38. qiskit/circuit/library/data_preparation/_zz_feature_map.py +150 -0
  39. qiskit/circuit/library/data_preparation/pauli_feature_map.py +342 -29
  40. qiskit/circuit/library/fourier_checking.py +72 -11
  41. qiskit/circuit/library/generalized_gates/__init__.py +1 -1
  42. qiskit/circuit/library/generalized_gates/diagonal.py +45 -51
  43. qiskit/circuit/library/generalized_gates/gms.py +67 -14
  44. qiskit/circuit/library/generalized_gates/gr.py +4 -4
  45. qiskit/circuit/library/generalized_gates/isometry.py +2 -2
  46. qiskit/circuit/library/generalized_gates/linear_function.py +12 -6
  47. qiskit/circuit/library/generalized_gates/mcmt.py +167 -107
  48. qiskit/circuit/library/generalized_gates/permutation.py +8 -6
  49. qiskit/circuit/library/generalized_gates/rv.py +8 -9
  50. qiskit/circuit/library/graph_state.py +93 -10
  51. qiskit/circuit/library/grover_operator.py +270 -2
  52. qiskit/circuit/library/hidden_linear_function.py +83 -20
  53. qiskit/circuit/library/iqp.py +99 -20
  54. qiskit/circuit/library/n_local/__init__.py +19 -7
  55. qiskit/circuit/library/n_local/efficient_su2.py +118 -5
  56. qiskit/circuit/library/n_local/evolved_operator_ansatz.py +259 -0
  57. qiskit/circuit/library/n_local/excitation_preserving.py +130 -6
  58. qiskit/circuit/library/n_local/n_local.py +406 -5
  59. qiskit/circuit/library/n_local/pauli_two_design.py +106 -4
  60. qiskit/circuit/library/n_local/qaoa_ansatz.py +80 -1
  61. qiskit/circuit/library/n_local/real_amplitudes.py +127 -7
  62. qiskit/circuit/library/n_local/two_local.py +14 -7
  63. qiskit/circuit/library/overlap.py +91 -26
  64. qiskit/circuit/library/pauli_evolution.py +17 -15
  65. qiskit/circuit/library/phase_estimation.py +80 -4
  66. qiskit/circuit/library/quantum_volume.py +72 -20
  67. qiskit/circuit/library/standard_gates/__init__.py +20 -1
  68. qiskit/circuit/library/standard_gates/dcx.py +2 -1
  69. qiskit/circuit/library/standard_gates/ecr.py +2 -2
  70. qiskit/circuit/library/standard_gates/h.py +4 -3
  71. qiskit/circuit/library/standard_gates/i.py +2 -1
  72. qiskit/circuit/library/standard_gates/iswap.py +2 -2
  73. qiskit/circuit/library/standard_gates/p.py +20 -12
  74. qiskit/circuit/library/standard_gates/r.py +1 -1
  75. qiskit/circuit/library/standard_gates/rx.py +4 -3
  76. qiskit/circuit/library/standard_gates/rxx.py +2 -2
  77. qiskit/circuit/library/standard_gates/ry.py +4 -3
  78. qiskit/circuit/library/standard_gates/ryy.py +2 -2
  79. qiskit/circuit/library/standard_gates/rz.py +13 -12
  80. qiskit/circuit/library/standard_gates/rzx.py +6 -6
  81. qiskit/circuit/library/standard_gates/rzz.py +1 -1
  82. qiskit/circuit/library/standard_gates/s.py +4 -4
  83. qiskit/circuit/library/standard_gates/swap.py +3 -3
  84. qiskit/circuit/library/standard_gates/sx.py +4 -3
  85. qiskit/circuit/library/standard_gates/t.py +2 -2
  86. qiskit/circuit/library/standard_gates/u.py +11 -3
  87. qiskit/circuit/library/standard_gates/u1.py +65 -15
  88. qiskit/circuit/library/standard_gates/u2.py +4 -1
  89. qiskit/circuit/library/standard_gates/u3.py +31 -3
  90. qiskit/circuit/library/standard_gates/x.py +7 -5
  91. qiskit/circuit/library/standard_gates/xx_minus_yy.py +2 -2
  92. qiskit/circuit/library/standard_gates/xx_plus_yy.py +2 -2
  93. qiskit/circuit/library/standard_gates/y.py +4 -3
  94. qiskit/circuit/library/standard_gates/z.py +3 -3
  95. qiskit/circuit/library/templates/clifford/clifford_2_1.py +9 -8
  96. qiskit/circuit/library/templates/clifford/clifford_2_2.py +10 -9
  97. qiskit/circuit/library/templates/clifford/clifford_2_3.py +9 -7
  98. qiskit/circuit/library/templates/clifford/clifford_2_4.py +9 -8
  99. qiskit/circuit/library/templates/clifford/clifford_3_1.py +9 -8
  100. qiskit/circuit/library/templates/clifford/clifford_4_1.py +10 -9
  101. qiskit/circuit/library/templates/clifford/clifford_4_2.py +10 -9
  102. qiskit/circuit/library/templates/clifford/clifford_4_3.py +10 -9
  103. qiskit/circuit/library/templates/clifford/clifford_4_4.py +10 -9
  104. qiskit/circuit/library/templates/clifford/clifford_5_1.py +10 -9
  105. qiskit/circuit/library/templates/clifford/clifford_6_1.py +10 -9
  106. qiskit/circuit/library/templates/clifford/clifford_6_2.py +10 -9
  107. qiskit/circuit/library/templates/clifford/clifford_6_3.py +10 -9
  108. qiskit/circuit/library/templates/clifford/clifford_6_4.py +9 -8
  109. qiskit/circuit/library/templates/clifford/clifford_6_5.py +10 -9
  110. qiskit/circuit/library/templates/clifford/clifford_8_1.py +10 -9
  111. qiskit/circuit/library/templates/clifford/clifford_8_2.py +10 -9
  112. qiskit/circuit/library/templates/clifford/clifford_8_3.py +10 -9
  113. qiskit/circuit/library/templates/nct/template_nct_2a_1.py +9 -7
  114. qiskit/circuit/library/templates/nct/template_nct_2a_2.py +10 -8
  115. qiskit/circuit/library/templates/nct/template_nct_2a_3.py +12 -10
  116. qiskit/circuit/library/templates/nct/template_nct_4a_1.py +16 -14
  117. qiskit/circuit/library/templates/nct/template_nct_4a_2.py +14 -12
  118. qiskit/circuit/library/templates/nct/template_nct_4a_3.py +12 -10
  119. qiskit/circuit/library/templates/nct/template_nct_4b_1.py +14 -12
  120. qiskit/circuit/library/templates/nct/template_nct_4b_2.py +12 -10
  121. qiskit/circuit/library/templates/nct/template_nct_5a_1.py +12 -10
  122. qiskit/circuit/library/templates/nct/template_nct_5a_2.py +12 -10
  123. qiskit/circuit/library/templates/nct/template_nct_5a_3.py +12 -10
  124. qiskit/circuit/library/templates/nct/template_nct_5a_4.py +11 -9
  125. qiskit/circuit/library/templates/nct/template_nct_6a_1.py +11 -9
  126. qiskit/circuit/library/templates/nct/template_nct_6a_2.py +12 -10
  127. qiskit/circuit/library/templates/nct/template_nct_6a_3.py +12 -10
  128. qiskit/circuit/library/templates/nct/template_nct_6a_4.py +12 -10
  129. qiskit/circuit/library/templates/nct/template_nct_6b_1.py +12 -10
  130. qiskit/circuit/library/templates/nct/template_nct_6b_2.py +12 -10
  131. qiskit/circuit/library/templates/nct/template_nct_6c_1.py +12 -10
  132. qiskit/circuit/library/templates/nct/template_nct_7a_1.py +13 -11
  133. qiskit/circuit/library/templates/nct/template_nct_7b_1.py +13 -11
  134. qiskit/circuit/library/templates/nct/template_nct_7c_1.py +13 -11
  135. qiskit/circuit/library/templates/nct/template_nct_7d_1.py +13 -11
  136. qiskit/circuit/library/templates/nct/template_nct_7e_1.py +13 -11
  137. qiskit/circuit/library/templates/nct/template_nct_9a_1.py +13 -11
  138. qiskit/circuit/library/templates/nct/template_nct_9c_1.py +11 -9
  139. qiskit/circuit/library/templates/nct/template_nct_9c_10.py +12 -10
  140. qiskit/circuit/library/templates/nct/template_nct_9c_11.py +12 -10
  141. qiskit/circuit/library/templates/nct/template_nct_9c_12.py +12 -10
  142. qiskit/circuit/library/templates/nct/template_nct_9c_2.py +12 -10
  143. qiskit/circuit/library/templates/nct/template_nct_9c_3.py +12 -10
  144. qiskit/circuit/library/templates/nct/template_nct_9c_4.py +12 -10
  145. qiskit/circuit/library/templates/nct/template_nct_9c_5.py +12 -10
  146. qiskit/circuit/library/templates/nct/template_nct_9c_6.py +12 -10
  147. qiskit/circuit/library/templates/nct/template_nct_9c_7.py +12 -10
  148. qiskit/circuit/library/templates/nct/template_nct_9c_8.py +12 -10
  149. qiskit/circuit/library/templates/nct/template_nct_9c_9.py +12 -10
  150. qiskit/circuit/library/templates/nct/template_nct_9d_1.py +11 -9
  151. qiskit/circuit/library/templates/nct/template_nct_9d_10.py +12 -10
  152. qiskit/circuit/library/templates/nct/template_nct_9d_2.py +12 -10
  153. qiskit/circuit/library/templates/nct/template_nct_9d_3.py +12 -10
  154. qiskit/circuit/library/templates/nct/template_nct_9d_4.py +12 -10
  155. qiskit/circuit/library/templates/nct/template_nct_9d_5.py +12 -10
  156. qiskit/circuit/library/templates/nct/template_nct_9d_6.py +12 -10
  157. qiskit/circuit/library/templates/nct/template_nct_9d_7.py +12 -10
  158. qiskit/circuit/library/templates/nct/template_nct_9d_8.py +12 -10
  159. qiskit/circuit/library/templates/nct/template_nct_9d_9.py +12 -10
  160. qiskit/circuit/library/templates/rzx/rzx_cy.py +11 -10
  161. qiskit/circuit/library/templates/rzx/rzx_xz.py +16 -15
  162. qiskit/circuit/library/templates/rzx/rzx_yz.py +12 -10
  163. qiskit/circuit/library/templates/rzx/rzx_zz1.py +22 -20
  164. qiskit/circuit/library/templates/rzx/rzx_zz2.py +16 -15
  165. qiskit/circuit/library/templates/rzx/rzx_zz3.py +17 -15
  166. qiskit/circuit/parameter.py +4 -0
  167. qiskit/circuit/parameterexpression.py +167 -34
  168. qiskit/circuit/quantumcircuit.py +162 -126
  169. qiskit/circuit/singleton.py +2 -0
  170. qiskit/circuit/store.py +2 -0
  171. qiskit/circuit/twirling.py +145 -0
  172. qiskit/compiler/assembler.py +17 -4
  173. qiskit/compiler/scheduler.py +2 -0
  174. qiskit/compiler/sequencer.py +2 -0
  175. qiskit/compiler/transpiler.py +81 -26
  176. qiskit/converters/circuit_to_dag.py +2 -2
  177. qiskit/converters/circuit_to_dagdependency.py +1 -1
  178. qiskit/converters/circuit_to_dagdependency_v2.py +1 -1
  179. qiskit/converters/circuit_to_instruction.py +1 -1
  180. qiskit/converters/dag_to_circuit.py +7 -5
  181. qiskit/converters/dag_to_dagdependency.py +1 -1
  182. qiskit/converters/dag_to_dagdependency_v2.py +1 -1
  183. qiskit/converters/dagdependency_to_circuit.py +5 -1
  184. qiskit/converters/dagdependency_to_dag.py +6 -1
  185. qiskit/dagcircuit/collect_blocks.py +3 -3
  186. qiskit/dagcircuit/dagdependency.py +18 -5
  187. qiskit/dagcircuit/dagdependency_v2.py +1 -1
  188. qiskit/dagcircuit/dagnode.py +2 -2
  189. qiskit/passmanager/__init__.py +2 -2
  190. qiskit/primitives/backend_estimator.py +5 -2
  191. qiskit/primitives/backend_sampler_v2.py +61 -18
  192. qiskit/primitives/base/base_estimator.py +2 -2
  193. qiskit/primitives/containers/data_bin.py +9 -1
  194. qiskit/primitives/statevector_sampler.py +1 -1
  195. qiskit/primitives/utils.py +1 -1
  196. qiskit/providers/__init__.py +3 -3
  197. qiskit/providers/backend.py +12 -1
  198. qiskit/providers/backend_compat.py +23 -3
  199. qiskit/providers/basic_provider/basic_simulator.py +12 -2
  200. qiskit/providers/fake_provider/fake_pulse_backend.py +6 -1
  201. qiskit/providers/fake_provider/generic_backend_v2.py +46 -30
  202. qiskit/providers/models/pulsedefaults.py +2 -0
  203. qiskit/pulse/builder.py +59 -18
  204. qiskit/pulse/calibration_entries.py +4 -1
  205. qiskit/pulse/channels.py +2 -0
  206. qiskit/pulse/exceptions.py +2 -0
  207. qiskit/pulse/instruction_schedule_map.py +21 -6
  208. qiskit/pulse/instructions/acquire.py +2 -0
  209. qiskit/pulse/instructions/delay.py +2 -0
  210. qiskit/pulse/instructions/directives.py +8 -0
  211. qiskit/pulse/instructions/frequency.py +3 -0
  212. qiskit/pulse/instructions/instruction.py +2 -0
  213. qiskit/pulse/instructions/phase.py +3 -0
  214. qiskit/pulse/instructions/play.py +2 -0
  215. qiskit/pulse/instructions/reference.py +2 -0
  216. qiskit/pulse/instructions/snapshot.py +2 -0
  217. qiskit/pulse/library/pulse.py +2 -0
  218. qiskit/pulse/library/symbolic_pulses.py +28 -0
  219. qiskit/pulse/library/waveform.py +2 -0
  220. qiskit/pulse/macros.py +1 -1
  221. qiskit/pulse/schedule.py +12 -13
  222. qiskit/pulse/transforms/alignments.py +5 -3
  223. qiskit/pulse/transforms/dag.py +7 -0
  224. qiskit/qasm2/export.py +5 -3
  225. qiskit/qasm2/parse.py +46 -2
  226. qiskit/qasm3/__init__.py +1 -0
  227. qiskit/qasm3/ast.py +123 -15
  228. qiskit/qasm3/exporter.py +103 -77
  229. qiskit/qobj/converters/pulse_instruction.py +6 -4
  230. qiskit/qpy/__init__.py +181 -0
  231. qiskit/qpy/binary_io/circuits.py +20 -5
  232. qiskit/qpy/binary_io/schedules.py +3 -4
  233. qiskit/qpy/binary_io/value.py +310 -13
  234. qiskit/qpy/common.py +46 -2
  235. qiskit/qpy/formats.py +7 -0
  236. qiskit/qpy/interface.py +40 -4
  237. qiskit/quantum_info/__init__.py +4 -0
  238. qiskit/quantum_info/operators/channel/transformations.py +28 -21
  239. qiskit/quantum_info/operators/dihedral/dihedral.py +1 -1
  240. qiskit/quantum_info/operators/operator.py +54 -8
  241. qiskit/quantum_info/operators/symplectic/base_pauli.py +11 -19
  242. qiskit/quantum_info/operators/symplectic/clifford.py +1 -1
  243. qiskit/quantum_info/operators/symplectic/clifford_circuits.py +1 -1
  244. qiskit/quantum_info/operators/symplectic/pauli.py +2 -0
  245. qiskit/quantum_info/operators/symplectic/pauli_list.py +4 -4
  246. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +23 -2
  247. qiskit/quantum_info/states/densitymatrix.py +5 -5
  248. qiskit/quantum_info/states/stabilizerstate.py +1 -1
  249. qiskit/quantum_info/states/statevector.py +6 -6
  250. qiskit/result/mitigation/base_readout_mitigator.py +1 -1
  251. qiskit/result/mitigation/correlated_readout_mitigator.py +9 -1
  252. qiskit/result/mitigation/local_readout_mitigator.py +9 -1
  253. qiskit/result/mitigation/utils.py +57 -0
  254. qiskit/scheduler/config.py +2 -0
  255. qiskit/scheduler/methods/basic.py +3 -0
  256. qiskit/scheduler/schedule_circuit.py +2 -0
  257. qiskit/scheduler/sequence.py +2 -0
  258. qiskit/synthesis/__init__.py +25 -0
  259. qiskit/synthesis/arithmetic/__init__.py +16 -0
  260. qiskit/synthesis/arithmetic/adders/__init__.py +17 -0
  261. qiskit/synthesis/arithmetic/adders/cdkm_ripple_carry_adder.py +154 -0
  262. qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +103 -0
  263. qiskit/synthesis/arithmetic/adders/vbe_ripple_carry_adder.py +161 -0
  264. qiskit/synthesis/arithmetic/multipliers/__init__.py +16 -0
  265. qiskit/synthesis/arithmetic/multipliers/hrs_cumulative_multiplier.py +102 -0
  266. qiskit/synthesis/arithmetic/multipliers/rg_qft_multiplier.py +99 -0
  267. qiskit/synthesis/clifford/clifford_decompose_bm.py +1 -2
  268. qiskit/synthesis/clifford/clifford_decompose_greedy.py +3 -2
  269. qiskit/synthesis/clifford/clifford_decompose_layers.py +2 -1
  270. qiskit/synthesis/evolution/__init__.py +1 -0
  271. qiskit/synthesis/evolution/lie_trotter.py +16 -42
  272. qiskit/synthesis/evolution/pauli_network.py +80 -0
  273. qiskit/synthesis/evolution/product_formula.py +165 -238
  274. qiskit/synthesis/evolution/qdrift.py +36 -29
  275. qiskit/synthesis/evolution/suzuki_trotter.py +87 -27
  276. qiskit/synthesis/multi_controlled/__init__.py +1 -0
  277. qiskit/synthesis/multi_controlled/mcmt_vchain.py +52 -0
  278. qiskit/synthesis/qft/qft_decompose_full.py +19 -1
  279. qiskit/synthesis/qft/qft_decompose_lnn.py +2 -1
  280. qiskit/synthesis/stabilizer/stabilizer_decompose.py +2 -1
  281. qiskit/synthesis/two_qubit/two_qubit_decompose.py +4 -63
  282. qiskit/synthesis/unitary/qsd.py +5 -5
  283. qiskit/transpiler/__init__.py +21 -14
  284. qiskit/transpiler/basepasses.py +1 -1
  285. qiskit/transpiler/passes/__init__.py +2 -0
  286. qiskit/transpiler/passes/basis/basis_translator.py +9 -565
  287. qiskit/transpiler/passes/basis/decompose.py +45 -12
  288. qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
  289. qiskit/transpiler/passes/basis/unroll_custom_definitions.py +1 -1
  290. qiskit/transpiler/passes/calibration/pulse_gate.py +4 -2
  291. qiskit/transpiler/passes/calibration/rx_builder.py +11 -7
  292. qiskit/transpiler/passes/calibration/rzx_builder.py +46 -30
  293. qiskit/transpiler/passes/layout/disjoint_utils.py +15 -13
  294. qiskit/transpiler/passes/layout/sabre_layout.py +7 -2
  295. qiskit/transpiler/passes/layout/sabre_pre_layout.py +5 -0
  296. qiskit/transpiler/passes/optimization/__init__.py +1 -0
  297. qiskit/transpiler/passes/optimization/collect_cliffords.py +19 -3
  298. qiskit/transpiler/passes/optimization/collect_linear_functions.py +1 -1
  299. qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +2 -2
  300. qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py +1 -1
  301. qiskit/transpiler/passes/optimization/consolidate_blocks.py +48 -131
  302. qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py +4 -2
  303. qiskit/transpiler/passes/optimization/elide_permutations.py +9 -32
  304. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +5 -11
  305. qiskit/transpiler/passes/optimization/optimize_1q_gates.py +1 -1
  306. qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py +1 -1
  307. qiskit/transpiler/passes/optimization/remove_identity_equiv.py +69 -0
  308. qiskit/transpiler/passes/optimization/template_matching/backward_match.py +5 -5
  309. qiskit/transpiler/passes/optimization/template_matching/forward_match.py +4 -4
  310. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +2 -2
  311. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +1 -1
  312. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/swap_strategy.py +1 -1
  313. qiskit/transpiler/passes/routing/sabre_swap.py +7 -3
  314. qiskit/transpiler/passes/routing/star_prerouting.py +2 -2
  315. qiskit/transpiler/passes/scheduling/alap.py +1 -1
  316. qiskit/transpiler/passes/scheduling/alignments/align_measures.py +2 -2
  317. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
  318. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +2 -0
  319. qiskit/transpiler/passes/scheduling/alignments/reschedule.py +2 -2
  320. qiskit/transpiler/passes/scheduling/asap.py +1 -1
  321. qiskit/transpiler/passes/scheduling/base_scheduler.py +14 -12
  322. qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +9 -4
  323. qiskit/transpiler/passes/scheduling/padding/base_padding.py +1 -1
  324. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +16 -5
  325. qiskit/transpiler/passes/scheduling/padding/pad_delay.py +4 -1
  326. qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +6 -2
  327. qiskit/transpiler/passes/scheduling/time_unit_conversion.py +9 -4
  328. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +262 -99
  329. qiskit/transpiler/passes/synthesis/hls_plugins.py +637 -7
  330. qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +3 -3
  331. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +55 -34
  332. qiskit/transpiler/passes/utils/barrier_before_final_measurements.py +2 -56
  333. qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +5 -0
  334. qiskit/transpiler/passes/utils/gate_direction.py +12 -275
  335. qiskit/transpiler/passes/utils/gates_basis.py +7 -30
  336. qiskit/transpiler/passes/utils/merge_adjacent_barriers.py +2 -1
  337. qiskit/transpiler/passmanager_config.py +22 -4
  338. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +40 -14
  339. qiskit/transpiler/preset_passmanagers/common.py +5 -3
  340. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +125 -42
  341. qiskit/transpiler/preset_passmanagers/plugin.py +1 -1
  342. qiskit/transpiler/target.py +74 -16
  343. qiskit/utils/deprecate_pulse.py +119 -0
  344. qiskit/visualization/circuit/_utils.py +2 -2
  345. qiskit/visualization/circuit/circuit_visualization.py +3 -2
  346. qiskit/visualization/circuit/matplotlib.py +1 -1
  347. qiskit/visualization/dag_visualization.py +1 -1
  348. qiskit/visualization/pass_manager_visualization.py +3 -14
  349. qiskit/visualization/pulse_v2/interface.py +3 -1
  350. qiskit/visualization/timeline/core.py +25 -2
  351. qiskit/visualization/timeline/interface.py +12 -0
  352. {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/METADATA +9 -8
  353. {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/RECORD +357 -346
  354. {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/WHEEL +1 -1
  355. {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/entry_points.txt +19 -0
  356. qiskit/circuit/library/data_preparation/zz_feature_map.py +0 -118
  357. qiskit/synthesis/two_qubit/weyl.py +0 -97
  358. qiskit/transpiler/passes/synthesis/qubit_tracker.py +0 -132
  359. {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/LICENSE.txt +0 -0
  360. {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/top_level.txt +0 -0
@@ -15,17 +15,26 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import inspect
18
- from collections.abc import Callable
19
- from typing import Any
20
- from functools import partial
18
+ import itertools
19
+ from collections.abc import Callable, Sequence
20
+ from collections import defaultdict
21
+ from itertools import combinations
22
+ import typing
21
23
  import numpy as np
24
+ import rustworkx as rx
22
25
  from qiskit.circuit.parameterexpression import ParameterExpression
23
- from qiskit.circuit.quantumcircuit import QuantumCircuit
26
+ from qiskit.circuit.quantumcircuit import QuantumCircuit, ParameterValueType
24
27
  from qiskit.quantum_info import SparsePauliOp, Pauli
25
28
  from qiskit.utils.deprecation import deprecate_arg
29
+ from qiskit._accelerate.circuit_library import pauli_evolution
26
30
 
27
31
  from .evolution_synthesis import EvolutionSynthesis
28
32
 
33
+ if typing.TYPE_CHECKING:
34
+ from qiskit.circuit.library import PauliEvolutionGate
35
+
36
+ SparsePauliLabel = typing.Tuple[str, list[int], ParameterValueType]
37
+
29
38
 
30
39
  class ProductFormula(EvolutionSynthesis):
31
40
  """Product formula base class for the decomposition of non-commuting operator exponentials.
@@ -60,6 +69,7 @@ class ProductFormula(EvolutionSynthesis):
60
69
  | None
61
70
  ) = None,
62
71
  wrap: bool = False,
72
+ preserve_order: bool = True,
63
73
  ) -> None:
64
74
  """
65
75
  Args:
@@ -78,24 +88,31 @@ class ProductFormula(EvolutionSynthesis):
78
88
  Alternatively, the function can also take Pauli operator and evolution time as
79
89
  inputs and returns the circuit that will be appended to the overall circuit being
80
90
  built.
81
- wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
82
- effect when ``atomic_evolution is None``.
91
+ wrap: Whether to wrap the atomic evolutions into custom gate objects. Note that setting
92
+ this to ``True`` is slower than ``False``. This only takes effect when
93
+ ``atomic_evolution is None``.
94
+ preserve_order: If ``False``, allows reordering the terms of the operator to
95
+ potentially yield a shallower evolution circuit. Not relevant
96
+ when synthesizing operator with a single term.
83
97
  """
84
98
  super().__init__()
85
99
  self.order = order
86
100
  self.reps = reps
87
101
  self.insert_barriers = insert_barriers
102
+ self.preserve_order = preserve_order
88
103
 
89
104
  # user-provided atomic evolution, stored for serialization
90
105
  self._atomic_evolution = atomic_evolution
106
+
107
+ if cx_structure not in ["chain", "fountain"]:
108
+ raise ValueError(f"Unsupported CX structure: {cx_structure}")
109
+
91
110
  self._cx_structure = cx_structure
92
111
  self._wrap = wrap
93
112
 
94
113
  # if atomic evolution is not provided, set a default
95
114
  if atomic_evolution is None:
96
- self.atomic_evolution = partial(
97
- _default_atomic_evolution, cx_structure=cx_structure, wrap=wrap
98
- )
115
+ self.atomic_evolution = None
99
116
 
100
117
  elif len(inspect.signature(atomic_evolution).parameters) == 2:
101
118
 
@@ -108,8 +125,50 @@ class ProductFormula(EvolutionSynthesis):
108
125
  else:
109
126
  self.atomic_evolution = atomic_evolution
110
127
 
128
+ def expand(
129
+ self, evolution: PauliEvolutionGate
130
+ ) -> list[tuple[str, tuple[int], ParameterValueType]]:
131
+ """Apply the product formula to expand the Hamiltonian in the evolution gate.
132
+
133
+ Args:
134
+ evolution: The :class:`.PauliEvolutionGate`, whose Hamiltonian we expand.
135
+
136
+ Returns:
137
+ A list of Pauli rotations in a sparse format, where each element is
138
+ ``(paulistring, qubits, coefficient)``. For example, the Lie-Trotter expansion
139
+ of ``H = XI + ZZ`` would return ``[("X", [1], 1), ("ZZ", [0, 1], 1)]``.
140
+ """
141
+ raise NotImplementedError(
142
+ f"The method ``expand`` is not implemented for {self.__class__}. Implement it to "
143
+ f"automatically enable the call to {self.__class__}.synthesize."
144
+ )
145
+
146
+ def synthesize(self, evolution: PauliEvolutionGate) -> QuantumCircuit:
147
+ """Synthesize a :class:`.PauliEvolutionGate`.
148
+
149
+ Args:
150
+ evolution: The evolution gate to synthesize.
151
+
152
+ Returns:
153
+ QuantumCircuit: A circuit implementing the evolution.
154
+ """
155
+ pauli_rotations = self.expand(evolution)
156
+ num_qubits = evolution.num_qubits
157
+
158
+ if self._wrap or self._atomic_evolution is not None:
159
+ # this is the slow path, where each Pauli evolution is constructed in Rust
160
+ # separately and then wrapped into a gate object
161
+ circuit = self._custom_evolution(num_qubits, pauli_rotations)
162
+ else:
163
+ # this is the fast path, where the whole evolution is constructed Rust-side
164
+ cx_fountain = self._cx_structure == "fountain"
165
+ data = pauli_evolution(num_qubits, pauli_rotations, self.insert_barriers, cx_fountain)
166
+ circuit = QuantumCircuit._from_circuit_data(data, add_regs=True)
167
+
168
+ return circuit
169
+
111
170
  @property
112
- def settings(self) -> dict[str, Any]:
171
+ def settings(self) -> dict[str, typing.Any]:
113
172
  """Return the settings in a dictionary, which can be used to reconstruct the object.
114
173
 
115
174
  Returns:
@@ -129,256 +188,124 @@ class ProductFormula(EvolutionSynthesis):
129
188
  "insert_barriers": self.insert_barriers,
130
189
  "cx_structure": self._cx_structure,
131
190
  "wrap": self._wrap,
191
+ "preserve_order": self.preserve_order,
132
192
  }
133
193
 
194
+ def _normalize_coefficients(
195
+ self, paulis: list[str | list[int], float | complex | ParameterExpression]
196
+ ) -> list[str | list[int] | ParameterValueType]:
197
+ """Ensure the coefficients are real (or parameter expressions)."""
198
+ return [[(op, qubits, real_or_fail(coeff)) for op, qubits, coeff in ops] for ops in paulis]
134
199
 
135
- def evolve_pauli(
136
- output: QuantumCircuit,
137
- pauli: Pauli,
138
- time: float | ParameterExpression = 1.0,
139
- cx_structure: str = "chain",
140
- wrap: bool = False,
141
- label: str | None = None,
142
- ) -> None:
143
- r"""Construct a circuit implementing the time evolution of a single Pauli string.
144
-
145
- For a Pauli string :math:`P = \{I, X, Y, Z\}^{\otimes n}` on :math:`n` qubits and an
146
- evolution time :math:`t`, the returned circuit implements the unitary operation
147
-
148
- .. math::
149
-
150
- U(t) = e^{-itP}.
151
-
152
- Since only a single Pauli string is evolved the circuit decomposition is exact.
153
-
154
- Args:
155
- output: The circuit object to which to append the evolved Pauli.
156
- pauli: The Pauli to evolve.
157
- time: The evolution time.
158
- cx_structure: Determine the structure of CX gates, can be either ``"chain"`` for
159
- next-neighbor connections or ``"fountain"`` to connect directly to the top qubit.
160
- wrap: Whether to wrap the single Pauli evolutions into custom gate objects.
161
- label: A label for the gate.
162
- """
163
- num_non_identity = len([label for label in pauli.to_label() if label != "I"])
164
-
165
- # first check, if the Pauli is only the identity, in which case the evolution only
166
- # adds a global phase
167
- if num_non_identity == 0:
168
- output.global_phase -= time
169
- # if we evolve on a single qubit, if yes use the corresponding qubit rotation
170
- elif num_non_identity == 1:
171
- _single_qubit_evolution(output, pauli, time, wrap)
172
- # same for two qubits, use Qiskit's native rotations
173
- elif num_non_identity == 2:
174
- _two_qubit_evolution(output, pauli, time, cx_structure, wrap)
175
- # otherwise do basis transformation and CX chains
176
- else:
177
- _multi_qubit_evolution(output, pauli, time, cx_structure, wrap)
178
-
179
-
180
- def _single_qubit_evolution(output, pauli, time, wrap):
181
- dest = QuantumCircuit(1) if wrap else output
182
- # Note that all phases are removed from the pauli label and are only in the coefficients.
183
- # That's because the operators we evolved have all been translated to a SparsePauliOp.
184
- qubits = []
185
- label = ""
186
- for i, pauli_i in enumerate(reversed(pauli.to_label())):
187
- idx = 0 if wrap else i
188
- if pauli_i == "X":
189
- dest.rx(2 * time, idx)
190
- qubits.append(i)
191
- label += "X"
192
- elif pauli_i == "Y":
193
- dest.ry(2 * time, idx)
194
- qubits.append(i)
195
- label += "Y"
196
- elif pauli_i == "Z":
197
- dest.rz(2 * time, idx)
198
- qubits.append(i)
199
- label += "Z"
200
-
201
- if wrap:
202
- gate = dest.to_gate(label=f"exp(it {label})")
203
- qubits = [output.qubits[q] for q in qubits]
204
- output.append(gate, qargs=qubits, copy=False)
205
-
206
-
207
- def _two_qubit_evolution(output, pauli, time, cx_structure, wrap):
208
- # Get the Paulis and the qubits they act on.
209
- # Note that all phases are removed from the pauli label and are only in the coefficients.
210
- # That's because the operators we evolved have all been translated to a SparsePauliOp.
211
- labels_as_array = np.array(list(reversed(pauli.to_label())))
212
- qubits = np.where(labels_as_array != "I")[0]
213
- indices = [0, 1] if wrap else qubits
214
- labels = np.array([labels_as_array[idx] for idx in qubits])
215
-
216
- dest = QuantumCircuit(2) if wrap else output
217
-
218
- # go through all cases we have implemented in Qiskit
219
- if all(labels == "X"): # RXX
220
- dest.rxx(2 * time, indices[0], indices[1])
221
- elif all(labels == "Y"): # RYY
222
- dest.ryy(2 * time, indices[0], indices[1])
223
- elif all(labels == "Z"): # RZZ
224
- dest.rzz(2 * time, indices[0], indices[1])
225
- elif labels[0] == "Z" and labels[1] == "X": # RZX
226
- dest.rzx(2 * time, indices[0], indices[1])
227
- elif labels[0] == "X" and labels[1] == "Z": # RXZ
228
- dest.rzx(2 * time, indices[1], indices[0])
229
- else: # all the others are not native in Qiskit, so use default the decomposition
230
- _multi_qubit_evolution(output, pauli, time, cx_structure, wrap)
231
- return
232
-
233
- if wrap:
234
- gate = dest.to_gate(label=f"exp(it {''.join(labels)})")
235
- qubits = [output.qubits[q] for q in qubits]
236
- output.append(gate, qargs=qubits, copy=False)
237
-
238
-
239
- def _multi_qubit_evolution(output, pauli, time, cx_structure, wrap):
240
- # get diagonalizing clifford
241
- cliff = diagonalizing_clifford(pauli)
242
-
243
- # get CX chain to reduce the evolution to the top qubit
244
- if cx_structure == "chain":
245
- chain = cnot_chain(pauli)
246
- else:
247
- chain = cnot_fountain(pauli)
248
-
249
- # determine qubit to do the rotation on
250
- target = None
251
- # Note that all phases are removed from the pauli label and are only in the coefficients.
252
- # That's because the operators we evolved have all been translated to a SparsePauliOp.
253
- for i, pauli_i in enumerate(reversed(pauli.to_label())):
254
- if pauli_i != "I":
255
- target = i
256
- break
257
-
258
- # build the evolution as: diagonalization, reduction, 1q evolution, followed by inverses
259
- dest = QuantumCircuit(pauli.num_qubits) if wrap else output
260
- dest.compose(cliff, inplace=True)
261
- dest.compose(chain, inplace=True)
262
- dest.rz(2 * time, target)
263
- dest.compose(chain.inverse(), inplace=True)
264
- dest.compose(cliff.inverse(), inplace=True)
265
-
266
- if wrap:
267
- gate = dest.to_gate(label=f"exp(it {pauli.to_label()})")
268
- output.append(gate, qargs=output.qubits, copy=False)
269
-
270
-
271
- def diagonalizing_clifford(pauli: Pauli) -> QuantumCircuit:
272
- """Get the clifford circuit to diagonalize the Pauli operator.
200
+ def _custom_evolution(self, num_qubits, pauli_rotations):
201
+ """Implement the evolution for the non-standard path.
273
202
 
274
- Args:
275
- pauli: The Pauli to diagonalize.
203
+ This is either because a user-defined atomic evolution is given, or because the evolution
204
+ of individual Paulis needs to be wrapped in gates.
205
+ """
206
+ circuit = QuantumCircuit(num_qubits)
207
+ cx_fountain = self._cx_structure == "fountain"
276
208
 
277
- Returns:
278
- A circuit to diagonalize.
279
- """
280
- cliff = QuantumCircuit(pauli.num_qubits)
281
- for i, pauli_i in enumerate(reversed(pauli.to_label())):
282
- if pauli_i == "Y":
283
- cliff.sdg(i)
284
- if pauli_i in ["X", "Y"]:
285
- cliff.h(i)
209
+ num_paulis = len(pauli_rotations)
210
+ for i, pauli_rotation in enumerate(pauli_rotations):
211
+ if self._atomic_evolution is not None:
212
+ # use the user-provided evolution with a global operator
213
+ operator = SparsePauliOp.from_sparse_list([pauli_rotation], num_qubits)
214
+ self.atomic_evolution(circuit, operator, time=1) # time is inside the Pauli coeff
286
215
 
287
- return cliff
216
+ else: # this means self._wrap is True
217
+ # we create a local sparse Pauli representation such that the operator
218
+ # does not span over all qubits of the circuit
219
+ pauli_string, qubits, coeff = pauli_rotation
220
+ local_pauli = (pauli_string, list(range(len(qubits))), coeff)
288
221
 
222
+ # build the circuit Rust-side
223
+ data = pauli_evolution(
224
+ len(qubits),
225
+ [local_pauli],
226
+ False,
227
+ cx_fountain,
228
+ )
229
+ evo = QuantumCircuit._from_circuit_data(data)
289
230
 
290
- def cnot_chain(pauli: Pauli) -> QuantumCircuit:
291
- """CX chain.
231
+ # and append it to the circuit with the correct label
232
+ gate = evo.to_gate(label=f"exp(it {pauli_string})")
233
+ circuit.append(gate, qubits)
292
234
 
293
- For example, for the Pauli with the label 'XYZIX'.
235
+ if self.insert_barriers and i < num_paulis - 1:
236
+ circuit.barrier()
294
237
 
295
- .. parsed-literal::
238
+ return circuit
296
239
 
297
- ┌───┐
298
- q_0: ──────────┤ X ├
299
- └─┬─┘
300
- q_1: ────────────┼──
301
- ┌───┐ │
302
- q_2: ─────┤ X ├──■──
303
- ┌───┐└─┬─┘
304
- q_3: ┤ X ├──■───────
305
- └─┬─┘
306
- q_4: ──■────────────
307
240
 
308
- Args:
309
- pauli: The Pauli for which to construct the CX chain.
241
+ def real_or_fail(value, tol=100):
242
+ """Return real if close, otherwise fail. Unbound parameters are left unchanged.
310
243
 
311
- Returns:
312
- A circuit implementing the CX chain.
244
+ Based on NumPy's ``real_if_close``, i.e. ``tol`` is in terms of machine precision for float.
313
245
  """
246
+ if isinstance(value, ParameterExpression):
247
+ return value
314
248
 
315
- chain = QuantumCircuit(pauli.num_qubits)
316
- control, target = None, None
249
+ abstol = tol * np.finfo(float).eps
250
+ if abs(np.imag(value)) < abstol:
251
+ return np.real(value)
317
252
 
318
- # iterate over the Pauli's and add CNOTs
319
- for i, pauli_i in enumerate(pauli.to_label()):
320
- i = pauli.num_qubits - i - 1
321
- if pauli_i != "I":
322
- if control is None:
323
- control = i
324
- else:
325
- target = i
253
+ raise ValueError(f"Encountered complex value {value}, but expected real.")
326
254
 
327
- if control is not None and target is not None:
328
- chain.cx(control, target)
329
- control = i
330
- target = None
331
255
 
332
- return chain
256
+ def reorder_paulis(
257
+ paulis: Sequence[SparsePauliLabel],
258
+ strategy: rx.ColoringStrategy = rx.ColoringStrategy.Saturation,
259
+ ) -> list[SparsePauliLabel]:
260
+ r"""
261
+ Creates an equivalent operator by reordering terms in order to yield a
262
+ shallower circuit after evolution synthesis. The original operator remains
263
+ unchanged.
333
264
 
265
+ This method works in three steps. First, a graph is constructed, where the
266
+ nodes are the terms of the operator and where two nodes are connected if
267
+ their terms act on the same qubit (for example, the terms :math:`IXX` and
268
+ :math:`IYI` would be connected, but not :math:`IXX` and :math:`YII`). Then,
269
+ the graph is colored. Two terms with the same color thus do not act on the
270
+ same qubit, and in particular, their evolution subcircuits can be run in
271
+ parallel in the greater evolution circuit of ``paulis``.
334
272
 
335
- def cnot_fountain(pauli: Pauli) -> QuantumCircuit:
336
- """CX chain in the fountain shape.
337
-
338
- For example, for the Pauli with the label 'XYZIX'.
339
-
340
- .. parsed-literal::
341
-
342
- ┌───┐┌───┐┌───┐
343
- q_0: ┤ X ├┤ X ├┤ X ├
344
- └─┬─┘└─┬─┘└─┬─┘
345
- q_1: ──┼────┼────┼──
346
- │ │ │
347
- q_2: ──■────┼────┼──
348
- │ │
349
- q_3: ───────■────┼──
350
-
351
- q_4: ────────────■──
273
+ This method is deterministic and invariant under permutation of the Pauli
274
+ term in ``paulis``.
352
275
 
353
276
  Args:
354
- pauli: The Pauli for which to construct the CX chain.
277
+ paulis: The operator whose terms to reorder.
278
+ strategy: The coloring heuristic to use, see ``ColoringStrategy`` [#].
279
+ Default is ``ColoringStrategy.Saturation``.
280
+
281
+ .. [#] https://www.rustworkx.org/apiref/rustworkx.ColoringStrategy.html#coloringstrategy
355
282
 
356
- Returns:
357
- A circuit implementing the CX chain.
358
283
  """
359
284
 
360
- chain = QuantumCircuit(pauli.num_qubits)
361
- control, target = None, None
362
- for i, pauli_i in enumerate(reversed(pauli.to_label())):
363
- if pauli_i != "I":
364
- if target is None:
365
- target = i
366
- else:
367
- control = i
368
-
369
- if control is not None and target is not None:
370
- chain.cx(control, target)
371
- control = None
372
-
373
- return chain
374
-
375
-
376
- def _default_atomic_evolution(output, operator, time, cx_structure, wrap):
377
- if isinstance(operator, Pauli):
378
- # single Pauli operator: just exponentiate it
379
- evolve_pauli(output, operator, time, cx_structure, wrap)
380
- else:
381
- # sum of Pauli operators: exponentiate each term (this assumes they commute)
382
- pauli_list = [(Pauli(op), np.real(coeff)) for op, coeff in operator.to_list()]
383
- for pauli, coeff in pauli_list:
384
- evolve_pauli(output, pauli, coeff * time, cx_structure, wrap)
285
+ def _term_sort_key(term: SparsePauliLabel) -> typing.Any:
286
+ # sort by index, then by pauli
287
+ return (term[1], term[0])
288
+
289
+ # Do nothing in trivial cases
290
+ if len(paulis) <= 1:
291
+ return paulis
292
+
293
+ terms = sorted(paulis, key=_term_sort_key)
294
+ graph = rx.PyGraph()
295
+ graph.add_nodes_from(terms)
296
+ indexed_nodes = list(enumerate(graph.nodes()))
297
+ for (idx1, (_, ind1, _)), (idx2, (_, ind2, _)) in combinations(indexed_nodes, 2):
298
+ # Add an edge between two terms if they touch the same qubit
299
+ if len(set(ind1).intersection(ind2)) > 0:
300
+ graph.add_edge(idx1, idx2, None)
301
+
302
+ # rx.graph_greedy_color is supposed to be deterministic
303
+ coloring = rx.graph_greedy_color(graph, strategy=strategy)
304
+ terms_by_color = defaultdict(list)
305
+
306
+ for term_idx, color in sorted(coloring.items()):
307
+ term = graph.nodes()[term_idx]
308
+ terms_by_color[color].append(term)
309
+
310
+ terms = list(itertools.chain(*terms_by_color.values()))
311
+ return terms
@@ -16,14 +16,19 @@ from __future__ import annotations
16
16
 
17
17
  import inspect
18
18
  import math
19
+ import typing
20
+ from itertools import chain
19
21
  from collections.abc import Callable
20
22
  import numpy as np
21
23
  from qiskit.circuit.quantumcircuit import QuantumCircuit
22
24
  from qiskit.quantum_info.operators import SparsePauliOp, Pauli
23
25
  from qiskit.utils.deprecation import deprecate_arg
26
+ from qiskit.exceptions import QiskitError
24
27
 
25
- from .product_formula import ProductFormula
26
- from .lie_trotter import LieTrotter
28
+ from .product_formula import ProductFormula, reorder_paulis
29
+
30
+ if typing.TYPE_CHECKING:
31
+ from qiskit.circuit.library import PauliEvolutionGate
27
32
 
28
33
 
29
34
  class QDrift(ProductFormula):
@@ -63,6 +68,7 @@ class QDrift(ProductFormula):
63
68
  ) = None,
64
69
  seed: int | None = None,
65
70
  wrap: bool = False,
71
+ preserve_order: bool = True,
66
72
  ) -> None:
67
73
  r"""
68
74
  Args:
@@ -83,49 +89,50 @@ class QDrift(ProductFormula):
83
89
  seed: An optional seed for reproducibility of the random sampling process.
84
90
  wrap: Whether to wrap the atomic evolutions into custom gate objects. This only takes
85
91
  effect when ``atomic_evolution is None``.
92
+ preserve_order: If ``False``, allows reordering the terms of the operator to
93
+ potentially yield a shallower evolution circuit. Not relevant
94
+ when synthesizing operator with a single term.
86
95
  """
87
- super().__init__(1, reps, insert_barriers, cx_structure, atomic_evolution, wrap)
96
+ super().__init__(
97
+ 1, reps, insert_barriers, cx_structure, atomic_evolution, wrap, preserve_order
98
+ )
88
99
  self.sampled_ops = None
89
100
  self.rng = np.random.default_rng(seed)
90
101
 
91
- def synthesize(self, evolution):
92
- # get operators and time to evolve
102
+ def expand(self, evolution: PauliEvolutionGate) -> list[tuple[str, tuple[int], float]]:
93
103
  operators = evolution.operator
94
- time = evolution.time
104
+ time = evolution.time # used to determine the number of gates
95
105
 
96
- if not isinstance(operators, list):
97
- pauli_list = [(Pauli(op), coeff) for op, coeff in operators.to_list()]
98
- coeffs = [np.real(coeff) for op, coeff in operators.to_list()]
106
+ # QDrift is based on first-order Lie-Trotter, hence we can just concatenate all
107
+ # Pauli terms and ignore commutations
108
+ if isinstance(operators, list):
109
+ paulis = list(chain.from_iterable([op.to_sparse_list() for op in operators]))
99
110
  else:
100
- pauli_list = [(op, 1) for op in operators]
101
- coeffs = [1 for op in operators]
111
+ paulis = operators.to_sparse_list()
112
+
113
+ try:
114
+ coeffs = [float(np.real_if_close(coeff)) for _, _, coeff in paulis]
115
+ except TypeError as exc:
116
+ raise QiskitError("QDrift requires bound, real coefficients.") from exc
102
117
 
103
118
  # We artificially make the weights positive
104
119
  weights = np.abs(coeffs)
105
120
  lambd = np.sum(weights)
106
121
 
107
122
  num_gates = math.ceil(2 * (lambd**2) * (time**2) * self.reps)
123
+
108
124
  # The protocol calls for the removal of the individual coefficients,
109
125
  # and multiplication by a constant evolution time.
110
- evolution_time = lambd * time / num_gates
111
-
112
- self.sampled_ops = self.rng.choice(
113
- np.array(pauli_list, dtype=object),
114
- size=(num_gates,),
115
- p=weights / lambd,
126
+ sampled = self.rng.choice(
127
+ np.array(paulis, dtype=object), size=(num_gates,), p=weights / lambd
116
128
  )
117
129
 
118
- # pylint: disable=cyclic-import
119
- from qiskit.circuit.library.pauli_evolution import PauliEvolutionGate
130
+ rescaled_time = 2 * lambd / num_gates * time
131
+ sampled_paulis = [
132
+ (pauli[0], pauli[1], np.real(np.sign(pauli[2])) * rescaled_time) for pauli in sampled
133
+ ]
120
134
 
121
- # Build the evolution circuit using the LieTrotter synthesis with the sampled operators
122
- lie_trotter = LieTrotter(
123
- insert_barriers=self.insert_barriers, atomic_evolution=self.atomic_evolution
124
- )
125
- evolution_circuit = PauliEvolutionGate(
126
- sum(SparsePauliOp(np.sign(coeff) * op) for op, coeff in self.sampled_ops),
127
- time=evolution_time,
128
- synthesis=lie_trotter,
129
- ).definition
135
+ if not self.preserve_order:
136
+ sampled_paulis = reorder_paulis(sampled_paulis)
130
137
 
131
- return evolution_circuit
138
+ return sampled_paulis