qiskit 1.1.1__cp38-abi3-macosx_10_9_universal2.whl → 1.2.0__cp38-abi3-macosx_10_9_universal2.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 (347) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/__init__.py +27 -24
  3. qiskit/_accelerate.abi3.so +0 -0
  4. qiskit/_numpy_compat.py +1 -1
  5. qiskit/assembler/assemble_circuits.py +107 -64
  6. qiskit/assembler/assemble_schedules.py +5 -12
  7. qiskit/assembler/disassemble.py +10 -1
  8. qiskit/circuit/__init__.py +6 -3
  9. qiskit/circuit/_classical_resource_map.py +5 -5
  10. qiskit/circuit/_utils.py +0 -13
  11. qiskit/circuit/add_control.py +1 -1
  12. qiskit/circuit/annotated_operation.py +23 -1
  13. qiskit/circuit/classical/expr/expr.py +4 -4
  14. qiskit/circuit/classical/expr/visitors.py +1 -1
  15. qiskit/circuit/classical/types/__init__.py +1 -1
  16. qiskit/circuit/classical/types/types.py +2 -2
  17. qiskit/circuit/classicalfunction/__init__.py +8 -0
  18. qiskit/circuit/classicalfunction/boolean_expression.py +1 -1
  19. qiskit/circuit/classicalfunction/classical_function_visitor.py +5 -5
  20. qiskit/circuit/classicalfunction/utils.py +1 -1
  21. qiskit/circuit/classicalregister.py +1 -1
  22. qiskit/circuit/commutation_checker.py +83 -35
  23. qiskit/circuit/controlflow/_builder_utils.py +1 -1
  24. qiskit/circuit/controlflow/builder.py +10 -6
  25. qiskit/circuit/controlflow/if_else.py +2 -2
  26. qiskit/circuit/controlflow/switch_case.py +1 -1
  27. qiskit/circuit/delay.py +1 -1
  28. qiskit/circuit/duration.py +2 -2
  29. qiskit/circuit/equivalence.py +5 -7
  30. qiskit/circuit/gate.py +11 -8
  31. qiskit/circuit/instruction.py +31 -13
  32. qiskit/circuit/instructionset.py +2 -5
  33. qiskit/circuit/library/__init__.py +2 -1
  34. qiskit/circuit/library/arithmetic/linear_amplitude_function.py +1 -1
  35. qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +1 -1
  36. qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +1 -1
  37. qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +1 -1
  38. qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +3 -3
  39. qiskit/circuit/library/arithmetic/polynomial_pauli_rotations.py +1 -1
  40. qiskit/circuit/library/basis_change/__init__.py +1 -1
  41. qiskit/circuit/library/basis_change/qft.py +40 -6
  42. qiskit/circuit/library/blueprintcircuit.py +3 -5
  43. qiskit/circuit/library/data_preparation/__init__.py +9 -2
  44. qiskit/circuit/library/data_preparation/initializer.py +8 -0
  45. qiskit/circuit/library/data_preparation/state_preparation.py +98 -178
  46. qiskit/circuit/library/generalized_gates/isometry.py +8 -8
  47. qiskit/circuit/library/generalized_gates/linear_function.py +3 -2
  48. qiskit/circuit/library/generalized_gates/mcg_up_to_diagonal.py +4 -4
  49. qiskit/circuit/library/generalized_gates/permutation.py +8 -9
  50. qiskit/circuit/library/generalized_gates/uc.py +3 -3
  51. qiskit/circuit/library/generalized_gates/uc_pauli_rot.py +2 -2
  52. qiskit/circuit/library/generalized_gates/unitary.py +13 -11
  53. qiskit/circuit/library/graph_state.py +1 -1
  54. qiskit/circuit/library/hamiltonian_gate.py +1 -2
  55. qiskit/circuit/library/hidden_linear_function.py +1 -1
  56. qiskit/circuit/library/n_local/evolved_operator_ansatz.py +3 -2
  57. qiskit/circuit/library/n_local/n_local.py +4 -5
  58. qiskit/circuit/library/n_local/pauli_two_design.py +1 -1
  59. qiskit/circuit/library/n_local/qaoa_ansatz.py +6 -8
  60. qiskit/circuit/library/n_local/two_local.py +1 -1
  61. qiskit/circuit/library/overlap.py +11 -5
  62. qiskit/circuit/library/pauli_evolution.py +7 -3
  63. qiskit/circuit/library/standard_gates/dcx.py +3 -0
  64. qiskit/circuit/library/standard_gates/ecr.py +3 -0
  65. qiskit/circuit/library/standard_gates/global_phase.py +3 -0
  66. qiskit/circuit/library/standard_gates/h.py +13 -5
  67. qiskit/circuit/library/standard_gates/i.py +3 -0
  68. qiskit/circuit/library/standard_gates/iswap.py +3 -0
  69. qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +19 -10
  70. qiskit/circuit/library/standard_gates/p.py +14 -9
  71. qiskit/circuit/library/standard_gates/r.py +3 -0
  72. qiskit/circuit/library/standard_gates/rx.py +21 -6
  73. qiskit/circuit/library/standard_gates/rxx.py +40 -1
  74. qiskit/circuit/library/standard_gates/ry.py +21 -6
  75. qiskit/circuit/library/standard_gates/ryy.py +40 -1
  76. qiskit/circuit/library/standard_gates/rz.py +22 -6
  77. qiskit/circuit/library/standard_gates/rzx.py +40 -1
  78. qiskit/circuit/library/standard_gates/rzz.py +41 -2
  79. qiskit/circuit/library/standard_gates/s.py +77 -0
  80. qiskit/circuit/library/standard_gates/swap.py +12 -5
  81. qiskit/circuit/library/standard_gates/sx.py +14 -5
  82. qiskit/circuit/library/standard_gates/t.py +5 -0
  83. qiskit/circuit/library/standard_gates/u.py +22 -7
  84. qiskit/circuit/library/standard_gates/u1.py +8 -3
  85. qiskit/circuit/library/standard_gates/u2.py +3 -0
  86. qiskit/circuit/library/standard_gates/u3.py +22 -7
  87. qiskit/circuit/library/standard_gates/x.py +158 -92
  88. qiskit/circuit/library/standard_gates/xx_minus_yy.py +40 -1
  89. qiskit/circuit/library/standard_gates/xx_plus_yy.py +52 -11
  90. qiskit/circuit/library/standard_gates/y.py +6 -1
  91. qiskit/circuit/library/standard_gates/z.py +8 -1
  92. qiskit/circuit/operation.py +1 -1
  93. qiskit/circuit/parameter.py +9 -10
  94. qiskit/circuit/parameterexpression.py +16 -13
  95. qiskit/circuit/parametertable.py +1 -190
  96. qiskit/circuit/parametervector.py +1 -1
  97. qiskit/circuit/quantumcircuit.py +395 -385
  98. qiskit/circuit/quantumcircuitdata.py +3 -5
  99. qiskit/circuit/quantumregister.py +1 -1
  100. qiskit/circuit/random/__init__.py +1 -1
  101. qiskit/circuit/random/utils.py +175 -26
  102. qiskit/circuit/register.py +5 -7
  103. qiskit/circuit/singleton.py +3 -3
  104. qiskit/circuit/tools/pi_check.py +4 -4
  105. qiskit/compiler/assembler.py +95 -24
  106. qiskit/compiler/scheduler.py +2 -2
  107. qiskit/compiler/transpiler.py +42 -128
  108. qiskit/converters/circuit_to_dag.py +4 -6
  109. qiskit/converters/circuit_to_gate.py +4 -8
  110. qiskit/converters/circuit_to_instruction.py +5 -17
  111. qiskit/converters/dag_to_circuit.py +2 -6
  112. qiskit/dagcircuit/collect_blocks.py +2 -2
  113. qiskit/dagcircuit/dagcircuit.py +197 -187
  114. qiskit/dagcircuit/dagdependency.py +4 -4
  115. qiskit/dagcircuit/dagdependency_v2.py +4 -4
  116. qiskit/dagcircuit/dagdepnode.py +1 -1
  117. qiskit/dagcircuit/dagnode.py +66 -157
  118. qiskit/passmanager/flow_controllers.py +1 -1
  119. qiskit/passmanager/passmanager.py +3 -3
  120. qiskit/primitives/__init__.py +1 -5
  121. qiskit/primitives/backend_estimator.py +25 -15
  122. qiskit/primitives/backend_estimator_v2.py +31 -7
  123. qiskit/primitives/backend_sampler.py +21 -12
  124. qiskit/primitives/backend_sampler_v2.py +12 -3
  125. qiskit/primitives/base/base_estimator.py +31 -4
  126. qiskit/primitives/base/base_primitive.py +2 -2
  127. qiskit/primitives/base/base_result.py +2 -2
  128. qiskit/primitives/base/base_sampler.py +26 -2
  129. qiskit/primitives/base/estimator_result.py +2 -2
  130. qiskit/primitives/base/sampler_result.py +2 -2
  131. qiskit/primitives/containers/__init__.py +0 -1
  132. qiskit/primitives/containers/bindings_array.py +2 -2
  133. qiskit/primitives/containers/bit_array.py +113 -12
  134. qiskit/primitives/containers/shape.py +3 -3
  135. qiskit/primitives/estimator.py +9 -2
  136. qiskit/primitives/primitive_job.py +1 -1
  137. qiskit/primitives/sampler.py +10 -3
  138. qiskit/primitives/statevector_estimator.py +5 -3
  139. qiskit/primitives/statevector_sampler.py +11 -5
  140. qiskit/primitives/utils.py +16 -0
  141. qiskit/providers/backend.py +15 -6
  142. qiskit/providers/backend_compat.py +7 -4
  143. qiskit/providers/basic_provider/basic_provider_tools.py +1 -1
  144. qiskit/providers/basic_provider/basic_simulator.py +33 -25
  145. qiskit/providers/fake_provider/fake_backend.py +10 -3
  146. qiskit/providers/fake_provider/fake_openpulse_2q.py +157 -149
  147. qiskit/providers/fake_provider/fake_openpulse_3q.py +228 -220
  148. qiskit/providers/fake_provider/fake_pulse_backend.py +2 -1
  149. qiskit/providers/fake_provider/fake_qasm_backend.py +7 -2
  150. qiskit/providers/fake_provider/generic_backend_v2.py +519 -68
  151. qiskit/providers/models/__init__.py +48 -11
  152. qiskit/providers/models/backendconfiguration.py +50 -4
  153. qiskit/providers/models/backendproperties.py +13 -2
  154. qiskit/providers/models/pulsedefaults.py +10 -11
  155. qiskit/providers/options.py +13 -13
  156. qiskit/providers/providerutils.py +3 -1
  157. qiskit/pulse/configuration.py +8 -12
  158. qiskit/pulse/instruction_schedule_map.py +3 -5
  159. qiskit/pulse/instructions/acquire.py +7 -8
  160. qiskit/pulse/instructions/instruction.py +2 -3
  161. qiskit/pulse/library/samplers/decorators.py +5 -9
  162. qiskit/pulse/library/symbolic_pulses.py +4 -7
  163. qiskit/pulse/library/waveform.py +2 -5
  164. qiskit/pulse/macros.py +11 -6
  165. qiskit/pulse/parser.py +8 -10
  166. qiskit/pulse/schedule.py +12 -20
  167. qiskit/pulse/transforms/alignments.py +1 -3
  168. qiskit/pulse/utils.py +1 -2
  169. qiskit/qasm/libs/stdgates.inc +35 -28
  170. qiskit/qasm2/__init__.py +7 -7
  171. qiskit/qasm2/export.py +5 -9
  172. qiskit/qasm2/parse.py +1 -1
  173. qiskit/qasm3/ast.py +9 -25
  174. qiskit/qasm3/exporter.py +582 -479
  175. qiskit/qasm3/printer.py +7 -16
  176. qiskit/qobj/common.py +10 -0
  177. qiskit/qobj/converters/lo_config.py +9 -0
  178. qiskit/qobj/converters/pulse_instruction.py +13 -6
  179. qiskit/qobj/pulse_qobj.py +69 -15
  180. qiskit/qobj/qasm_qobj.py +72 -20
  181. qiskit/qobj/utils.py +9 -0
  182. qiskit/qpy/__init__.py +1 -1
  183. qiskit/qpy/binary_io/circuits.py +8 -5
  184. qiskit/qpy/binary_io/schedules.py +1 -1
  185. qiskit/qpy/binary_io/value.py +3 -3
  186. qiskit/qpy/interface.py +3 -2
  187. qiskit/qpy/type_keys.py +2 -2
  188. qiskit/quantum_info/operators/channel/quantum_channel.py +3 -6
  189. qiskit/quantum_info/operators/channel/superop.py +2 -2
  190. qiskit/quantum_info/operators/channel/transformations.py +1 -1
  191. qiskit/quantum_info/operators/dihedral/dihedral.py +3 -4
  192. qiskit/quantum_info/operators/dihedral/dihedral_circuits.py +1 -3
  193. qiskit/quantum_info/operators/dihedral/random.py +6 -3
  194. qiskit/quantum_info/operators/measures.py +2 -2
  195. qiskit/quantum_info/operators/op_shape.py +12 -20
  196. qiskit/quantum_info/operators/operator.py +14 -21
  197. qiskit/quantum_info/operators/predicates.py +1 -0
  198. qiskit/quantum_info/operators/symplectic/base_pauli.py +7 -11
  199. qiskit/quantum_info/operators/symplectic/clifford.py +1 -1
  200. qiskit/quantum_info/operators/symplectic/pauli.py +14 -12
  201. qiskit/quantum_info/operators/symplectic/pauli_list.py +9 -10
  202. qiskit/quantum_info/operators/symplectic/random.py +1 -1
  203. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +15 -17
  204. qiskit/quantum_info/quaternion.py +1 -1
  205. qiskit/quantum_info/states/densitymatrix.py +5 -8
  206. qiskit/quantum_info/states/stabilizerstate.py +128 -37
  207. qiskit/quantum_info/states/statevector.py +4 -8
  208. qiskit/result/counts.py +2 -2
  209. qiskit/result/mitigation/correlated_readout_mitigator.py +2 -2
  210. qiskit/result/mitigation/local_readout_mitigator.py +2 -2
  211. qiskit/result/mitigation/utils.py +1 -3
  212. qiskit/result/models.py +17 -16
  213. qiskit/result/result.py +15 -20
  214. qiskit/scheduler/lowering.py +2 -2
  215. qiskit/synthesis/__init__.py +2 -1
  216. qiskit/synthesis/clifford/__init__.py +1 -1
  217. qiskit/synthesis/clifford/clifford_decompose_ag.py +2 -2
  218. qiskit/synthesis/clifford/clifford_decompose_bm.py +10 -240
  219. qiskit/synthesis/clifford/clifford_decompose_greedy.py +9 -303
  220. qiskit/synthesis/clifford/clifford_decompose_layers.py +25 -23
  221. qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_full.py +1 -1
  222. qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_general.py +1 -1
  223. qiskit/synthesis/discrete_basis/generate_basis_approximations.py +2 -2
  224. qiskit/synthesis/discrete_basis/solovay_kitaev.py +24 -14
  225. qiskit/synthesis/evolution/evolution_synthesis.py +4 -2
  226. qiskit/synthesis/evolution/lie_trotter.py +46 -19
  227. qiskit/synthesis/evolution/product_formula.py +111 -55
  228. qiskit/synthesis/evolution/qdrift.py +40 -10
  229. qiskit/synthesis/evolution/suzuki_trotter.py +43 -33
  230. qiskit/synthesis/linear/__init__.py +1 -0
  231. qiskit/synthesis/linear/cnot_synth.py +22 -96
  232. qiskit/synthesis/linear/linear_depth_lnn.py +8 -8
  233. qiskit/synthesis/linear/linear_matrix_utils.py +13 -161
  234. qiskit/synthesis/linear_phase/cnot_phase_synth.py +1 -1
  235. qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py +3 -3
  236. qiskit/synthesis/linear_phase/cz_depth_lnn.py +1 -1
  237. qiskit/synthesis/one_qubit/one_qubit_decompose.py +29 -29
  238. qiskit/synthesis/permutation/permutation_full.py +5 -29
  239. qiskit/synthesis/permutation/permutation_lnn.py +2 -24
  240. qiskit/synthesis/permutation/permutation_utils.py +2 -59
  241. qiskit/synthesis/qft/__init__.py +1 -0
  242. qiskit/synthesis/qft/qft_decompose_full.py +79 -0
  243. qiskit/synthesis/qft/qft_decompose_lnn.py +17 -9
  244. qiskit/synthesis/stabilizer/stabilizer_circuit.py +6 -6
  245. qiskit/synthesis/stabilizer/stabilizer_decompose.py +2 -2
  246. qiskit/synthesis/two_qubit/local_invariance.py +8 -38
  247. qiskit/synthesis/two_qubit/two_qubit_decompose.py +48 -129
  248. qiskit/synthesis/unitary/aqc/cnot_structures.py +1 -1
  249. qiskit/synthesis/unitary/qsd.py +5 -3
  250. qiskit/transpiler/__init__.py +6 -5
  251. qiskit/transpiler/basepasses.py +1 -1
  252. qiskit/transpiler/coupling.py +3 -3
  253. qiskit/transpiler/instruction_durations.py +1 -2
  254. qiskit/transpiler/layout.py +6 -6
  255. qiskit/transpiler/passes/__init__.py +2 -0
  256. qiskit/transpiler/passes/basis/basis_translator.py +84 -64
  257. qiskit/transpiler/passes/basis/translate_parameterized.py +3 -5
  258. qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
  259. qiskit/transpiler/passes/basis/unroll_custom_definitions.py +10 -10
  260. qiskit/transpiler/passes/calibration/rx_builder.py +3 -3
  261. qiskit/transpiler/passes/calibration/rzx_builder.py +3 -3
  262. qiskit/transpiler/passes/layout/apply_layout.py +13 -3
  263. qiskit/transpiler/passes/layout/sabre_layout.py +10 -8
  264. qiskit/transpiler/passes/layout/sabre_pre_layout.py +4 -1
  265. qiskit/transpiler/passes/layout/set_layout.py +2 -2
  266. qiskit/transpiler/passes/layout/vf2_layout.py +1 -1
  267. qiskit/transpiler/passes/layout/vf2_utils.py +3 -3
  268. qiskit/transpiler/passes/optimization/__init__.py +1 -0
  269. qiskit/transpiler/passes/optimization/collect_cliffords.py +6 -15
  270. qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +2 -2
  271. qiskit/transpiler/passes/optimization/commutation_analysis.py +7 -10
  272. qiskit/transpiler/passes/optimization/commutative_cancellation.py +35 -19
  273. qiskit/transpiler/passes/optimization/consolidate_blocks.py +17 -8
  274. qiskit/transpiler/passes/optimization/inverse_cancellation.py +6 -6
  275. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +64 -41
  276. qiskit/transpiler/passes/optimization/optimize_1q_gates.py +1 -1
  277. qiskit/transpiler/passes/optimization/split_2q_unitaries.py +83 -0
  278. qiskit/transpiler/passes/optimization/template_matching/backward_match.py +1 -1
  279. qiskit/transpiler/passes/optimization/template_matching/forward_match.py +2 -2
  280. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +1 -1
  281. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +3 -2
  282. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/pauli_2q_evolution_commutation.py +5 -1
  283. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/swap_strategy.py +1 -1
  284. qiskit/transpiler/passes/routing/layout_transformation.py +2 -1
  285. qiskit/transpiler/passes/routing/sabre_swap.py +35 -26
  286. qiskit/transpiler/passes/routing/star_prerouting.py +80 -105
  287. qiskit/transpiler/passes/routing/stochastic_swap.py +1 -3
  288. qiskit/transpiler/passes/scheduling/alap.py +1 -2
  289. qiskit/transpiler/passes/scheduling/alignments/__init__.py +2 -2
  290. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
  291. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +2 -2
  292. qiskit/transpiler/passes/scheduling/alignments/reschedule.py +1 -1
  293. qiskit/transpiler/passes/scheduling/asap.py +1 -2
  294. qiskit/transpiler/passes/scheduling/base_scheduler.py +5 -5
  295. qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +3 -3
  296. qiskit/transpiler/passes/scheduling/padding/base_padding.py +1 -1
  297. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +20 -14
  298. qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +7 -6
  299. qiskit/transpiler/passes/scheduling/time_unit_conversion.py +4 -3
  300. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +211 -36
  301. qiskit/transpiler/passes/synthesis/plugin.py +2 -2
  302. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +83 -40
  303. qiskit/transpiler/passes/utils/__init__.py +0 -1
  304. qiskit/transpiler/passes/utils/check_gate_direction.py +4 -4
  305. qiskit/transpiler/passes/utils/check_map.py +3 -6
  306. qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +3 -4
  307. qiskit/transpiler/passes/utils/error.py +2 -2
  308. qiskit/transpiler/passes/utils/fixed_point.py +3 -3
  309. qiskit/transpiler/passes/utils/gate_direction.py +1 -1
  310. qiskit/transpiler/passes/utils/gates_basis.py +1 -2
  311. qiskit/transpiler/passmanager.py +7 -6
  312. qiskit/transpiler/preset_passmanagers/__init__.py +4 -228
  313. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +73 -18
  314. qiskit/transpiler/preset_passmanagers/common.py +3 -6
  315. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +518 -0
  316. qiskit/transpiler/preset_passmanagers/level0.py +1 -1
  317. qiskit/transpiler/target.py +27 -8
  318. qiskit/user_config.py +29 -6
  319. qiskit/utils/classtools.py +3 -3
  320. qiskit/utils/deprecation.py +3 -2
  321. qiskit/utils/lazy_tester.py +2 -2
  322. qiskit/utils/optionals.py +8 -8
  323. qiskit/visualization/bloch.py +62 -24
  324. qiskit/visualization/circuit/_utils.py +34 -10
  325. qiskit/visualization/circuit/circuit_visualization.py +23 -16
  326. qiskit/visualization/circuit/latex.py +29 -27
  327. qiskit/visualization/circuit/matplotlib.py +4 -2
  328. qiskit/visualization/circuit/qcstyle.py +2 -2
  329. qiskit/visualization/circuit/text.py +9 -15
  330. qiskit/visualization/dag_visualization.py +12 -5
  331. qiskit/visualization/pass_manager_visualization.py +9 -9
  332. qiskit/visualization/pulse_v2/core.py +1 -1
  333. qiskit/visualization/pulse_v2/events.py +1 -1
  334. qiskit/visualization/pulse_v2/generators/frame.py +3 -4
  335. qiskit/visualization/pulse_v2/generators/waveform.py +5 -9
  336. qiskit/visualization/pulse_v2/layouts.py +1 -5
  337. qiskit/visualization/pulse_v2/plotters/matplotlib.py +1 -2
  338. qiskit/visualization/state_visualization.py +5 -6
  339. qiskit/visualization/timeline/plotters/matplotlib.py +1 -2
  340. qiskit/visualization/transition_visualization.py +7 -2
  341. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/METADATA +28 -28
  342. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/RECORD +346 -344
  343. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/WHEEL +1 -1
  344. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/entry_points.txt +3 -0
  345. qiskit/transpiler/passes/utils/block_to_matrix.py +0 -47
  346. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/LICENSE.txt +0 -0
  347. {qiskit-1.1.1.dist-info → qiskit-1.2.0.dist-info}/top_level.txt +0 -0
@@ -54,6 +54,8 @@ from qiskit.dagcircuit.exceptions import DAGCircuitError
54
54
  from qiskit.dagcircuit.dagnode import DAGNode, DAGOpNode, DAGInNode, DAGOutNode
55
55
  from qiskit.circuit.bit import Bit
56
56
  from qiskit.pulse import Schedule
57
+ from qiskit._accelerate.euler_one_qubit_decomposer import collect_1q_runs_filter
58
+ from qiskit._accelerate.convert_2q_block_matrix import collect_2q_blocks_filter
57
59
 
58
60
  BitLocations = namedtuple("BitLocations", ("index", "registers"))
59
61
  # The allowable arguments to :meth:`DAGCircuit.copy_empty_like`'s ``vars_mode``.
@@ -271,7 +273,7 @@ class DAGCircuit:
271
273
 
272
274
  duplicate_qubits = set(self.qubits).intersection(qubits)
273
275
  if duplicate_qubits:
274
- raise DAGCircuitError("duplicate qubits %s" % duplicate_qubits)
276
+ raise DAGCircuitError(f"duplicate qubits {duplicate_qubits}")
275
277
 
276
278
  for qubit in qubits:
277
279
  self.qubits.append(qubit)
@@ -285,7 +287,7 @@ class DAGCircuit:
285
287
 
286
288
  duplicate_clbits = set(self.clbits).intersection(clbits)
287
289
  if duplicate_clbits:
288
- raise DAGCircuitError("duplicate clbits %s" % duplicate_clbits)
290
+ raise DAGCircuitError(f"duplicate clbits {duplicate_clbits}")
289
291
 
290
292
  for clbit in clbits:
291
293
  self.clbits.append(clbit)
@@ -297,7 +299,7 @@ class DAGCircuit:
297
299
  if not isinstance(qreg, QuantumRegister):
298
300
  raise DAGCircuitError("not a QuantumRegister instance.")
299
301
  if qreg.name in self.qregs:
300
- raise DAGCircuitError("duplicate register %s" % qreg.name)
302
+ raise DAGCircuitError(f"duplicate register {qreg.name}")
301
303
  self.qregs[qreg.name] = qreg
302
304
  existing_qubits = set(self.qubits)
303
305
  for j in range(qreg.size):
@@ -315,7 +317,7 @@ class DAGCircuit:
315
317
  if not isinstance(creg, ClassicalRegister):
316
318
  raise DAGCircuitError("not a ClassicalRegister instance.")
317
319
  if creg.name in self.cregs:
318
- raise DAGCircuitError("duplicate register %s" % creg.name)
320
+ raise DAGCircuitError(f"duplicate register {creg.name}")
319
321
  self.cregs[creg.name] = creg
320
322
  existing_clbits = set(self.clbits)
321
323
  for j in range(creg.size):
@@ -451,17 +453,17 @@ class DAGCircuit:
451
453
  """
452
454
  if any(not isinstance(clbit, Clbit) for clbit in clbits):
453
455
  raise DAGCircuitError(
454
- "clbits not of type Clbit: %s" % [b for b in clbits if not isinstance(b, Clbit)]
456
+ f"clbits not of type Clbit: {[b for b in clbits if not isinstance(b, Clbit)]}"
455
457
  )
456
458
 
457
459
  clbits = set(clbits)
458
460
  unknown_clbits = clbits.difference(self.clbits)
459
461
  if unknown_clbits:
460
- raise DAGCircuitError("clbits not in circuit: %s" % unknown_clbits)
462
+ raise DAGCircuitError(f"clbits not in circuit: {unknown_clbits}")
461
463
 
462
464
  busy_clbits = {bit for bit in clbits if not self._is_wire_idle(bit)}
463
465
  if busy_clbits:
464
- raise DAGCircuitError("clbits not idle: %s" % busy_clbits)
466
+ raise DAGCircuitError(f"clbits not idle: {busy_clbits}")
465
467
 
466
468
  # remove any references to bits
467
469
  cregs_to_remove = {creg for creg in self.cregs.values() if not clbits.isdisjoint(creg)}
@@ -487,13 +489,13 @@ class DAGCircuit:
487
489
  """
488
490
  if any(not isinstance(creg, ClassicalRegister) for creg in cregs):
489
491
  raise DAGCircuitError(
490
- "cregs not of type ClassicalRegister: %s"
491
- % [r for r in cregs if not isinstance(r, ClassicalRegister)]
492
+ "cregs not of type ClassicalRegister: "
493
+ f"{[r for r in cregs if not isinstance(r, ClassicalRegister)]}"
492
494
  )
493
495
 
494
496
  unknown_cregs = set(cregs).difference(self.cregs.values())
495
497
  if unknown_cregs:
496
- raise DAGCircuitError("cregs not in circuit: %s" % unknown_cregs)
498
+ raise DAGCircuitError(f"cregs not in circuit: {unknown_cregs}")
497
499
 
498
500
  for creg in cregs:
499
501
  del self.cregs[creg.name]
@@ -517,17 +519,17 @@ class DAGCircuit:
517
519
  """
518
520
  if any(not isinstance(qubit, Qubit) for qubit in qubits):
519
521
  raise DAGCircuitError(
520
- "qubits not of type Qubit: %s" % [b for b in qubits if not isinstance(b, Qubit)]
522
+ f"qubits not of type Qubit: {[b for b in qubits if not isinstance(b, Qubit)]}"
521
523
  )
522
524
 
523
525
  qubits = set(qubits)
524
526
  unknown_qubits = qubits.difference(self.qubits)
525
527
  if unknown_qubits:
526
- raise DAGCircuitError("qubits not in circuit: %s" % unknown_qubits)
528
+ raise DAGCircuitError(f"qubits not in circuit: {unknown_qubits}")
527
529
 
528
530
  busy_qubits = {bit for bit in qubits if not self._is_wire_idle(bit)}
529
531
  if busy_qubits:
530
- raise DAGCircuitError("qubits not idle: %s" % busy_qubits)
532
+ raise DAGCircuitError(f"qubits not idle: {busy_qubits}")
531
533
 
532
534
  # remove any references to bits
533
535
  qregs_to_remove = {qreg for qreg in self.qregs.values() if not qubits.isdisjoint(qreg)}
@@ -553,13 +555,13 @@ class DAGCircuit:
553
555
  """
554
556
  if any(not isinstance(qreg, QuantumRegister) for qreg in qregs):
555
557
  raise DAGCircuitError(
556
- "qregs not of type QuantumRegister: %s"
557
- % [r for r in qregs if not isinstance(r, QuantumRegister)]
558
+ f"qregs not of type QuantumRegister: "
559
+ f"{[r for r in qregs if not isinstance(r, QuantumRegister)]}"
558
560
  )
559
561
 
560
562
  unknown_qregs = set(qregs).difference(self.qregs.values())
561
563
  if unknown_qregs:
562
- raise DAGCircuitError("qregs not in circuit: %s" % unknown_qregs)
564
+ raise DAGCircuitError(f"qregs not in circuit: {unknown_qregs}")
563
565
 
564
566
  for qreg in qregs:
565
567
  del self.qregs[qreg.name]
@@ -581,13 +583,13 @@ class DAGCircuit:
581
583
  DAGCircuitError: the wire is not in the circuit.
582
584
  """
583
585
  if wire not in self._wires:
584
- raise DAGCircuitError("wire %s not in circuit" % wire)
586
+ raise DAGCircuitError(f"wire {wire} not in circuit")
585
587
 
586
588
  try:
587
589
  child = next(self.successors(self.input_map[wire]))
588
590
  except StopIteration as e:
589
591
  raise DAGCircuitError(
590
- "Invalid dagcircuit input node %s has no output" % self.input_map[wire]
592
+ f"Invalid dagcircuit input node {self.input_map[wire]} has no output"
591
593
  ) from e
592
594
  return child is self.output_map[wire]
593
595
 
@@ -642,17 +644,17 @@ class DAGCircuit:
642
644
  if wire not in amap:
643
645
  raise DAGCircuitError(f"wire {wire} not found in {amap}")
644
646
 
645
- def _increment_op(self, op):
646
- if op.name in self._op_names:
647
- self._op_names[op.name] += 1
647
+ def _increment_op(self, op_name):
648
+ if op_name in self._op_names:
649
+ self._op_names[op_name] += 1
648
650
  else:
649
- self._op_names[op.name] = 1
651
+ self._op_names[op_name] = 1
650
652
 
651
- def _decrement_op(self, op):
652
- if self._op_names[op.name] == 1:
653
- del self._op_names[op.name]
653
+ def _decrement_op(self, op_name):
654
+ if self._op_names[op_name] == 1:
655
+ del self._op_names[op_name]
654
656
  else:
655
- self._op_names[op.name] -= 1
657
+ self._op_names[op_name] -= 1
656
658
 
657
659
  def copy_empty_like(self, *, vars_mode: _VarsMode = "alike"):
658
660
  """Return a copy of self with the same structure but empty.
@@ -717,6 +719,34 @@ class DAGCircuit:
717
719
 
718
720
  return target_dag
719
721
 
722
+ def _apply_op_node_back(self, node: DAGOpNode, *, check: bool = False):
723
+ additional = ()
724
+ if _may_have_additional_wires(node):
725
+ # This is the slow path; most of the time, this won't happen.
726
+ additional = set(_additional_wires(node.op)).difference(node.cargs)
727
+
728
+ if check:
729
+ self._check_condition(node.name, node.condition)
730
+ self._check_wires(node.qargs, self.output_map)
731
+ self._check_wires(node.cargs, self.output_map)
732
+ self._check_wires(additional, self.output_map)
733
+
734
+ node._node_id = self._multi_graph.add_node(node)
735
+ self._increment_op(node.name)
736
+
737
+ # Add new in-edges from predecessors of the output nodes to the
738
+ # operation node while deleting the old in-edges of the output nodes
739
+ # and adding new edges from the operation node to each output node
740
+ self._multi_graph.insert_node_on_in_edges_multiple(
741
+ node._node_id,
742
+ [
743
+ self.output_map[bit]._node_id
744
+ for bits in (node.qargs, node.cargs, additional)
745
+ for bit in bits
746
+ ],
747
+ )
748
+ return node
749
+
720
750
  def apply_operation_back(
721
751
  self,
722
752
  op: Operation,
@@ -743,32 +773,9 @@ class DAGCircuit:
743
773
  DAGCircuitError: if a leaf node is connected to multiple outputs
744
774
 
745
775
  """
746
- qargs = tuple(qargs)
747
- cargs = tuple(cargs)
748
- additional = ()
749
-
750
- if _may_have_additional_wires(op):
751
- # This is the slow path; most of the time, this won't happen.
752
- additional = set(_additional_wires(op)).difference(cargs)
753
-
754
- if check:
755
- self._check_condition(op.name, getattr(op, "condition", None))
756
- self._check_wires(qargs, self.output_map)
757
- self._check_wires(cargs, self.output_map)
758
- self._check_wires(additional, self.output_map)
759
-
760
- node = DAGOpNode(op=op, qargs=qargs, cargs=cargs, dag=self)
761
- node._node_id = self._multi_graph.add_node(node)
762
- self._increment_op(op)
763
-
764
- # Add new in-edges from predecessors of the output nodes to the
765
- # operation node while deleting the old in-edges of the output nodes
766
- # and adding new edges from the operation node to each output node
767
- self._multi_graph.insert_node_on_in_edges_multiple(
768
- node._node_id,
769
- [self.output_map[bit]._node_id for bits in (qargs, cargs, additional) for bit in bits],
776
+ return self._apply_op_node_back(
777
+ DAGOpNode(op=op, qargs=tuple(qargs), cargs=tuple(cargs), dag=self), check=check
770
778
  )
771
- return node
772
779
 
773
780
  def apply_operation_front(
774
781
  self,
@@ -799,26 +806,30 @@ class DAGCircuit:
799
806
  cargs = tuple(cargs)
800
807
  additional = ()
801
808
 
802
- if _may_have_additional_wires(op):
809
+ node = DAGOpNode(op=op, qargs=qargs, cargs=cargs, dag=self)
810
+ if _may_have_additional_wires(node):
803
811
  # This is the slow path; most of the time, this won't happen.
804
- additional = set(_additional_wires(op)).difference(cargs)
812
+ additional = set(_additional_wires(node.op)).difference(cargs)
805
813
 
806
814
  if check:
807
- self._check_condition(op.name, getattr(op, "condition", None))
808
- self._check_wires(qargs, self.output_map)
809
- self._check_wires(cargs, self.output_map)
815
+ self._check_condition(node.name, node.condition)
816
+ self._check_wires(node.qargs, self.output_map)
817
+ self._check_wires(node.cargs, self.output_map)
810
818
  self._check_wires(additional, self.output_map)
811
819
 
812
- node = DAGOpNode(op=op, qargs=qargs, cargs=cargs, dag=self)
813
820
  node._node_id = self._multi_graph.add_node(node)
814
- self._increment_op(op)
821
+ self._increment_op(node.name)
815
822
 
816
823
  # Add new out-edges to successors of the input nodes from the
817
824
  # operation node while deleting the old out-edges of the input nodes
818
825
  # and adding new edges to the operation node from each input node
819
826
  self._multi_graph.insert_node_on_out_edges_multiple(
820
827
  node._node_id,
821
- [self.input_map[bit]._node_id for bits in (qargs, cargs, additional) for bit in bits],
828
+ [
829
+ self.input_map[bit]._node_id
830
+ for bits in (node.qargs, node.cargs, additional)
831
+ for bit in bits
832
+ ],
822
833
  )
823
834
  return node
824
835
 
@@ -950,12 +961,11 @@ class DAGCircuit:
950
961
  # the mapped wire should already exist
951
962
  if m_wire not in dag.output_map:
952
963
  raise DAGCircuitError(
953
- "wire %s[%d] not in self" % (m_wire.register.name, m_wire.index)
964
+ f"wire {m_wire.register.name}[{m_wire.index}] not in self"
954
965
  )
955
966
  if nd.wire not in other._wires:
956
967
  raise DAGCircuitError(
957
- "inconsistent wire type for %s[%d] in other"
958
- % (nd.register.name, nd.wire.index)
968
+ f"inconsistent wire type for {nd.register.name}[{nd.wire.index}] in other"
959
969
  )
960
970
  # If it's a Var wire, we already checked that it exists in the destination.
961
971
  elif isinstance(nd, DAGOutNode):
@@ -964,17 +974,28 @@ class DAGCircuit:
964
974
  elif isinstance(nd, DAGOpNode):
965
975
  m_qargs = [edge_map.get(x, x) for x in nd.qargs]
966
976
  m_cargs = [edge_map.get(x, x) for x in nd.cargs]
967
- op = nd.op.copy()
968
- if (condition := getattr(op, "condition", None)) is not None:
969
- if not isinstance(op, ControlFlowOp):
970
- op = op.c_if(*variable_mapper.map_condition(condition, allow_reorder=True))
977
+ inst = nd._to_circuit_instruction(deepcopy=True)
978
+ m_op = None
979
+ if inst.condition is not None:
980
+ if inst.is_control_flow():
981
+ m_op = inst.operation
982
+ m_op.condition = variable_mapper.map_condition(
983
+ inst.condition, allow_reorder=True
984
+ )
971
985
  else:
972
- op.condition = variable_mapper.map_condition(condition, allow_reorder=True)
973
- elif isinstance(op, SwitchCaseOp):
974
- op.target = variable_mapper.map_target(op.target)
975
- dag.apply_operation_back(op, m_qargs, m_cargs, check=False)
986
+ m_op = inst.operation.c_if(
987
+ *variable_mapper.map_condition(inst.condition, allow_reorder=True)
988
+ )
989
+ elif inst.is_control_flow() and isinstance(inst.operation, SwitchCaseOp):
990
+ m_op = inst.operation
991
+ m_op.target = variable_mapper.map_target(m_op.target)
992
+ if m_op is None:
993
+ inst = inst.replace(qubits=m_qargs, clbits=m_cargs)
994
+ else:
995
+ inst = inst.replace(operation=m_op, qubits=m_qargs, clbits=m_cargs)
996
+ dag._apply_op_node_back(DAGOpNode.from_instruction(inst), check=False)
976
997
  else:
977
- raise DAGCircuitError("bad node type %s" % type(nd))
998
+ raise DAGCircuitError(f"bad node type {type(nd)}")
978
999
 
979
1000
  if not inplace:
980
1001
  return dag
@@ -1327,9 +1348,9 @@ class DAGCircuit:
1327
1348
  for nd in node_block:
1328
1349
  block_qargs |= set(nd.qargs)
1329
1350
  block_cargs |= set(nd.cargs)
1330
- if (condition := getattr(nd.op, "condition", None)) is not None:
1351
+ if (condition := getattr(nd, "condition", None)) is not None:
1331
1352
  block_cargs.update(condition_resources(condition).clbits)
1332
- elif isinstance(nd.op, SwitchCaseOp):
1353
+ elif nd.name in CONTROL_FLOW_OP_NAMES and isinstance(nd.op, SwitchCaseOp):
1333
1354
  if isinstance(nd.op.target, Clbit):
1334
1355
  block_cargs.add(nd.op.target)
1335
1356
  elif isinstance(nd.op.target, ClassicalRegister):
@@ -1343,6 +1364,13 @@ class DAGCircuit:
1343
1364
  block_cargs.sort(key=wire_pos_map.get)
1344
1365
  new_node = DAGOpNode(op, block_qargs, block_cargs, dag=self)
1345
1366
 
1367
+ # check the op to insert matches the number of qubits we put it on
1368
+ if op.num_qubits != len(block_qargs):
1369
+ raise DAGCircuitError(
1370
+ f"Number of qubits in the replacement operation ({op.num_qubits}) is not equal to "
1371
+ f"the number of qubits in the block ({len(block_qargs)})!"
1372
+ )
1373
+
1346
1374
  try:
1347
1375
  new_node._node_id = self._multi_graph.contract_nodes(
1348
1376
  block_ids, new_node, check_cycle=cycle_check
@@ -1352,10 +1380,10 @@ class DAGCircuit:
1352
1380
  "Replacing the specified node block would introduce a cycle"
1353
1381
  ) from ex
1354
1382
 
1355
- self._increment_op(op)
1383
+ self._increment_op(op.name)
1356
1384
 
1357
1385
  for nd in node_block:
1358
- self._decrement_op(nd.op)
1386
+ self._decrement_op(nd.name)
1359
1387
 
1360
1388
  return new_node
1361
1389
 
@@ -1404,7 +1432,7 @@ class DAGCircuit:
1404
1432
  node_wire_order = list(node.qargs) + list(node.cargs)
1405
1433
  # If we're not propagating it, the number of wires in the input DAG should include the
1406
1434
  # condition as well.
1407
- if not propagate_condition and _may_have_additional_wires(node.op):
1435
+ if not propagate_condition and _may_have_additional_wires(node):
1408
1436
  node_wire_order += [
1409
1437
  wire for wire in _additional_wires(node.op) if wire not in node_cargs
1410
1438
  ]
@@ -1426,7 +1454,7 @@ class DAGCircuit:
1426
1454
  raise DAGCircuitError(
1427
1455
  f"bit mapping invalid: {input_dag_wire} and {our_wire} are different bit types"
1428
1456
  )
1429
- if _may_have_additional_wires(node.op):
1457
+ if _may_have_additional_wires(node):
1430
1458
  node_vars = {var for var in _additional_wires(node.op) if isinstance(var, expr.Var)}
1431
1459
  else:
1432
1460
  node_vars = set()
@@ -1443,11 +1471,7 @@ class DAGCircuit:
1443
1471
  reverse_wire_map = {b: a for a, b in wire_map.items()}
1444
1472
  # It doesn't make sense to try and propagate a condition from a control-flow op; a
1445
1473
  # replacement for the control-flow op should implement the operation completely.
1446
- if (
1447
- propagate_condition
1448
- and not isinstance(node.op, ControlFlowOp)
1449
- and (op_condition := getattr(node.op, "condition", None)) is not None
1450
- ):
1474
+ if propagate_condition and not node.is_control_flow() and node.condition is not None:
1451
1475
  in_dag = input_dag.copy_empty_like()
1452
1476
  # The remapping of `condition` below is still using the old code that assumes a 2-tuple.
1453
1477
  # This is because this remapping code only makes sense in the case of non-control-flow
@@ -1456,7 +1480,7 @@ class DAGCircuit:
1456
1480
  # in favour of the new-style conditional blocks. The extra logic in here to add
1457
1481
  # additional wires into the map as necessary would hugely complicate matters if we tried
1458
1482
  # to abstract it out into the `VariableMapper` used elsewhere.
1459
- target, value = op_condition
1483
+ target, value = node.condition
1460
1484
  if isinstance(target, Clbit):
1461
1485
  new_target = reverse_wire_map.get(target, Clbit())
1462
1486
  if new_target not in wire_map:
@@ -1526,7 +1550,7 @@ class DAGCircuit:
1526
1550
  )[0]
1527
1551
  self._multi_graph.add_edge(pred._node_id, succ._node_id, contracted_var)
1528
1552
 
1529
- # Exlude any nodes from in_dag that are not a DAGOpNode or are on
1553
+ # Exclude any nodes from in_dag that are not a DAGOpNode or are on
1530
1554
  # wires outside the set specified by the wires kwarg
1531
1555
  def filter_fn(node):
1532
1556
  if not isinstance(node, DAGOpNode):
@@ -1566,7 +1590,7 @@ class DAGCircuit:
1566
1590
  node_map = self._multi_graph.substitute_node_with_subgraph(
1567
1591
  node._node_id, in_dag._multi_graph, edge_map_fn, filter_fn, edge_weight_map
1568
1592
  )
1569
- self._decrement_op(node.op)
1593
+ self._decrement_op(node.name)
1570
1594
 
1571
1595
  variable_mapper = _classical_resource_map.VariableMapper(
1572
1596
  self.cregs.values(), wire_map, add_register=self.add_creg
@@ -1576,28 +1600,34 @@ class DAGCircuit:
1576
1600
  for old_node_index, new_node_index in node_map.items():
1577
1601
  # update node attributes
1578
1602
  old_node = in_dag._multi_graph[old_node_index]
1579
- if isinstance(old_node.op, SwitchCaseOp):
1603
+ m_op = None
1604
+ if not old_node.is_standard_gate() and isinstance(old_node.op, SwitchCaseOp):
1580
1605
  m_op = SwitchCaseOp(
1581
1606
  variable_mapper.map_target(old_node.op.target),
1582
1607
  old_node.op.cases_specifier(),
1583
1608
  label=old_node.op.label,
1584
1609
  )
1585
- elif getattr(old_node.op, "condition", None) is not None:
1610
+ elif old_node.condition is not None:
1586
1611
  m_op = old_node.op
1587
- if not isinstance(old_node.op, ControlFlowOp):
1612
+ if old_node.is_control_flow():
1613
+ m_op.condition = variable_mapper.map_condition(m_op.condition)
1614
+ else:
1588
1615
  new_condition = variable_mapper.map_condition(m_op.condition)
1589
1616
  if new_condition is not None:
1590
1617
  m_op = m_op.c_if(*new_condition)
1591
- else:
1592
- m_op.condition = variable_mapper.map_condition(m_op.condition)
1593
- else:
1594
- m_op = old_node.op
1595
1618
  m_qargs = [wire_map[x] for x in old_node.qargs]
1596
1619
  m_cargs = [wire_map[x] for x in old_node.cargs]
1597
- new_node = DAGOpNode(m_op, qargs=m_qargs, cargs=m_cargs, dag=self)
1620
+ old_instruction = old_node._to_circuit_instruction()
1621
+ if m_op is None:
1622
+ new_instruction = old_instruction.replace(qubits=m_qargs, clbits=m_cargs)
1623
+ else:
1624
+ new_instruction = old_instruction.replace(
1625
+ operation=m_op, qubits=m_qargs, clbits=m_cargs
1626
+ )
1627
+ new_node = DAGOpNode.from_instruction(new_instruction)
1598
1628
  new_node._node_id = new_node_index
1599
1629
  self._multi_graph[new_node_index] = new_node
1600
- self._increment_op(new_node.op)
1630
+ self._increment_op(new_node.name)
1601
1631
 
1602
1632
  return {k: self._multi_graph[v] for k, v in node_map.items()}
1603
1633
 
@@ -1616,7 +1646,7 @@ class DAGCircuit:
1616
1646
  be used.
1617
1647
  propagate_condition (bool): Optional, default True. If True, a condition on the
1618
1648
  ``node`` to be replaced will be applied to the new ``op``. This is the legacy
1619
- behaviour. If either node is a control-flow operation, this will be ignored. If
1649
+ behavior. If either node is a control-flow operation, this will be ignored. If
1620
1650
  the ``op`` already has a condition, :exc:`.DAGCircuitError` is raised.
1621
1651
 
1622
1652
  Returns:
@@ -1632,10 +1662,10 @@ class DAGCircuit:
1632
1662
 
1633
1663
  if node.op.num_qubits != op.num_qubits or node.op.num_clbits != op.num_clbits:
1634
1664
  raise DAGCircuitError(
1635
- "Cannot replace node of width ({} qubits, {} clbits) with "
1636
- "operation of mismatched width ({} qubits, {} clbits).".format(
1637
- node.op.num_qubits, node.op.num_clbits, op.num_qubits, op.num_clbits
1638
- )
1665
+ f"Cannot replace node of width ({node.op.num_qubits} qubits, "
1666
+ f"{node.op.num_clbits} clbits) with "
1667
+ f"operation of mismatched width ({op.num_qubits} qubits, "
1668
+ f"{op.num_clbits} clbits)."
1639
1669
  )
1640
1670
 
1641
1671
  # This might include wires that are inherent to the node, like in its `condition` or
@@ -1669,17 +1699,17 @@ class DAGCircuit:
1669
1699
 
1670
1700
  if inplace:
1671
1701
  if op.name != node.op.name:
1672
- self._increment_op(op)
1673
- self._decrement_op(node.op)
1702
+ self._increment_op(op.name)
1703
+ self._decrement_op(node.name)
1674
1704
  node.op = op
1675
1705
  return node
1676
1706
 
1677
1707
  new_node = copy.copy(node)
1678
1708
  new_node.op = op
1679
1709
  self._multi_graph[node._node_id] = new_node
1680
- if op.name != node.op.name:
1681
- self._increment_op(op)
1682
- self._decrement_op(node.op)
1710
+ if op.name != node.name:
1711
+ self._increment_op(op.name)
1712
+ self._decrement_op(node.name)
1683
1713
  return new_node
1684
1714
 
1685
1715
  def separable_circuits(
@@ -1823,11 +1853,18 @@ class DAGCircuit:
1823
1853
  list[DAGOpNode]: the list of node ids containing the given op.
1824
1854
  """
1825
1855
  nodes = []
1856
+ filter_is_nonstandard = getattr(op, "_standard_gate", None) is None
1826
1857
  for node in self._multi_graph.nodes():
1827
1858
  if isinstance(node, DAGOpNode):
1828
- if not include_directives and getattr(node.op, "_directive", False):
1859
+ if not include_directives and node.is_directive():
1829
1860
  continue
1830
- if op is None or isinstance(node.op, op):
1861
+ if op is None or (
1862
+ # This middle catch is to avoid Python-space operation creation for most uses of
1863
+ # `op`; we're usually just looking for control-flow ops, and standard gates
1864
+ # aren't control-flow ops.
1865
+ not (filter_is_nonstandard and node.is_standard_gate())
1866
+ and isinstance(node.op, op)
1867
+ ):
1831
1868
  nodes.append(node)
1832
1869
  return nodes
1833
1870
 
@@ -1847,7 +1884,7 @@ class DAGCircuit:
1847
1884
  """Get the set of "op" nodes with the given name."""
1848
1885
  named_nodes = []
1849
1886
  for node in self._multi_graph.nodes():
1850
- if isinstance(node, DAGOpNode) and node.op.name in names:
1887
+ if isinstance(node, DAGOpNode) and node.name in names:
1851
1888
  named_nodes.append(node)
1852
1889
  return named_nodes
1853
1890
 
@@ -1953,14 +1990,12 @@ class DAGCircuit:
1953
1990
  """
1954
1991
  if not isinstance(node, DAGOpNode):
1955
1992
  raise DAGCircuitError(
1956
- 'The method remove_op_node only works on DAGOpNodes. A "%s" '
1957
- "node type was wrongly provided." % type(node)
1993
+ f'The method remove_op_node only works on DAGOpNodes. A "{type(node)}" '
1994
+ "node type was wrongly provided."
1958
1995
  )
1959
1996
 
1960
- self._multi_graph.remove_node_retain_edges(
1961
- node._node_id, use_outgoing=False, condition=lambda edge1, edge2: edge1 == edge2
1962
- )
1963
- self._decrement_op(node.op)
1997
+ self._multi_graph.remove_node_retain_edges_by_id(node._node_id)
1998
+ self._decrement_op(node.name)
1964
1999
 
1965
2000
  def remove_ancestors_of(self, node):
1966
2001
  """Remove all of the ancestor operation nodes of node."""
@@ -2055,14 +2090,11 @@ class DAGCircuit:
2055
2090
  new_layer = self.copy_empty_like(vars_mode=vars_mode)
2056
2091
 
2057
2092
  for node in op_nodes:
2058
- # this creates new DAGOpNodes in the new_layer
2059
- new_layer.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
2093
+ new_layer._apply_op_node_back(node, check=False)
2060
2094
 
2061
2095
  # The quantum registers that have an operation in this layer.
2062
2096
  support_list = [
2063
- op_node.qargs
2064
- for op_node in new_layer.op_nodes()
2065
- if not getattr(op_node.op, "_directive", False)
2097
+ op_node.qargs for op_node in new_layer.op_nodes() if not op_node.is_directive()
2066
2098
  ]
2067
2099
 
2068
2100
  yield {"graph": new_layer, "partition": support_list}
@@ -2114,56 +2146,25 @@ class DAGCircuit:
2114
2146
  """
2115
2147
 
2116
2148
  def filter_fn(node):
2117
- return (
2118
- isinstance(node, DAGOpNode)
2119
- and node.op.name in namelist
2120
- and getattr(node.op, "condition", None) is None
2121
- )
2149
+ return isinstance(node, DAGOpNode) and node.name in namelist and node.condition is None
2122
2150
 
2123
2151
  group_list = rx.collect_runs(self._multi_graph, filter_fn)
2124
2152
  return {tuple(x) for x in group_list}
2125
2153
 
2126
2154
  def collect_1q_runs(self) -> list[list[DAGOpNode]]:
2127
2155
  """Return a set of non-conditional runs of 1q "op" nodes."""
2128
-
2129
- def filter_fn(node):
2130
- return (
2131
- isinstance(node, DAGOpNode)
2132
- and len(node.qargs) == 1
2133
- and len(node.cargs) == 0
2134
- and isinstance(node.op, Gate)
2135
- and hasattr(node.op, "__array__")
2136
- and getattr(node.op, "condition", None) is None
2137
- and not node.op.is_parameterized()
2138
- )
2139
-
2140
- return rx.collect_runs(self._multi_graph, filter_fn)
2156
+ return rx.collect_runs(self._multi_graph, collect_1q_runs_filter)
2141
2157
 
2142
2158
  def collect_2q_runs(self):
2143
2159
  """Return a set of non-conditional runs of 2q "op" nodes."""
2144
2160
 
2145
- to_qid = {}
2146
- for i, qubit in enumerate(self.qubits):
2147
- to_qid[qubit] = i
2148
-
2149
- def filter_fn(node):
2150
- if isinstance(node, DAGOpNode):
2151
- return (
2152
- isinstance(node.op, Gate)
2153
- and len(node.qargs) <= 2
2154
- and not getattr(node.op, "condition", None)
2155
- and not node.op.is_parameterized()
2156
- )
2157
- else:
2158
- return None
2159
-
2160
2161
  def color_fn(edge):
2161
2162
  if isinstance(edge, Qubit):
2162
- return to_qid[edge]
2163
+ return self.find_bit(edge).index
2163
2164
  else:
2164
2165
  return None
2165
2166
 
2166
- return rx.collect_bicolor_runs(self._multi_graph, filter_fn, color_fn)
2167
+ return rx.collect_bicolor_runs(self._multi_graph, collect_2q_blocks_filter, color_fn)
2167
2168
 
2168
2169
  def nodes_on_wire(self, wire, only_ops=False):
2169
2170
  """
@@ -2182,7 +2183,7 @@ class DAGCircuit:
2182
2183
  current_node = self.input_map.get(wire, None)
2183
2184
 
2184
2185
  if not current_node:
2185
- raise DAGCircuitError("The given wire %s is not present in the circuit" % str(wire))
2186
+ raise DAGCircuitError(f"The given wire {str(wire)} is not present in the circuit")
2186
2187
 
2187
2188
  more_nodes = True
2188
2189
  while more_nodes:
@@ -2265,36 +2266,44 @@ class DAGCircuit:
2265
2266
  output_node = self.output_map.get(qubit, None)
2266
2267
  if not output_node:
2267
2268
  raise DAGCircuitError(f"Qubit {qubit} is not part of this circuit.")
2268
- # Add the qubit to the causal cone.
2269
- qubits_to_check = {qubit}
2270
- # Add predecessors of output node to the queue.
2271
- queue = deque(self.predecessors(output_node))
2272
2269
 
2273
- # While queue isn't empty
2270
+ qubits_in_cone = {qubit}
2271
+ queue = deque(self.quantum_predecessors(output_node))
2272
+
2273
+ # The processed_non_directive_nodes stores the set of processed non-directive nodes.
2274
+ # This is an optimization to avoid considering the same non-directive node multiple
2275
+ # times when reached from different paths.
2276
+ # The directive nodes (such as barriers or measures) are trickier since when processing
2277
+ # them we only add their predecessors that intersect qubits_in_cone. Hence, directive
2278
+ # nodes have to be considered multiple times.
2279
+ processed_non_directive_nodes = set()
2280
+
2274
2281
  while queue:
2275
- # Pop first element.
2276
2282
  node_to_check = queue.popleft()
2277
- # Check whether element is input or output node.
2283
+
2278
2284
  if isinstance(node_to_check, DAGOpNode):
2279
- # Keep all the qubits in the operation inside a set.
2280
- qubit_set = set(node_to_check.qargs)
2281
- # Check if there are any qubits in common and that the operation is not a barrier.
2282
- if (
2283
- len(qubit_set.intersection(qubits_to_check)) > 0
2284
- and node_to_check.op.name != "barrier"
2285
- and not getattr(node_to_check.op, "_directive")
2286
- ):
2287
- # If so, add all the qubits to the causal cone.
2288
- qubits_to_check = qubits_to_check.union(qubit_set)
2289
- # For each predecessor of the current node, filter input/output nodes,
2290
- # also make sure it has at least one qubit in common. Then append.
2291
- for node in self.quantum_predecessors(node_to_check):
2292
- if (
2293
- isinstance(node, DAGOpNode)
2294
- and len(qubits_to_check.intersection(set(node.qargs))) > 0
2295
- ):
2296
- queue.append(node)
2297
- return qubits_to_check
2285
+ # If the operation is not a directive (in particular not a barrier nor a measure),
2286
+ # we do not do anything if it was already processed. Otherwise, we add its qubits
2287
+ # to qubits_in_cone, and append its predecessors to queue.
2288
+ if not getattr(node_to_check.op, "_directive"):
2289
+ if node_to_check in processed_non_directive_nodes:
2290
+ continue
2291
+ qubits_in_cone = qubits_in_cone.union(set(node_to_check.qargs))
2292
+ processed_non_directive_nodes.add(node_to_check)
2293
+ for pred in self.quantum_predecessors(node_to_check):
2294
+ if isinstance(pred, DAGOpNode):
2295
+ queue.append(pred)
2296
+ else:
2297
+ # Directives (such as barriers and measures) may be defined over all the qubits,
2298
+ # yet not all of these qubits should be considered in the causal cone. So we
2299
+ # only add those predecessors that have qubits in common with qubits_in_cone.
2300
+ for pred in self.quantum_predecessors(node_to_check):
2301
+ if isinstance(pred, DAGOpNode) and not qubits_in_cone.isdisjoint(
2302
+ set(pred.qargs)
2303
+ ):
2304
+ queue.append(pred)
2305
+
2306
+ return qubits_in_cone
2298
2307
 
2299
2308
  def properties(self):
2300
2309
  """Return a dictionary of circuit properties."""
@@ -2352,24 +2361,25 @@ class _DAGVarInfo:
2352
2361
  self.out_node = out_node
2353
2362
 
2354
2363
 
2355
- def _may_have_additional_wires(operation) -> bool:
2356
- """Return whether a given :class:`.Operation` may contain references to additional wires
2357
- locations within itself. If this is ``False``, it doesn't necessarily mean that the operation
2358
- _will_ access memory inherently, but a ``True`` return guarantees that it won't.
2364
+ def _may_have_additional_wires(node) -> bool:
2365
+ """Return whether a given :class:`.DAGOpNode` may contain references to additional wires
2366
+ locations within its :class:`.Operation`. If this is ``True``, it doesn't necessarily mean
2367
+ that the operation _will_ access memory inherently, but a ``False`` return guarantees that it
2368
+ won't.
2359
2369
 
2360
2370
  The memory might be classical bits or classical variables, such as a control-flow operation or a
2361
2371
  store.
2362
2372
 
2363
2373
  Args:
2364
- operation (qiskit.circuit.Operation): the operation to check.
2374
+ operation (qiskit.dagcircuit.DAGOpNode): the operation to check.
2365
2375
  """
2366
2376
  # This is separate to `_additional_wires` because most of the time there won't be any extra
2367
2377
  # wires beyond the explicit `qargs` and `cargs` so we want a fast path to be able to skip
2368
2378
  # creating and testing a generator for emptiness.
2369
2379
  #
2370
2380
  # If updating this, you most likely also need to update `_additional_wires`.
2371
- return getattr(operation, "condition", None) is not None or isinstance(
2372
- operation, (ControlFlowOp, Store)
2381
+ return node.condition is not None or (
2382
+ not node.is_standard_gate() and isinstance(node.op, (ControlFlowOp, Store))
2373
2383
  )
2374
2384
 
2375
2385