qiskit 1.3.0__cp39-abi3-win32.whl → 1.3.0b1__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 (361) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/__init__.py +1 -20
  3. qiskit/_accelerate.pyd +0 -0
  4. qiskit/assembler/assemble_schedules.py +0 -2
  5. qiskit/circuit/__init__.py +1 -44
  6. qiskit/circuit/_standard_gates_commutations.py +0 -585
  7. qiskit/circuit/barrier.py +0 -2
  8. qiskit/circuit/controlflow/builder.py +3 -3
  9. qiskit/circuit/controlflow/if_else.py +5 -13
  10. qiskit/circuit/controlflow/while_loop.py +2 -10
  11. qiskit/circuit/delay.py +3 -20
  12. qiskit/circuit/equivalence.py +214 -13
  13. qiskit/circuit/gate.py +1 -3
  14. qiskit/circuit/instruction.py +11 -32
  15. qiskit/circuit/instructionset.py +0 -2
  16. qiskit/circuit/library/__init__.py +14 -110
  17. qiskit/circuit/library/arithmetic/__init__.py +2 -9
  18. qiskit/circuit/library/arithmetic/adders/__init__.py +0 -1
  19. qiskit/circuit/library/arithmetic/adders/adder.py +2 -154
  20. qiskit/circuit/library/arithmetic/adders/cdkm_ripple_carry_adder.py +56 -20
  21. qiskit/circuit/library/arithmetic/adders/draper_qft_adder.py +1 -14
  22. qiskit/circuit/library/arithmetic/adders/vbe_ripple_carry_adder.py +91 -21
  23. qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +1 -1
  24. qiskit/circuit/library/arithmetic/multipliers/__init__.py +0 -1
  25. qiskit/circuit/library/arithmetic/multipliers/hrs_cumulative_multiplier.py +1 -8
  26. qiskit/circuit/library/arithmetic/multipliers/multiplier.py +3 -94
  27. qiskit/circuit/library/arithmetic/multipliers/rg_qft_multiplier.py +1 -8
  28. qiskit/circuit/library/arithmetic/weighted_adder.py +1 -1
  29. qiskit/circuit/library/basis_change/qft.py +38 -20
  30. qiskit/circuit/library/blueprintcircuit.py +0 -64
  31. qiskit/circuit/library/boolean_logic/__init__.py +4 -4
  32. qiskit/circuit/library/boolean_logic/inner_product.py +4 -81
  33. qiskit/circuit/library/boolean_logic/quantum_and.py +4 -107
  34. qiskit/circuit/library/boolean_logic/quantum_or.py +3 -107
  35. qiskit/circuit/library/boolean_logic/quantum_xor.py +3 -97
  36. qiskit/circuit/library/data_preparation/__init__.py +3 -6
  37. qiskit/circuit/library/data_preparation/pauli_feature_map.py +29 -342
  38. qiskit/circuit/library/data_preparation/{_z_feature_map.py → z_feature_map.py} +34 -45
  39. qiskit/circuit/library/data_preparation/zz_feature_map.py +118 -0
  40. qiskit/circuit/library/fourier_checking.py +11 -72
  41. qiskit/circuit/library/generalized_gates/__init__.py +1 -1
  42. qiskit/circuit/library/generalized_gates/diagonal.py +51 -45
  43. qiskit/circuit/library/generalized_gates/gms.py +14 -67
  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 +6 -12
  47. qiskit/circuit/library/generalized_gates/mcmt.py +107 -167
  48. qiskit/circuit/library/generalized_gates/permutation.py +6 -8
  49. qiskit/circuit/library/generalized_gates/rv.py +9 -8
  50. qiskit/circuit/library/graph_state.py +10 -93
  51. qiskit/circuit/library/grover_operator.py +2 -270
  52. qiskit/circuit/library/hidden_linear_function.py +20 -83
  53. qiskit/circuit/library/iqp.py +20 -99
  54. qiskit/circuit/library/n_local/__init__.py +7 -19
  55. qiskit/circuit/library/n_local/efficient_su2.py +5 -118
  56. qiskit/circuit/library/n_local/evolved_operator_ansatz.py +0 -259
  57. qiskit/circuit/library/n_local/excitation_preserving.py +6 -130
  58. qiskit/circuit/library/n_local/n_local.py +5 -406
  59. qiskit/circuit/library/n_local/pauli_two_design.py +4 -106
  60. qiskit/circuit/library/n_local/qaoa_ansatz.py +1 -80
  61. qiskit/circuit/library/n_local/real_amplitudes.py +7 -127
  62. qiskit/circuit/library/n_local/two_local.py +7 -14
  63. qiskit/circuit/library/overlap.py +26 -91
  64. qiskit/circuit/library/pauli_evolution.py +15 -17
  65. qiskit/circuit/library/phase_estimation.py +4 -80
  66. qiskit/circuit/library/quantum_volume.py +20 -72
  67. qiskit/circuit/library/standard_gates/__init__.py +1 -20
  68. qiskit/circuit/library/standard_gates/dcx.py +1 -2
  69. qiskit/circuit/library/standard_gates/ecr.py +2 -2
  70. qiskit/circuit/library/standard_gates/h.py +3 -4
  71. qiskit/circuit/library/standard_gates/i.py +1 -2
  72. qiskit/circuit/library/standard_gates/iswap.py +2 -2
  73. qiskit/circuit/library/standard_gates/p.py +12 -20
  74. qiskit/circuit/library/standard_gates/r.py +1 -1
  75. qiskit/circuit/library/standard_gates/rx.py +3 -4
  76. qiskit/circuit/library/standard_gates/rxx.py +2 -2
  77. qiskit/circuit/library/standard_gates/ry.py +3 -4
  78. qiskit/circuit/library/standard_gates/ryy.py +2 -2
  79. qiskit/circuit/library/standard_gates/rz.py +12 -13
  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 +3 -4
  85. qiskit/circuit/library/standard_gates/t.py +2 -2
  86. qiskit/circuit/library/standard_gates/u.py +3 -11
  87. qiskit/circuit/library/standard_gates/u1.py +15 -65
  88. qiskit/circuit/library/standard_gates/u2.py +1 -4
  89. qiskit/circuit/library/standard_gates/u3.py +3 -31
  90. qiskit/circuit/library/standard_gates/x.py +5 -7
  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 +3 -4
  94. qiskit/circuit/library/standard_gates/z.py +3 -3
  95. qiskit/circuit/library/templates/clifford/clifford_2_1.py +8 -9
  96. qiskit/circuit/library/templates/clifford/clifford_2_2.py +9 -10
  97. qiskit/circuit/library/templates/clifford/clifford_2_3.py +7 -9
  98. qiskit/circuit/library/templates/clifford/clifford_2_4.py +8 -9
  99. qiskit/circuit/library/templates/clifford/clifford_3_1.py +8 -9
  100. qiskit/circuit/library/templates/clifford/clifford_4_1.py +9 -10
  101. qiskit/circuit/library/templates/clifford/clifford_4_2.py +9 -10
  102. qiskit/circuit/library/templates/clifford/clifford_4_3.py +9 -10
  103. qiskit/circuit/library/templates/clifford/clifford_4_4.py +9 -10
  104. qiskit/circuit/library/templates/clifford/clifford_5_1.py +9 -10
  105. qiskit/circuit/library/templates/clifford/clifford_6_1.py +9 -10
  106. qiskit/circuit/library/templates/clifford/clifford_6_2.py +9 -10
  107. qiskit/circuit/library/templates/clifford/clifford_6_3.py +9 -10
  108. qiskit/circuit/library/templates/clifford/clifford_6_4.py +8 -9
  109. qiskit/circuit/library/templates/clifford/clifford_6_5.py +9 -10
  110. qiskit/circuit/library/templates/clifford/clifford_8_1.py +9 -10
  111. qiskit/circuit/library/templates/clifford/clifford_8_2.py +9 -10
  112. qiskit/circuit/library/templates/clifford/clifford_8_3.py +9 -10
  113. qiskit/circuit/library/templates/nct/template_nct_2a_1.py +7 -9
  114. qiskit/circuit/library/templates/nct/template_nct_2a_2.py +8 -10
  115. qiskit/circuit/library/templates/nct/template_nct_2a_3.py +10 -12
  116. qiskit/circuit/library/templates/nct/template_nct_4a_1.py +14 -16
  117. qiskit/circuit/library/templates/nct/template_nct_4a_2.py +12 -14
  118. qiskit/circuit/library/templates/nct/template_nct_4a_3.py +10 -12
  119. qiskit/circuit/library/templates/nct/template_nct_4b_1.py +12 -14
  120. qiskit/circuit/library/templates/nct/template_nct_4b_2.py +10 -12
  121. qiskit/circuit/library/templates/nct/template_nct_5a_1.py +10 -12
  122. qiskit/circuit/library/templates/nct/template_nct_5a_2.py +10 -12
  123. qiskit/circuit/library/templates/nct/template_nct_5a_3.py +10 -12
  124. qiskit/circuit/library/templates/nct/template_nct_5a_4.py +9 -11
  125. qiskit/circuit/library/templates/nct/template_nct_6a_1.py +9 -11
  126. qiskit/circuit/library/templates/nct/template_nct_6a_2.py +10 -12
  127. qiskit/circuit/library/templates/nct/template_nct_6a_3.py +10 -12
  128. qiskit/circuit/library/templates/nct/template_nct_6a_4.py +10 -12
  129. qiskit/circuit/library/templates/nct/template_nct_6b_1.py +10 -12
  130. qiskit/circuit/library/templates/nct/template_nct_6b_2.py +10 -12
  131. qiskit/circuit/library/templates/nct/template_nct_6c_1.py +10 -12
  132. qiskit/circuit/library/templates/nct/template_nct_7a_1.py +11 -13
  133. qiskit/circuit/library/templates/nct/template_nct_7b_1.py +11 -13
  134. qiskit/circuit/library/templates/nct/template_nct_7c_1.py +11 -13
  135. qiskit/circuit/library/templates/nct/template_nct_7d_1.py +11 -13
  136. qiskit/circuit/library/templates/nct/template_nct_7e_1.py +11 -13
  137. qiskit/circuit/library/templates/nct/template_nct_9a_1.py +11 -13
  138. qiskit/circuit/library/templates/nct/template_nct_9c_1.py +9 -11
  139. qiskit/circuit/library/templates/nct/template_nct_9c_10.py +10 -12
  140. qiskit/circuit/library/templates/nct/template_nct_9c_11.py +10 -12
  141. qiskit/circuit/library/templates/nct/template_nct_9c_12.py +10 -12
  142. qiskit/circuit/library/templates/nct/template_nct_9c_2.py +10 -12
  143. qiskit/circuit/library/templates/nct/template_nct_9c_3.py +10 -12
  144. qiskit/circuit/library/templates/nct/template_nct_9c_4.py +10 -12
  145. qiskit/circuit/library/templates/nct/template_nct_9c_5.py +10 -12
  146. qiskit/circuit/library/templates/nct/template_nct_9c_6.py +10 -12
  147. qiskit/circuit/library/templates/nct/template_nct_9c_7.py +10 -12
  148. qiskit/circuit/library/templates/nct/template_nct_9c_8.py +10 -12
  149. qiskit/circuit/library/templates/nct/template_nct_9c_9.py +10 -12
  150. qiskit/circuit/library/templates/nct/template_nct_9d_1.py +9 -11
  151. qiskit/circuit/library/templates/nct/template_nct_9d_10.py +10 -12
  152. qiskit/circuit/library/templates/nct/template_nct_9d_2.py +10 -12
  153. qiskit/circuit/library/templates/nct/template_nct_9d_3.py +10 -12
  154. qiskit/circuit/library/templates/nct/template_nct_9d_4.py +10 -12
  155. qiskit/circuit/library/templates/nct/template_nct_9d_5.py +10 -12
  156. qiskit/circuit/library/templates/nct/template_nct_9d_6.py +10 -12
  157. qiskit/circuit/library/templates/nct/template_nct_9d_7.py +10 -12
  158. qiskit/circuit/library/templates/nct/template_nct_9d_8.py +10 -12
  159. qiskit/circuit/library/templates/nct/template_nct_9d_9.py +10 -12
  160. qiskit/circuit/library/templates/rzx/rzx_cy.py +10 -11
  161. qiskit/circuit/library/templates/rzx/rzx_xz.py +15 -16
  162. qiskit/circuit/library/templates/rzx/rzx_yz.py +10 -12
  163. qiskit/circuit/library/templates/rzx/rzx_zz1.py +20 -22
  164. qiskit/circuit/library/templates/rzx/rzx_zz2.py +15 -16
  165. qiskit/circuit/library/templates/rzx/rzx_zz3.py +15 -17
  166. qiskit/circuit/parameter.py +0 -4
  167. qiskit/circuit/parameterexpression.py +34 -167
  168. qiskit/circuit/quantumcircuit.py +126 -162
  169. qiskit/circuit/singleton.py +0 -2
  170. qiskit/circuit/store.py +0 -2
  171. qiskit/compiler/assembler.py +4 -17
  172. qiskit/compiler/scheduler.py +0 -2
  173. qiskit/compiler/sequencer.py +0 -2
  174. qiskit/compiler/transpiler.py +26 -81
  175. qiskit/converters/circuit_to_dag.py +2 -2
  176. qiskit/converters/circuit_to_dagdependency.py +1 -1
  177. qiskit/converters/circuit_to_dagdependency_v2.py +1 -1
  178. qiskit/converters/circuit_to_instruction.py +1 -1
  179. qiskit/converters/dag_to_circuit.py +5 -7
  180. qiskit/converters/dag_to_dagdependency.py +1 -1
  181. qiskit/converters/dag_to_dagdependency_v2.py +1 -1
  182. qiskit/converters/dagdependency_to_circuit.py +1 -5
  183. qiskit/converters/dagdependency_to_dag.py +1 -6
  184. qiskit/dagcircuit/collect_blocks.py +3 -3
  185. qiskit/dagcircuit/dagdependency.py +5 -18
  186. qiskit/dagcircuit/dagdependency_v2.py +1 -1
  187. qiskit/dagcircuit/dagnode.py +2 -2
  188. qiskit/passmanager/__init__.py +2 -2
  189. qiskit/primitives/backend_estimator.py +2 -5
  190. qiskit/primitives/backend_sampler_v2.py +18 -61
  191. qiskit/primitives/base/base_estimator.py +2 -2
  192. qiskit/primitives/containers/data_bin.py +1 -9
  193. qiskit/primitives/statevector_sampler.py +1 -1
  194. qiskit/primitives/utils.py +1 -1
  195. qiskit/providers/__init__.py +3 -3
  196. qiskit/providers/backend.py +1 -12
  197. qiskit/providers/backend_compat.py +3 -23
  198. qiskit/providers/basic_provider/basic_simulator.py +2 -12
  199. qiskit/providers/fake_provider/fake_pulse_backend.py +1 -6
  200. qiskit/providers/fake_provider/generic_backend_v2.py +30 -46
  201. qiskit/providers/models/pulsedefaults.py +0 -2
  202. qiskit/pulse/builder.py +18 -59
  203. qiskit/pulse/calibration_entries.py +1 -4
  204. qiskit/pulse/channels.py +0 -2
  205. qiskit/pulse/exceptions.py +0 -2
  206. qiskit/pulse/instruction_schedule_map.py +6 -21
  207. qiskit/pulse/instructions/acquire.py +0 -2
  208. qiskit/pulse/instructions/delay.py +0 -2
  209. qiskit/pulse/instructions/directives.py +0 -8
  210. qiskit/pulse/instructions/frequency.py +0 -3
  211. qiskit/pulse/instructions/instruction.py +0 -2
  212. qiskit/pulse/instructions/phase.py +0 -3
  213. qiskit/pulse/instructions/play.py +0 -2
  214. qiskit/pulse/instructions/reference.py +0 -2
  215. qiskit/pulse/instructions/snapshot.py +0 -2
  216. qiskit/pulse/library/pulse.py +0 -2
  217. qiskit/pulse/library/symbolic_pulses.py +0 -28
  218. qiskit/pulse/library/waveform.py +0 -2
  219. qiskit/pulse/macros.py +1 -1
  220. qiskit/pulse/schedule.py +13 -12
  221. qiskit/pulse/transforms/alignments.py +3 -5
  222. qiskit/pulse/transforms/dag.py +0 -7
  223. qiskit/qasm2/export.py +3 -5
  224. qiskit/qasm2/parse.py +2 -46
  225. qiskit/qasm3/__init__.py +0 -1
  226. qiskit/qasm3/ast.py +15 -123
  227. qiskit/qasm3/exporter.py +77 -103
  228. qiskit/qobj/converters/pulse_instruction.py +4 -6
  229. qiskit/qpy/__init__.py +0 -181
  230. qiskit/qpy/binary_io/circuits.py +5 -20
  231. qiskit/qpy/binary_io/schedules.py +4 -3
  232. qiskit/qpy/binary_io/value.py +13 -310
  233. qiskit/qpy/common.py +2 -46
  234. qiskit/qpy/formats.py +0 -7
  235. qiskit/qpy/interface.py +4 -40
  236. qiskit/quantum_info/__init__.py +0 -4
  237. qiskit/quantum_info/operators/channel/transformations.py +21 -28
  238. qiskit/quantum_info/operators/dihedral/dihedral.py +1 -1
  239. qiskit/quantum_info/operators/operator.py +8 -54
  240. qiskit/quantum_info/operators/symplectic/base_pauli.py +19 -11
  241. qiskit/quantum_info/operators/symplectic/clifford.py +1 -1
  242. qiskit/quantum_info/operators/symplectic/clifford_circuits.py +1 -1
  243. qiskit/quantum_info/operators/symplectic/pauli.py +0 -2
  244. qiskit/quantum_info/operators/symplectic/pauli_list.py +4 -4
  245. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +2 -23
  246. qiskit/quantum_info/states/densitymatrix.py +5 -5
  247. qiskit/quantum_info/states/stabilizerstate.py +1 -1
  248. qiskit/quantum_info/states/statevector.py +6 -6
  249. qiskit/result/mitigation/base_readout_mitigator.py +1 -1
  250. qiskit/result/mitigation/correlated_readout_mitigator.py +1 -9
  251. qiskit/result/mitigation/local_readout_mitigator.py +1 -9
  252. qiskit/result/mitigation/utils.py +0 -57
  253. qiskit/scheduler/config.py +0 -2
  254. qiskit/scheduler/methods/basic.py +0 -3
  255. qiskit/scheduler/schedule_circuit.py +0 -2
  256. qiskit/scheduler/sequence.py +0 -2
  257. qiskit/synthesis/__init__.py +0 -25
  258. qiskit/synthesis/clifford/clifford_decompose_bm.py +2 -1
  259. qiskit/synthesis/clifford/clifford_decompose_greedy.py +2 -3
  260. qiskit/synthesis/clifford/clifford_decompose_layers.py +1 -2
  261. qiskit/synthesis/evolution/__init__.py +0 -1
  262. qiskit/synthesis/evolution/lie_trotter.py +42 -16
  263. qiskit/synthesis/evolution/product_formula.py +238 -165
  264. qiskit/synthesis/evolution/qdrift.py +29 -36
  265. qiskit/synthesis/evolution/suzuki_trotter.py +27 -87
  266. qiskit/synthesis/multi_controlled/__init__.py +0 -1
  267. qiskit/synthesis/qft/qft_decompose_full.py +1 -19
  268. qiskit/synthesis/qft/qft_decompose_lnn.py +1 -2
  269. qiskit/synthesis/stabilizer/stabilizer_decompose.py +1 -2
  270. qiskit/synthesis/two_qubit/two_qubit_decompose.py +63 -4
  271. qiskit/synthesis/two_qubit/weyl.py +97 -0
  272. qiskit/synthesis/unitary/qsd.py +5 -5
  273. qiskit/transpiler/__init__.py +14 -21
  274. qiskit/transpiler/basepasses.py +1 -1
  275. qiskit/transpiler/passes/__init__.py +0 -2
  276. qiskit/transpiler/passes/basis/basis_translator.py +565 -9
  277. qiskit/transpiler/passes/basis/decompose.py +12 -45
  278. qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
  279. qiskit/transpiler/passes/basis/unroll_custom_definitions.py +1 -1
  280. qiskit/transpiler/passes/calibration/pulse_gate.py +2 -4
  281. qiskit/transpiler/passes/calibration/rx_builder.py +7 -11
  282. qiskit/transpiler/passes/calibration/rzx_builder.py +30 -46
  283. qiskit/transpiler/passes/layout/disjoint_utils.py +13 -15
  284. qiskit/transpiler/passes/layout/sabre_layout.py +2 -7
  285. qiskit/transpiler/passes/layout/sabre_pre_layout.py +0 -5
  286. qiskit/transpiler/passes/optimization/__init__.py +0 -1
  287. qiskit/transpiler/passes/optimization/collect_cliffords.py +3 -19
  288. qiskit/transpiler/passes/optimization/collect_linear_functions.py +1 -1
  289. qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +2 -2
  290. qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py +1 -1
  291. qiskit/transpiler/passes/optimization/consolidate_blocks.py +131 -48
  292. qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py +2 -4
  293. qiskit/transpiler/passes/optimization/elide_permutations.py +32 -9
  294. qiskit/transpiler/passes/optimization/inverse_cancellation.py +0 -2
  295. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +11 -5
  296. qiskit/transpiler/passes/optimization/optimize_1q_gates.py +1 -1
  297. qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py +1 -1
  298. qiskit/transpiler/passes/optimization/template_matching/backward_match.py +5 -5
  299. qiskit/transpiler/passes/optimization/template_matching/forward_match.py +4 -4
  300. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +2 -2
  301. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +1 -1
  302. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/swap_strategy.py +1 -1
  303. qiskit/transpiler/passes/routing/sabre_swap.py +3 -7
  304. qiskit/transpiler/passes/routing/star_prerouting.py +2 -2
  305. qiskit/transpiler/passes/scheduling/alap.py +1 -1
  306. qiskit/transpiler/passes/scheduling/alignments/align_measures.py +2 -2
  307. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
  308. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +0 -2
  309. qiskit/transpiler/passes/scheduling/alignments/reschedule.py +2 -2
  310. qiskit/transpiler/passes/scheduling/asap.py +1 -1
  311. qiskit/transpiler/passes/scheduling/base_scheduler.py +12 -14
  312. qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +4 -9
  313. qiskit/transpiler/passes/scheduling/padding/base_padding.py +1 -1
  314. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +5 -16
  315. qiskit/transpiler/passes/scheduling/padding/pad_delay.py +1 -4
  316. qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +2 -6
  317. qiskit/transpiler/passes/scheduling/time_unit_conversion.py +4 -9
  318. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +99 -262
  319. qiskit/transpiler/passes/synthesis/hls_plugins.py +7 -638
  320. qiskit/transpiler/passes/synthesis/qubit_tracker.py +132 -0
  321. qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +3 -3
  322. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +34 -55
  323. qiskit/transpiler/passes/utils/barrier_before_final_measurements.py +56 -2
  324. qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +0 -5
  325. qiskit/transpiler/passes/utils/gate_direction.py +275 -12
  326. qiskit/transpiler/passes/utils/gates_basis.py +30 -7
  327. qiskit/transpiler/passes/utils/merge_adjacent_barriers.py +1 -2
  328. qiskit/transpiler/passmanager_config.py +4 -22
  329. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +14 -40
  330. qiskit/transpiler/preset_passmanagers/common.py +3 -5
  331. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +42 -125
  332. qiskit/transpiler/preset_passmanagers/plugin.py +1 -1
  333. qiskit/transpiler/target.py +16 -74
  334. qiskit/visualization/circuit/_utils.py +2 -2
  335. qiskit/visualization/circuit/circuit_visualization.py +2 -3
  336. qiskit/visualization/circuit/matplotlib.py +1 -1
  337. qiskit/visualization/dag_visualization.py +1 -1
  338. qiskit/visualization/pass_manager_visualization.py +14 -3
  339. qiskit/visualization/pulse_v2/interface.py +1 -3
  340. qiskit/visualization/timeline/core.py +2 -25
  341. qiskit/visualization/timeline/interface.py +0 -12
  342. {qiskit-1.3.0.dist-info → qiskit-1.3.0b1.dist-info}/METADATA +19 -20
  343. {qiskit-1.3.0.dist-info → qiskit-1.3.0b1.dist-info}/RECORD +347 -358
  344. {qiskit-1.3.0.dist-info → qiskit-1.3.0b1.dist-info}/WHEEL +1 -1
  345. {qiskit-1.3.0.dist-info → qiskit-1.3.0b1.dist-info}/entry_points.txt +0 -19
  346. qiskit/circuit/library/data_preparation/_zz_feature_map.py +0 -150
  347. qiskit/circuit/twirling.py +0 -145
  348. qiskit/synthesis/arithmetic/__init__.py +0 -16
  349. qiskit/synthesis/arithmetic/adders/__init__.py +0 -17
  350. qiskit/synthesis/arithmetic/adders/cdkm_ripple_carry_adder.py +0 -154
  351. qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +0 -103
  352. qiskit/synthesis/arithmetic/adders/vbe_ripple_carry_adder.py +0 -161
  353. qiskit/synthesis/arithmetic/multipliers/__init__.py +0 -16
  354. qiskit/synthesis/arithmetic/multipliers/hrs_cumulative_multiplier.py +0 -102
  355. qiskit/synthesis/arithmetic/multipliers/rg_qft_multiplier.py +0 -99
  356. qiskit/synthesis/evolution/pauli_network.py +0 -80
  357. qiskit/synthesis/multi_controlled/mcmt_vchain.py +0 -52
  358. qiskit/transpiler/passes/optimization/remove_identity_equiv.py +0 -69
  359. qiskit/utils/deprecate_pulse.py +0 -119
  360. {qiskit-1.3.0.dist-info → qiskit-1.3.0b1.dist-info}/LICENSE.txt +0 -0
  361. {qiskit-1.3.0.dist-info → qiskit-1.3.0b1.dist-info}/top_level.txt +0 -0
@@ -13,12 +13,29 @@
13
13
 
14
14
  """Translates gates to a target basis using a given equivalence library."""
15
15
 
16
+ import time
16
17
  import logging
17
18
 
19
+ from functools import singledispatchmethod
20
+ from itertools import zip_longest
18
21
  from collections import defaultdict
19
22
 
23
+ import rustworkx
24
+
25
+ from qiskit.circuit import (
26
+ Gate,
27
+ ParameterVector,
28
+ QuantumRegister,
29
+ ControlFlowOp,
30
+ QuantumCircuit,
31
+ ParameterExpression,
32
+ )
33
+ from qiskit.dagcircuit import DAGCircuit, DAGOpNode
34
+ from qiskit.converters import circuit_to_dag, dag_to_circuit
35
+ from qiskit.circuit.equivalence import Key, NodeData
20
36
  from qiskit.transpiler.basepasses import TransformationPass
21
- from qiskit._accelerate.basis.basis_translator import base_run
37
+ from qiskit.transpiler.exceptions import TranspilerError
38
+ from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES
22
39
 
23
40
  logger = logging.getLogger(__name__)
24
41
 
@@ -125,13 +142,552 @@ class BasisTranslator(TransformationPass):
125
142
  Returns:
126
143
  DAGCircuit: translated circuit.
127
144
  """
145
+ if self._target_basis is None and self._target is None:
146
+ return dag
147
+
148
+ qarg_indices = {qubit: index for index, qubit in enumerate(dag.qubits)}
149
+
150
+ # Names of instructions assumed to supported by any backend.
151
+ if self._target is None:
152
+ basic_instrs = ["measure", "reset", "barrier", "snapshot", "delay", "store"]
153
+ target_basis = set(self._target_basis)
154
+ source_basis = set(self._extract_basis(dag))
155
+ qargs_local_source_basis = {}
156
+ else:
157
+ basic_instrs = ["barrier", "snapshot", "store"]
158
+ target_basis = self._target.keys() - set(self._non_global_operations)
159
+ source_basis, qargs_local_source_basis = self._extract_basis_target(dag, qarg_indices)
160
+
161
+ target_basis = set(target_basis).union(basic_instrs)
162
+ # If the source basis is a subset of the target basis and we have no circuit
163
+ # instructions on qargs that have non-global operations there is nothing to
164
+ # translate and we can exit early.
165
+ source_basis_names = {x[0] for x in source_basis}
166
+ if source_basis_names.issubset(target_basis) and not qargs_local_source_basis:
167
+ return dag
168
+
169
+ logger.info(
170
+ "Begin BasisTranslator from source basis %s to target basis %s.",
171
+ source_basis,
172
+ target_basis,
173
+ )
174
+
175
+ # Search for a path from source to target basis.
176
+ search_start_time = time.time()
177
+ basis_transforms = _basis_search(self._equiv_lib, source_basis, target_basis)
178
+
179
+ qarg_local_basis_transforms = {}
180
+ for qarg, local_source_basis in qargs_local_source_basis.items():
181
+ expanded_target = set(target_basis)
182
+ # For any multiqubit operation that contains a subset of qubits that
183
+ # has a non-local operation, include that non-local operation in the
184
+ # search. This matches with the check we did above to include those
185
+ # subset non-local operations in the check here.
186
+ if len(qarg) > 1:
187
+ for non_local_qarg, local_basis in self._qargs_with_non_global_operation.items():
188
+ if qarg.issuperset(non_local_qarg):
189
+ expanded_target |= local_basis
190
+ else:
191
+ expanded_target |= self._qargs_with_non_global_operation[tuple(qarg)]
192
+
193
+ logger.info(
194
+ "Performing BasisTranslator search from source basis %s to target "
195
+ "basis %s on qarg %s.",
196
+ local_source_basis,
197
+ expanded_target,
198
+ qarg,
199
+ )
200
+ local_basis_transforms = _basis_search(
201
+ self._equiv_lib, local_source_basis, expanded_target
202
+ )
203
+
204
+ if local_basis_transforms is None:
205
+ raise TranspilerError(
206
+ "Unable to translate the operations in the circuit: "
207
+ f"{[x[0] for x in local_source_basis]} to the backend's (or manually "
208
+ f"specified) target basis: {list(expanded_target)}. This likely means the "
209
+ "target basis is not universal or there are additional equivalence rules "
210
+ "needed in the EquivalenceLibrary being used. For more details on this "
211
+ "error see: "
212
+ "https://docs.quantum.ibm.com/api/qiskit/qiskit.transpiler.passes."
213
+ "BasisTranslator#translation-errors"
214
+ )
215
+
216
+ qarg_local_basis_transforms[qarg] = local_basis_transforms
217
+
218
+ search_end_time = time.time()
219
+ logger.info(
220
+ "Basis translation path search completed in %.3fs.", search_end_time - search_start_time
221
+ )
222
+
223
+ if basis_transforms is None:
224
+ raise TranspilerError(
225
+ "Unable to translate the operations in the circuit: "
226
+ f"{[x[0] for x in source_basis]} to the backend's (or manually specified) target "
227
+ f"basis: {list(target_basis)}. This likely means the target basis is not universal "
228
+ "or there are additional equivalence rules needed in the EquivalenceLibrary being "
229
+ "used. For more details on this error see: "
230
+ "https://docs.quantum.ibm.com/api/qiskit/qiskit.transpiler.passes."
231
+ "BasisTranslator#translation-errors"
232
+ )
233
+
234
+ # Compose found path into a set of instruction substitution rules.
235
+
236
+ compose_start_time = time.time()
237
+ instr_map = _compose_transforms(basis_transforms, source_basis, dag)
238
+ extra_instr_map = {
239
+ qarg: _compose_transforms(transforms, qargs_local_source_basis[qarg], dag)
240
+ for qarg, transforms in qarg_local_basis_transforms.items()
241
+ }
242
+
243
+ compose_end_time = time.time()
244
+ logger.info(
245
+ "Basis translation paths composed in %.3fs.", compose_end_time - compose_start_time
246
+ )
247
+
248
+ # Replace source instructions with target translations.
249
+
250
+ replace_start_time = time.time()
251
+
252
+ def apply_translation(dag, wire_map):
253
+ is_updated = False
254
+ out_dag = dag.copy_empty_like()
255
+ for node in dag.topological_op_nodes():
256
+ node_qargs = tuple(wire_map[bit] for bit in node.qargs)
257
+ qubit_set = frozenset(node_qargs)
258
+ if node.name in target_basis or len(node.qargs) < self._min_qubits:
259
+ if node.name in CONTROL_FLOW_OP_NAMES:
260
+ flow_blocks = []
261
+ for block in node.op.blocks:
262
+ dag_block = circuit_to_dag(block)
263
+ updated_dag, is_updated = apply_translation(
264
+ dag_block,
265
+ {
266
+ inner: wire_map[outer]
267
+ for inner, outer in zip(block.qubits, node.qargs)
268
+ },
269
+ )
270
+ if is_updated:
271
+ flow_circ_block = dag_to_circuit(updated_dag)
272
+ else:
273
+ flow_circ_block = block
274
+ flow_blocks.append(flow_circ_block)
275
+ node.op = node.op.replace_blocks(flow_blocks)
276
+ out_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
277
+ continue
278
+ if (
279
+ node_qargs in self._qargs_with_non_global_operation
280
+ and node.name in self._qargs_with_non_global_operation[node_qargs]
281
+ ):
282
+ out_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
283
+ continue
284
+
285
+ if dag.has_calibration_for(node):
286
+ out_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
287
+ continue
288
+ if qubit_set in extra_instr_map:
289
+ self._replace_node(out_dag, node, extra_instr_map[qubit_set])
290
+ elif (node.name, node.num_qubits) in instr_map:
291
+ self._replace_node(out_dag, node, instr_map)
292
+ else:
293
+ raise TranspilerError(f"BasisTranslator did not map {node.name}.")
294
+ is_updated = True
295
+ return out_dag, is_updated
128
296
 
129
- return base_run(
130
- dag,
131
- self._equiv_lib,
132
- self._qargs_with_non_global_operation,
133
- self._min_qubits,
134
- None if self._target_basis is None else set(self._target_basis),
135
- self._target,
136
- None if self._non_global_operations is None else set(self._non_global_operations),
297
+ out_dag, _ = apply_translation(dag, qarg_indices)
298
+ replace_end_time = time.time()
299
+ logger.info(
300
+ "Basis translation instructions replaced in %.3fs.",
301
+ replace_end_time - replace_start_time,
137
302
  )
303
+
304
+ return out_dag
305
+
306
+ def _replace_node(self, dag, node, instr_map):
307
+ target_params, target_dag = instr_map[node.name, node.num_qubits]
308
+ if len(node.params) != len(target_params):
309
+ raise TranspilerError(
310
+ "Translation num_params not equal to op num_params."
311
+ f"Op: {node.params} {node.name} Translation: {target_params}\n{target_dag}"
312
+ )
313
+ if node.params:
314
+ parameter_map = dict(zip(target_params, node.params))
315
+ for inner_node in target_dag.topological_op_nodes():
316
+ new_node = DAGOpNode.from_instruction(inner_node._to_circuit_instruction())
317
+ new_node.qargs = tuple(
318
+ node.qargs[target_dag.find_bit(x).index] for x in inner_node.qargs
319
+ )
320
+ new_node.cargs = tuple(
321
+ node.cargs[target_dag.find_bit(x).index] for x in inner_node.cargs
322
+ )
323
+
324
+ if not new_node.is_standard_gate():
325
+ new_node.op = new_node.op.copy()
326
+ if any(isinstance(x, ParameterExpression) for x in inner_node.params):
327
+ new_params = []
328
+ for param in new_node.params:
329
+ if not isinstance(param, ParameterExpression):
330
+ new_params.append(param)
331
+ else:
332
+ bind_dict = {x: parameter_map[x] for x in param.parameters}
333
+ if any(isinstance(x, ParameterExpression) for x in bind_dict.values()):
334
+ new_value = param
335
+ for x in bind_dict.items():
336
+ new_value = new_value.assign(*x)
337
+ else:
338
+ new_value = param.bind(bind_dict)
339
+ if not new_value.parameters:
340
+ new_value = new_value.numeric()
341
+ new_params.append(new_value)
342
+ new_node.params = new_params
343
+ if not new_node.is_standard_gate():
344
+ new_node.op.params = new_params
345
+ dag._apply_op_node_back(new_node)
346
+
347
+ if isinstance(target_dag.global_phase, ParameterExpression):
348
+ old_phase = target_dag.global_phase
349
+ bind_dict = {x: parameter_map[x] for x in old_phase.parameters}
350
+ if any(isinstance(x, ParameterExpression) for x in bind_dict.values()):
351
+ new_phase = old_phase
352
+ for x in bind_dict.items():
353
+ new_phase = new_phase.assign(*x)
354
+ else:
355
+ new_phase = old_phase.bind(bind_dict)
356
+ if not new_phase.parameters:
357
+ new_phase = new_phase.numeric()
358
+ if isinstance(new_phase, complex):
359
+ raise TranspilerError(f"Global phase must be real, but got '{new_phase}'")
360
+ dag.global_phase += new_phase
361
+
362
+ else:
363
+ for inner_node in target_dag.topological_op_nodes():
364
+ new_node = DAGOpNode.from_instruction(
365
+ inner_node._to_circuit_instruction(),
366
+ )
367
+ new_node.qargs = tuple(
368
+ node.qargs[target_dag.find_bit(x).index] for x in inner_node.qargs
369
+ )
370
+ new_node.cargs = tuple(
371
+ node.cargs[target_dag.find_bit(x).index] for x in inner_node.cargs
372
+ )
373
+ if not new_node.is_standard_gate:
374
+ new_node.op = new_node.op.copy()
375
+ # dag_op may be the same instance as other ops in the dag,
376
+ # so if there is a condition, need to copy
377
+ if getattr(node.op, "condition", None):
378
+ new_node_op = new_node.op.to_mutable()
379
+ new_node_op.condition = node.op.condition
380
+ new_node.op = new_node_op
381
+ dag._apply_op_node_back(new_node)
382
+ if target_dag.global_phase:
383
+ dag.global_phase += target_dag.global_phase
384
+
385
+ @singledispatchmethod
386
+ def _extract_basis(self, circuit):
387
+ return circuit
388
+
389
+ @_extract_basis.register
390
+ def _(self, dag: DAGCircuit):
391
+ for node in dag.op_nodes():
392
+ if not dag.has_calibration_for(node) and len(node.qargs) >= self._min_qubits:
393
+ yield (node.name, node.num_qubits)
394
+ if node.name in CONTROL_FLOW_OP_NAMES:
395
+ for block in node.op.blocks:
396
+ yield from self._extract_basis(block)
397
+
398
+ @_extract_basis.register
399
+ def _(self, circ: QuantumCircuit):
400
+ for instruction in circ.data:
401
+ operation = instruction.operation
402
+ if (
403
+ not circ.has_calibration_for(instruction)
404
+ and len(instruction.qubits) >= self._min_qubits
405
+ ):
406
+ yield (operation.name, operation.num_qubits)
407
+ if isinstance(operation, ControlFlowOp):
408
+ for block in operation.blocks:
409
+ yield from self._extract_basis(block)
410
+
411
+ def _extract_basis_target(
412
+ self, dag, qarg_indices, source_basis=None, qargs_local_source_basis=None
413
+ ):
414
+ if source_basis is None:
415
+ source_basis = set()
416
+ if qargs_local_source_basis is None:
417
+ qargs_local_source_basis = defaultdict(set)
418
+ for node in dag.op_nodes():
419
+ qargs = tuple(qarg_indices[bit] for bit in node.qargs)
420
+ if dag.has_calibration_for(node) or len(node.qargs) < self._min_qubits:
421
+ continue
422
+ # Treat the instruction as on an incomplete basis if the qargs are in the
423
+ # qargs_with_non_global_operation dictionary or if any of the qubits in qargs
424
+ # are a superset for a non-local operation. For example, if the qargs
425
+ # are (0, 1) and that's a global (ie no non-local operations on (0, 1)
426
+ # operation but there is a non-local operation on (1,) we need to
427
+ # do an extra non-local search for this op to ensure we include any
428
+ # single qubit operation for (1,) as valid. This pattern also holds
429
+ # true for > 2q ops too (so for 4q operations we need to check for 3q, 2q,
430
+ # and 1q operations in the same manner)
431
+ if qargs in self._qargs_with_non_global_operation or any(
432
+ frozenset(qargs).issuperset(incomplete_qargs)
433
+ for incomplete_qargs in self._qargs_with_non_global_operation
434
+ ):
435
+ qargs_local_source_basis[frozenset(qargs)].add((node.name, node.num_qubits))
436
+ else:
437
+ source_basis.add((node.name, node.num_qubits))
438
+ if node.name in CONTROL_FLOW_OP_NAMES:
439
+ for block in node.op.blocks:
440
+ block_dag = circuit_to_dag(block)
441
+ source_basis, qargs_local_source_basis = self._extract_basis_target(
442
+ block_dag,
443
+ {
444
+ inner: qarg_indices[outer]
445
+ for inner, outer in zip(block.qubits, node.qargs)
446
+ },
447
+ source_basis=source_basis,
448
+ qargs_local_source_basis=qargs_local_source_basis,
449
+ )
450
+ return source_basis, qargs_local_source_basis
451
+
452
+
453
+ class StopIfBasisRewritable(Exception):
454
+ """Custom exception that signals `rustworkx.dijkstra_search` to stop."""
455
+
456
+
457
+ class BasisSearchVisitor(rustworkx.visit.DijkstraVisitor):
458
+ """Handles events emitted during `rustworkx.dijkstra_search`."""
459
+
460
+ def __init__(self, graph, source_basis, target_basis):
461
+ self.graph = graph
462
+ self.target_basis = set(target_basis)
463
+ self._source_gates_remain = set(source_basis)
464
+ self._num_gates_remain_for_rule = {}
465
+ save_index = -1
466
+ for edata in self.graph.edges():
467
+ if save_index == edata.index:
468
+ continue
469
+ self._num_gates_remain_for_rule[edata.index] = edata.num_gates
470
+ save_index = edata.index
471
+
472
+ self._basis_transforms = []
473
+ self._predecessors = {}
474
+ self._opt_cost_map = {}
475
+
476
+ def discover_vertex(self, v, score):
477
+ gate = self.graph[v].key
478
+ self._source_gates_remain.discard(gate)
479
+ self._opt_cost_map[gate] = score
480
+ rule = self._predecessors.get(gate, None)
481
+ if rule is not None:
482
+ logger.debug(
483
+ "Gate %s generated using rule \n%s\n with total cost of %s.",
484
+ gate.name,
485
+ rule.circuit,
486
+ score,
487
+ )
488
+ self._basis_transforms.append((gate.name, gate.num_qubits, rule.params, rule.circuit))
489
+ # we can stop the search if we have found all gates in the original circuit.
490
+ if not self._source_gates_remain:
491
+ # if we start from source gates and apply `basis_transforms` in reverse order, we'll end
492
+ # up with gates in the target basis. Note though that `basis_transforms` may include
493
+ # additional transformations that are not required to map our source gates to the given
494
+ # target basis.
495
+ self._basis_transforms.reverse()
496
+ raise StopIfBasisRewritable
497
+
498
+ def examine_edge(self, edge):
499
+ _, target, edata = edge
500
+ if edata is None:
501
+ return
502
+
503
+ self._num_gates_remain_for_rule[edata.index] -= 1
504
+
505
+ target = self.graph[target].key
506
+ # if there are gates in this `rule` that we have not yet generated, we can't apply
507
+ # this `rule`. if `target` is already in basis, it's not beneficial to use this rule.
508
+ if self._num_gates_remain_for_rule[edata.index] > 0 or target in self.target_basis:
509
+ raise rustworkx.visit.PruneSearch
510
+
511
+ def edge_relaxed(self, edge):
512
+ _, target, edata = edge
513
+ if edata is not None:
514
+ gate = self.graph[target].key
515
+ self._predecessors[gate] = edata.rule
516
+
517
+ def edge_cost(self, edge_data):
518
+ """Returns the cost of an edge.
519
+
520
+ This function computes the cost of this edge rule by summing
521
+ the costs of all gates in the rule equivalence circuit. In the
522
+ end, we need to subtract the cost of the source since `dijkstra`
523
+ will later add it.
524
+ """
525
+
526
+ if edge_data is None:
527
+ # the target of the edge is a gate in the target basis,
528
+ # so we return a default value of 1.
529
+ return 1
530
+
531
+ cost_tot = 0
532
+ for instruction in edge_data.rule.circuit:
533
+ key = Key(name=instruction.name, num_qubits=len(instruction.qubits))
534
+ cost_tot += self._opt_cost_map[key]
535
+
536
+ return cost_tot - self._opt_cost_map[edge_data.source]
537
+
538
+ @property
539
+ def basis_transforms(self):
540
+ """Returns the gate basis transforms."""
541
+ return self._basis_transforms
542
+
543
+
544
+ def _basis_search(equiv_lib, source_basis, target_basis):
545
+ """Search for a set of transformations from source_basis to target_basis.
546
+
547
+ Args:
548
+ equiv_lib (EquivalenceLibrary): Source of valid translations
549
+ source_basis (Set[Tuple[gate_name: str, gate_num_qubits: int]]): Starting basis.
550
+ target_basis (Set[gate_name: str]): Target basis.
551
+
552
+ Returns:
553
+ Optional[List[Tuple[gate, equiv_params, equiv_circuit]]]: List of (gate,
554
+ equiv_params, equiv_circuit) tuples tuples which, if applied in order
555
+ will map from source_basis to target_basis. Returns None if no path
556
+ was found.
557
+ """
558
+
559
+ logger.debug("Begining basis search from %s to %s.", source_basis, target_basis)
560
+
561
+ source_basis = {
562
+ (gate_name, gate_num_qubits)
563
+ for gate_name, gate_num_qubits in source_basis
564
+ if gate_name not in target_basis
565
+ }
566
+
567
+ # if source basis is empty, no work to be done.
568
+ if not source_basis:
569
+ return []
570
+
571
+ # This is only necessary since gates in target basis are currently reported by
572
+ # their names and we need to have in addition the number of qubits they act on.
573
+ target_basis_keys = [key for key in equiv_lib.keys() if key.name in target_basis]
574
+
575
+ graph = equiv_lib.graph
576
+ vis = BasisSearchVisitor(graph, source_basis, target_basis_keys)
577
+
578
+ # we add a dummy node and connect it with gates in the target basis.
579
+ # we'll start the search from this dummy node.
580
+ dummy = graph.add_node(NodeData(key="key", equivs=[("dummy starting node", 0)]))
581
+
582
+ try:
583
+ graph.add_edges_from_no_data(
584
+ [(dummy, equiv_lib.node_index(key)) for key in target_basis_keys]
585
+ )
586
+ rtn = None
587
+ try:
588
+ rustworkx.digraph_dijkstra_search(graph, [dummy], vis.edge_cost, vis)
589
+ except StopIfBasisRewritable:
590
+ rtn = vis.basis_transforms
591
+
592
+ logger.debug("Transformation path:")
593
+ for gate_name, gate_num_qubits, params, equiv in rtn:
594
+ logger.debug("%s/%s => %s\n%s", gate_name, gate_num_qubits, params, equiv)
595
+ finally:
596
+ # Remove dummy node in order to return graph to original state
597
+ graph.remove_node(dummy)
598
+
599
+ return rtn
600
+
601
+
602
+ def _compose_transforms(basis_transforms, source_basis, source_dag):
603
+ """Compose a set of basis transforms into a set of replacements.
604
+
605
+ Args:
606
+ basis_transforms (List[Tuple[gate_name, params, equiv]]): List of
607
+ transforms to compose.
608
+ source_basis (Set[Tuple[gate_name: str, gate_num_qubits: int]]): Names
609
+ of gates which need to be translated.
610
+ source_dag (DAGCircuit): DAG with example gates from source_basis.
611
+ (Used to determine num_params for gate in source_basis.)
612
+
613
+ Returns:
614
+ Dict[gate_name, Tuple(params, dag)]: Dictionary mapping between each gate
615
+ in source_basis and a DAGCircuit instance to replace it. Gates in
616
+ source_basis but not affected by basis_transforms will be included
617
+ as a key mapping to itself.
618
+ """
619
+ example_gates = _get_example_gates(source_dag)
620
+ mapped_instrs = {}
621
+
622
+ for gate_name, gate_num_qubits in source_basis:
623
+ # Need to grab a gate instance to find num_qubits and num_params.
624
+ # Can be removed following https://github.com/Qiskit/qiskit-terra/pull/3947 .
625
+ example_gate = example_gates[gate_name, gate_num_qubits]
626
+ num_params = len(example_gate.params)
627
+
628
+ placeholder_params = ParameterVector(gate_name, num_params)
629
+ placeholder_gate = Gate(gate_name, gate_num_qubits, list(placeholder_params))
630
+ placeholder_gate.params = list(placeholder_params)
631
+
632
+ dag = DAGCircuit()
633
+ qr = QuantumRegister(gate_num_qubits)
634
+ dag.add_qreg(qr)
635
+ dag.apply_operation_back(placeholder_gate, qr, (), check=False)
636
+ mapped_instrs[gate_name, gate_num_qubits] = placeholder_params, dag
637
+
638
+ for gate_name, gate_num_qubits, equiv_params, equiv in basis_transforms:
639
+ logger.debug(
640
+ "Composing transform step: %s/%s %s =>\n%s",
641
+ gate_name,
642
+ gate_num_qubits,
643
+ equiv_params,
644
+ equiv,
645
+ )
646
+
647
+ for mapped_instr_name, (dag_params, dag) in mapped_instrs.items():
648
+ doomed_nodes = [
649
+ node
650
+ for node in dag.op_nodes()
651
+ if (node.name, node.num_qubits) == (gate_name, gate_num_qubits)
652
+ ]
653
+
654
+ if doomed_nodes and logger.isEnabledFor(logging.DEBUG):
655
+
656
+ logger.debug(
657
+ "Updating transform for mapped instr %s %s from \n%s",
658
+ mapped_instr_name,
659
+ dag_params,
660
+ dag_to_circuit(dag, copy_operations=False),
661
+ )
662
+
663
+ for node in doomed_nodes:
664
+
665
+ replacement = equiv.assign_parameters(dict(zip_longest(equiv_params, node.params)))
666
+
667
+ replacement_dag = circuit_to_dag(replacement)
668
+
669
+ dag.substitute_node_with_dag(node, replacement_dag)
670
+
671
+ if doomed_nodes and logger.isEnabledFor(logging.DEBUG):
672
+
673
+ logger.debug(
674
+ "Updated transform for mapped instr %s %s to\n%s",
675
+ mapped_instr_name,
676
+ dag_params,
677
+ dag_to_circuit(dag, copy_operations=False),
678
+ )
679
+
680
+ return mapped_instrs
681
+
682
+
683
+ def _get_example_gates(source_dag):
684
+ def recurse(dag, example_gates=None):
685
+ example_gates = example_gates or {}
686
+ for node in dag.op_nodes():
687
+ example_gates[(node.name, node.num_qubits)] = node
688
+ if node.name in CONTROL_FLOW_OP_NAMES:
689
+ for block in node.op.blocks:
690
+ example_gates = recurse(circuit_to_dag(block), example_gates)
691
+ return example_gates
692
+
693
+ return recurse(source_dag)
@@ -11,20 +11,13 @@
11
11
  # that they have been altered from the originals.
12
12
 
13
13
  """Expand a gate in a circuit using its decomposition rules."""
14
-
15
- from __future__ import annotations
16
-
17
- from collections.abc import Sequence
18
- from typing import Type
14
+ from typing import Type, Union, List, Optional
19
15
  from fnmatch import fnmatch
20
16
 
21
17
  from qiskit.transpiler.basepasses import TransformationPass
22
- from qiskit.dagcircuit.dagnode import DAGOpNode
23
18
  from qiskit.dagcircuit.dagcircuit import DAGCircuit
24
19
  from qiskit.converters.circuit_to_dag import circuit_to_dag
25
- from qiskit.circuit.instruction import Instruction
26
-
27
- from ..synthesis import HighLevelSynthesis
20
+ from qiskit.circuit.gate import Gate
28
21
 
29
22
 
30
23
  class Decompose(TransformationPass):
@@ -32,21 +25,16 @@ class Decompose(TransformationPass):
32
25
 
33
26
  def __init__(
34
27
  self,
35
- gates_to_decompose: (
36
- str | Type[Instruction] | Sequence[str | Type[Instruction]] | None
37
- ) = None,
38
- apply_synthesis: bool = False,
28
+ gates_to_decompose: Optional[Union[Type[Gate], List[Type[Gate]], List[str], str]] = None,
39
29
  ) -> None:
40
- """
30
+ """Decompose initializer.
31
+
41
32
  Args:
42
33
  gates_to_decompose: optional subset of gates to be decomposed,
43
34
  identified by gate label, name or type. Defaults to all gates.
44
- apply_synthesis: If ``True``, run :class:`.HighLevelSynthesis` to synthesize operations
45
- that do not have a definition attached.
46
35
  """
47
36
  super().__init__()
48
37
  self.gates_to_decompose = gates_to_decompose
49
- self.apply_synthesis = apply_synthesis
50
38
 
51
39
  def run(self, dag: DAGCircuit) -> DAGCircuit:
52
40
  """Run the Decompose pass on `dag`.
@@ -57,26 +45,13 @@ class Decompose(TransformationPass):
57
45
  Returns:
58
46
  output dag where ``gate`` was expanded.
59
47
  """
60
- # We might use HLS to synthesize objects that do not have a definition
61
- hls = HighLevelSynthesis() if self.apply_synthesis else None
62
-
63
48
  # Walk through the DAG and expand each non-basis node
64
49
  for node in dag.op_nodes():
65
- # Check in self.gates_to_decompose if the operation should be decomposed
66
- if not self._should_decompose(node):
67
- continue
68
-
69
- if getattr(node.op, "definition", None) is None:
70
- # if we try to synthesize, turn the node into a DAGCircuit and run HLS
71
- if self.apply_synthesis:
72
- node_as_dag = _node_to_dag(node)
73
- synthesized = hls.run(node_as_dag)
74
- dag.substitute_node_with_dag(node, synthesized)
75
-
76
- # else: no definition and synthesis not enabled, so we do nothing
77
- else:
50
+ if self._should_decompose(node):
51
+ if getattr(node.op, "definition", None) is None:
52
+ continue
53
+ # TODO: allow choosing among multiple decomposition rules
78
54
  rule = node.op.definition.data
79
-
80
55
  if (
81
56
  len(rule) == 1
82
57
  and len(node.qargs) == len(rule[0].qubits) == 1 # to preserve gate order
@@ -91,8 +66,9 @@ class Decompose(TransformationPass):
91
66
 
92
67
  return dag
93
68
 
94
- def _should_decompose(self, node: DAGOpNode) -> bool:
95
- """Call a decomposition pass on this circuit to decompose one level (shallow decompose)."""
69
+ def _should_decompose(self, node) -> bool:
70
+ """Call a decomposition pass on this circuit,
71
+ to decompose one level (shallow decompose)."""
96
72
  if self.gates_to_decompose is None: # check if no gates given
97
73
  return True
98
74
 
@@ -120,12 +96,3 @@ class Decompose(TransformationPass):
120
96
  return True
121
97
  else:
122
98
  return False
123
-
124
-
125
- def _node_to_dag(node: DAGOpNode) -> DAGCircuit:
126
- dag = DAGCircuit()
127
- dag.add_qubits(node.qargs)
128
- dag.add_clbits(node.cargs)
129
-
130
- dag.apply_operation_back(node.op, node.qargs, node.cargs)
131
- return dag