qiskit 1.1.2__cp38-abi3-macosx_10_9_universal2.whl → 1.2.0rc1__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 (341) 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 +1 -1
  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/boolean_expression.py +1 -1
  18. qiskit/circuit/classicalfunction/classical_function_visitor.py +5 -5
  19. qiskit/circuit/classicalfunction/utils.py +1 -1
  20. qiskit/circuit/classicalregister.py +1 -1
  21. qiskit/circuit/commutation_checker.py +83 -35
  22. qiskit/circuit/controlflow/_builder_utils.py +1 -1
  23. qiskit/circuit/controlflow/builder.py +10 -6
  24. qiskit/circuit/controlflow/if_else.py +2 -2
  25. qiskit/circuit/controlflow/switch_case.py +1 -1
  26. qiskit/circuit/delay.py +1 -1
  27. qiskit/circuit/duration.py +2 -2
  28. qiskit/circuit/equivalence.py +5 -7
  29. qiskit/circuit/gate.py +11 -8
  30. qiskit/circuit/instruction.py +31 -13
  31. qiskit/circuit/instructionset.py +2 -5
  32. qiskit/circuit/library/__init__.py +2 -1
  33. qiskit/circuit/library/arithmetic/linear_amplitude_function.py +1 -1
  34. qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +1 -1
  35. qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +1 -1
  36. qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +1 -1
  37. qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +3 -3
  38. qiskit/circuit/library/arithmetic/polynomial_pauli_rotations.py +1 -1
  39. qiskit/circuit/library/basis_change/__init__.py +1 -1
  40. qiskit/circuit/library/basis_change/qft.py +40 -6
  41. qiskit/circuit/library/blueprintcircuit.py +3 -5
  42. qiskit/circuit/library/data_preparation/__init__.py +9 -2
  43. qiskit/circuit/library/data_preparation/initializer.py +8 -0
  44. qiskit/circuit/library/data_preparation/state_preparation.py +98 -178
  45. qiskit/circuit/library/generalized_gates/isometry.py +8 -8
  46. qiskit/circuit/library/generalized_gates/linear_function.py +3 -2
  47. qiskit/circuit/library/generalized_gates/mcg_up_to_diagonal.py +4 -4
  48. qiskit/circuit/library/generalized_gates/permutation.py +8 -9
  49. qiskit/circuit/library/generalized_gates/uc.py +3 -3
  50. qiskit/circuit/library/generalized_gates/uc_pauli_rot.py +2 -2
  51. qiskit/circuit/library/generalized_gates/unitary.py +13 -11
  52. qiskit/circuit/library/graph_state.py +1 -1
  53. qiskit/circuit/library/hamiltonian_gate.py +1 -2
  54. qiskit/circuit/library/hidden_linear_function.py +1 -1
  55. qiskit/circuit/library/n_local/evolved_operator_ansatz.py +3 -2
  56. qiskit/circuit/library/n_local/n_local.py +4 -5
  57. qiskit/circuit/library/n_local/pauli_two_design.py +1 -1
  58. qiskit/circuit/library/n_local/qaoa_ansatz.py +6 -8
  59. qiskit/circuit/library/n_local/two_local.py +1 -1
  60. qiskit/circuit/library/overlap.py +11 -5
  61. qiskit/circuit/library/pauli_evolution.py +7 -3
  62. qiskit/circuit/library/standard_gates/dcx.py +3 -0
  63. qiskit/circuit/library/standard_gates/ecr.py +3 -0
  64. qiskit/circuit/library/standard_gates/global_phase.py +3 -0
  65. qiskit/circuit/library/standard_gates/h.py +13 -5
  66. qiskit/circuit/library/standard_gates/i.py +3 -0
  67. qiskit/circuit/library/standard_gates/iswap.py +3 -0
  68. qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +19 -10
  69. qiskit/circuit/library/standard_gates/p.py +14 -9
  70. qiskit/circuit/library/standard_gates/r.py +3 -0
  71. qiskit/circuit/library/standard_gates/rx.py +21 -6
  72. qiskit/circuit/library/standard_gates/rxx.py +40 -1
  73. qiskit/circuit/library/standard_gates/ry.py +21 -6
  74. qiskit/circuit/library/standard_gates/ryy.py +40 -1
  75. qiskit/circuit/library/standard_gates/rz.py +22 -6
  76. qiskit/circuit/library/standard_gates/rzx.py +40 -1
  77. qiskit/circuit/library/standard_gates/rzz.py +41 -2
  78. qiskit/circuit/library/standard_gates/s.py +77 -0
  79. qiskit/circuit/library/standard_gates/swap.py +12 -5
  80. qiskit/circuit/library/standard_gates/sx.py +14 -5
  81. qiskit/circuit/library/standard_gates/t.py +5 -0
  82. qiskit/circuit/library/standard_gates/u.py +22 -7
  83. qiskit/circuit/library/standard_gates/u1.py +8 -3
  84. qiskit/circuit/library/standard_gates/u2.py +3 -0
  85. qiskit/circuit/library/standard_gates/u3.py +22 -7
  86. qiskit/circuit/library/standard_gates/x.py +156 -92
  87. qiskit/circuit/library/standard_gates/xx_minus_yy.py +40 -1
  88. qiskit/circuit/library/standard_gates/xx_plus_yy.py +52 -11
  89. qiskit/circuit/library/standard_gates/y.py +6 -1
  90. qiskit/circuit/library/standard_gates/z.py +8 -1
  91. qiskit/circuit/operation.py +1 -1
  92. qiskit/circuit/parameter.py +9 -10
  93. qiskit/circuit/parameterexpression.py +16 -13
  94. qiskit/circuit/parametertable.py +1 -190
  95. qiskit/circuit/parametervector.py +1 -1
  96. qiskit/circuit/quantumcircuit.py +392 -384
  97. qiskit/circuit/quantumcircuitdata.py +3 -5
  98. qiskit/circuit/quantumregister.py +1 -1
  99. qiskit/circuit/random/__init__.py +1 -1
  100. qiskit/circuit/random/utils.py +175 -26
  101. qiskit/circuit/register.py +5 -7
  102. qiskit/circuit/singleton.py +3 -3
  103. qiskit/circuit/tools/pi_check.py +4 -4
  104. qiskit/compiler/assembler.py +95 -24
  105. qiskit/compiler/scheduler.py +2 -2
  106. qiskit/compiler/transpiler.py +41 -127
  107. qiskit/converters/circuit_to_dag.py +4 -6
  108. qiskit/converters/circuit_to_gate.py +4 -8
  109. qiskit/converters/circuit_to_instruction.py +5 -17
  110. qiskit/converters/dag_to_circuit.py +2 -6
  111. qiskit/dagcircuit/collect_blocks.py +2 -2
  112. qiskit/dagcircuit/dagcircuit.py +190 -187
  113. qiskit/dagcircuit/dagdependency.py +4 -4
  114. qiskit/dagcircuit/dagdependency_v2.py +4 -4
  115. qiskit/dagcircuit/dagdepnode.py +1 -1
  116. qiskit/dagcircuit/dagnode.py +66 -157
  117. qiskit/passmanager/flow_controllers.py +1 -1
  118. qiskit/passmanager/passmanager.py +3 -3
  119. qiskit/primitives/__init__.py +1 -5
  120. qiskit/primitives/backend_estimator.py +25 -15
  121. qiskit/primitives/backend_estimator_v2.py +31 -7
  122. qiskit/primitives/backend_sampler.py +21 -12
  123. qiskit/primitives/backend_sampler_v2.py +12 -3
  124. qiskit/primitives/base/base_estimator.py +31 -4
  125. qiskit/primitives/base/base_primitive.py +2 -2
  126. qiskit/primitives/base/base_result.py +2 -2
  127. qiskit/primitives/base/base_sampler.py +26 -2
  128. qiskit/primitives/base/estimator_result.py +2 -2
  129. qiskit/primitives/base/sampler_result.py +2 -2
  130. qiskit/primitives/containers/__init__.py +0 -1
  131. qiskit/primitives/containers/bindings_array.py +2 -2
  132. qiskit/primitives/containers/bit_array.py +108 -10
  133. qiskit/primitives/containers/shape.py +3 -3
  134. qiskit/primitives/estimator.py +9 -2
  135. qiskit/primitives/primitive_job.py +1 -1
  136. qiskit/primitives/sampler.py +10 -3
  137. qiskit/primitives/statevector_estimator.py +5 -3
  138. qiskit/primitives/statevector_sampler.py +11 -5
  139. qiskit/primitives/utils.py +16 -0
  140. qiskit/providers/backend.py +15 -6
  141. qiskit/providers/backend_compat.py +7 -4
  142. qiskit/providers/basic_provider/basic_provider_tools.py +1 -1
  143. qiskit/providers/basic_provider/basic_simulator.py +32 -24
  144. qiskit/providers/fake_provider/fake_backend.py +10 -3
  145. qiskit/providers/fake_provider/fake_openpulse_2q.py +154 -146
  146. qiskit/providers/fake_provider/fake_openpulse_3q.py +226 -217
  147. qiskit/providers/fake_provider/fake_qasm_backend.py +5 -1
  148. qiskit/providers/fake_provider/generic_backend_v2.py +80 -50
  149. qiskit/providers/models/__init__.py +11 -0
  150. qiskit/providers/models/backendconfiguration.py +50 -4
  151. qiskit/providers/models/backendproperties.py +13 -2
  152. qiskit/providers/models/pulsedefaults.py +10 -11
  153. qiskit/providers/options.py +13 -13
  154. qiskit/providers/providerutils.py +3 -1
  155. qiskit/pulse/configuration.py +8 -12
  156. qiskit/pulse/instruction_schedule_map.py +3 -5
  157. qiskit/pulse/instructions/acquire.py +7 -8
  158. qiskit/pulse/instructions/instruction.py +2 -3
  159. qiskit/pulse/library/samplers/decorators.py +5 -9
  160. qiskit/pulse/library/symbolic_pulses.py +4 -7
  161. qiskit/pulse/library/waveform.py +2 -5
  162. qiskit/pulse/macros.py +11 -6
  163. qiskit/pulse/parser.py +8 -10
  164. qiskit/pulse/schedule.py +9 -17
  165. qiskit/pulse/transforms/alignments.py +1 -3
  166. qiskit/pulse/utils.py +1 -2
  167. qiskit/qasm/libs/stdgates.inc +35 -28
  168. qiskit/qasm2/__init__.py +7 -7
  169. qiskit/qasm2/export.py +5 -9
  170. qiskit/qasm2/parse.py +1 -1
  171. qiskit/qasm3/ast.py +9 -25
  172. qiskit/qasm3/exporter.py +578 -481
  173. qiskit/qasm3/printer.py +7 -16
  174. qiskit/qobj/common.py +10 -0
  175. qiskit/qobj/converters/lo_config.py +9 -0
  176. qiskit/qobj/converters/pulse_instruction.py +13 -6
  177. qiskit/qobj/pulse_qobj.py +69 -15
  178. qiskit/qobj/qasm_qobj.py +72 -20
  179. qiskit/qobj/utils.py +9 -0
  180. qiskit/qpy/binary_io/circuits.py +8 -5
  181. qiskit/qpy/binary_io/schedules.py +1 -1
  182. qiskit/qpy/binary_io/value.py +3 -3
  183. qiskit/qpy/interface.py +3 -2
  184. qiskit/qpy/type_keys.py +2 -2
  185. qiskit/quantum_info/operators/channel/quantum_channel.py +3 -6
  186. qiskit/quantum_info/operators/channel/superop.py +2 -2
  187. qiskit/quantum_info/operators/channel/transformations.py +1 -1
  188. qiskit/quantum_info/operators/dihedral/dihedral.py +3 -4
  189. qiskit/quantum_info/operators/dihedral/dihedral_circuits.py +1 -3
  190. qiskit/quantum_info/operators/dihedral/random.py +6 -3
  191. qiskit/quantum_info/operators/measures.py +2 -2
  192. qiskit/quantum_info/operators/op_shape.py +12 -20
  193. qiskit/quantum_info/operators/operator.py +14 -21
  194. qiskit/quantum_info/operators/predicates.py +1 -0
  195. qiskit/quantum_info/operators/symplectic/base_pauli.py +7 -11
  196. qiskit/quantum_info/operators/symplectic/clifford.py +1 -1
  197. qiskit/quantum_info/operators/symplectic/pauli.py +3 -3
  198. qiskit/quantum_info/operators/symplectic/pauli_list.py +9 -10
  199. qiskit/quantum_info/operators/symplectic/random.py +1 -1
  200. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +14 -16
  201. qiskit/quantum_info/quaternion.py +1 -1
  202. qiskit/quantum_info/states/densitymatrix.py +5 -8
  203. qiskit/quantum_info/states/stabilizerstate.py +128 -37
  204. qiskit/quantum_info/states/statevector.py +4 -8
  205. qiskit/result/counts.py +2 -2
  206. qiskit/result/mitigation/correlated_readout_mitigator.py +2 -2
  207. qiskit/result/mitigation/local_readout_mitigator.py +2 -2
  208. qiskit/result/mitigation/utils.py +1 -3
  209. qiskit/result/models.py +17 -16
  210. qiskit/result/result.py +15 -20
  211. qiskit/scheduler/lowering.py +2 -2
  212. qiskit/synthesis/__init__.py +2 -1
  213. qiskit/synthesis/clifford/__init__.py +1 -1
  214. qiskit/synthesis/clifford/clifford_decompose_ag.py +2 -2
  215. qiskit/synthesis/clifford/clifford_decompose_bm.py +10 -240
  216. qiskit/synthesis/clifford/clifford_decompose_greedy.py +9 -303
  217. qiskit/synthesis/clifford/clifford_decompose_layers.py +25 -23
  218. qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_full.py +1 -1
  219. qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_general.py +1 -1
  220. qiskit/synthesis/discrete_basis/generate_basis_approximations.py +1 -1
  221. qiskit/synthesis/discrete_basis/solovay_kitaev.py +2 -2
  222. qiskit/synthesis/evolution/evolution_synthesis.py +4 -2
  223. qiskit/synthesis/evolution/lie_trotter.py +46 -19
  224. qiskit/synthesis/evolution/product_formula.py +111 -55
  225. qiskit/synthesis/evolution/qdrift.py +40 -10
  226. qiskit/synthesis/evolution/suzuki_trotter.py +43 -33
  227. qiskit/synthesis/linear/__init__.py +1 -0
  228. qiskit/synthesis/linear/cnot_synth.py +22 -96
  229. qiskit/synthesis/linear/linear_depth_lnn.py +8 -8
  230. qiskit/synthesis/linear/linear_matrix_utils.py +13 -161
  231. qiskit/synthesis/linear_phase/cnot_phase_synth.py +1 -1
  232. qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py +3 -3
  233. qiskit/synthesis/linear_phase/cz_depth_lnn.py +1 -1
  234. qiskit/synthesis/one_qubit/one_qubit_decompose.py +29 -29
  235. qiskit/synthesis/permutation/permutation_full.py +5 -29
  236. qiskit/synthesis/permutation/permutation_lnn.py +2 -24
  237. qiskit/synthesis/permutation/permutation_utils.py +2 -59
  238. qiskit/synthesis/qft/__init__.py +1 -0
  239. qiskit/synthesis/qft/qft_decompose_full.py +79 -0
  240. qiskit/synthesis/qft/qft_decompose_lnn.py +17 -9
  241. qiskit/synthesis/stabilizer/stabilizer_circuit.py +6 -6
  242. qiskit/synthesis/stabilizer/stabilizer_decompose.py +2 -2
  243. qiskit/synthesis/two_qubit/local_invariance.py +8 -38
  244. qiskit/synthesis/two_qubit/two_qubit_decompose.py +48 -129
  245. qiskit/synthesis/unitary/aqc/cnot_structures.py +1 -1
  246. qiskit/synthesis/unitary/qsd.py +5 -3
  247. qiskit/transpiler/__init__.py +1 -0
  248. qiskit/transpiler/basepasses.py +1 -1
  249. qiskit/transpiler/coupling.py +3 -3
  250. qiskit/transpiler/instruction_durations.py +1 -2
  251. qiskit/transpiler/layout.py +3 -3
  252. qiskit/transpiler/passes/__init__.py +2 -0
  253. qiskit/transpiler/passes/basis/basis_translator.py +82 -63
  254. qiskit/transpiler/passes/basis/translate_parameterized.py +3 -5
  255. qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
  256. qiskit/transpiler/passes/basis/unroll_custom_definitions.py +10 -10
  257. qiskit/transpiler/passes/calibration/rx_builder.py +3 -3
  258. qiskit/transpiler/passes/calibration/rzx_builder.py +3 -3
  259. qiskit/transpiler/passes/layout/apply_layout.py +13 -3
  260. qiskit/transpiler/passes/layout/sabre_layout.py +10 -8
  261. qiskit/transpiler/passes/layout/sabre_pre_layout.py +4 -1
  262. qiskit/transpiler/passes/layout/set_layout.py +2 -2
  263. qiskit/transpiler/passes/layout/vf2_layout.py +1 -1
  264. qiskit/transpiler/passes/layout/vf2_utils.py +3 -3
  265. qiskit/transpiler/passes/optimization/__init__.py +1 -0
  266. qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +2 -2
  267. qiskit/transpiler/passes/optimization/commutation_analysis.py +7 -10
  268. qiskit/transpiler/passes/optimization/commutative_cancellation.py +35 -19
  269. qiskit/transpiler/passes/optimization/consolidate_blocks.py +11 -8
  270. qiskit/transpiler/passes/optimization/inverse_cancellation.py +6 -6
  271. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +64 -41
  272. qiskit/transpiler/passes/optimization/optimize_1q_gates.py +1 -1
  273. qiskit/transpiler/passes/optimization/split_2q_unitaries.py +83 -0
  274. qiskit/transpiler/passes/optimization/template_matching/backward_match.py +1 -1
  275. qiskit/transpiler/passes/optimization/template_matching/forward_match.py +2 -2
  276. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +1 -1
  277. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +3 -2
  278. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/swap_strategy.py +1 -1
  279. qiskit/transpiler/passes/routing/layout_transformation.py +2 -1
  280. qiskit/transpiler/passes/routing/sabre_swap.py +35 -26
  281. qiskit/transpiler/passes/routing/star_prerouting.py +80 -105
  282. qiskit/transpiler/passes/routing/stochastic_swap.py +1 -3
  283. qiskit/transpiler/passes/scheduling/alap.py +1 -2
  284. qiskit/transpiler/passes/scheduling/alignments/__init__.py +2 -2
  285. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
  286. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +1 -1
  287. qiskit/transpiler/passes/scheduling/alignments/reschedule.py +1 -1
  288. qiskit/transpiler/passes/scheduling/asap.py +1 -2
  289. qiskit/transpiler/passes/scheduling/base_scheduler.py +5 -5
  290. qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +3 -3
  291. qiskit/transpiler/passes/scheduling/padding/base_padding.py +1 -1
  292. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +11 -11
  293. qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +7 -6
  294. qiskit/transpiler/passes/scheduling/time_unit_conversion.py +4 -3
  295. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +211 -36
  296. qiskit/transpiler/passes/synthesis/plugin.py +2 -2
  297. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +80 -40
  298. qiskit/transpiler/passes/utils/__init__.py +0 -1
  299. qiskit/transpiler/passes/utils/check_gate_direction.py +4 -4
  300. qiskit/transpiler/passes/utils/check_map.py +3 -6
  301. qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +3 -4
  302. qiskit/transpiler/passes/utils/error.py +2 -2
  303. qiskit/transpiler/passes/utils/fixed_point.py +3 -3
  304. qiskit/transpiler/passes/utils/gate_direction.py +1 -1
  305. qiskit/transpiler/passes/utils/gates_basis.py +1 -2
  306. qiskit/transpiler/passmanager.py +7 -6
  307. qiskit/transpiler/preset_passmanagers/__init__.py +4 -228
  308. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +117 -18
  309. qiskit/transpiler/preset_passmanagers/common.py +3 -6
  310. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +518 -0
  311. qiskit/transpiler/preset_passmanagers/level0.py +1 -1
  312. qiskit/transpiler/target.py +27 -8
  313. qiskit/user_config.py +29 -6
  314. qiskit/utils/classtools.py +3 -3
  315. qiskit/utils/deprecation.py +3 -2
  316. qiskit/utils/lazy_tester.py +2 -2
  317. qiskit/utils/optionals.py +8 -8
  318. qiskit/visualization/bloch.py +19 -67
  319. qiskit/visualization/circuit/_utils.py +34 -10
  320. qiskit/visualization/circuit/circuit_visualization.py +23 -16
  321. qiskit/visualization/circuit/latex.py +29 -27
  322. qiskit/visualization/circuit/matplotlib.py +4 -2
  323. qiskit/visualization/circuit/qcstyle.py +2 -2
  324. qiskit/visualization/circuit/text.py +9 -15
  325. qiskit/visualization/dag_visualization.py +5 -12
  326. qiskit/visualization/pulse_v2/core.py +1 -1
  327. qiskit/visualization/pulse_v2/events.py +1 -1
  328. qiskit/visualization/pulse_v2/generators/frame.py +3 -4
  329. qiskit/visualization/pulse_v2/generators/waveform.py +5 -9
  330. qiskit/visualization/pulse_v2/layouts.py +1 -5
  331. qiskit/visualization/pulse_v2/plotters/matplotlib.py +1 -2
  332. qiskit/visualization/state_visualization.py +5 -6
  333. qiskit/visualization/timeline/plotters/matplotlib.py +1 -2
  334. qiskit/visualization/transition_visualization.py +7 -2
  335. {qiskit-1.1.2.dist-info → qiskit-1.2.0rc1.dist-info}/METADATA +26 -26
  336. {qiskit-1.1.2.dist-info → qiskit-1.2.0rc1.dist-info}/RECORD +340 -338
  337. {qiskit-1.1.2.dist-info → qiskit-1.2.0rc1.dist-info}/WHEEL +1 -1
  338. {qiskit-1.1.2.dist-info → qiskit-1.2.0rc1.dist-info}/entry_points.txt +3 -0
  339. qiskit/transpiler/passes/utils/block_to_matrix.py +0 -47
  340. {qiskit-1.1.2.dist-info → qiskit-1.2.0rc1.dist-info}/LICENSE.txt +0 -0
  341. {qiskit-1.1.2.dist-info → qiskit-1.2.0rc1.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):
@@ -1359,10 +1380,10 @@ class DAGCircuit:
1359
1380
  "Replacing the specified node block would introduce a cycle"
1360
1381
  ) from ex
1361
1382
 
1362
- self._increment_op(op)
1383
+ self._increment_op(op.name)
1363
1384
 
1364
1385
  for nd in node_block:
1365
- self._decrement_op(nd.op)
1386
+ self._decrement_op(nd.name)
1366
1387
 
1367
1388
  return new_node
1368
1389
 
@@ -1411,7 +1432,7 @@ class DAGCircuit:
1411
1432
  node_wire_order = list(node.qargs) + list(node.cargs)
1412
1433
  # If we're not propagating it, the number of wires in the input DAG should include the
1413
1434
  # condition as well.
1414
- if not propagate_condition and _may_have_additional_wires(node.op):
1435
+ if not propagate_condition and _may_have_additional_wires(node):
1415
1436
  node_wire_order += [
1416
1437
  wire for wire in _additional_wires(node.op) if wire not in node_cargs
1417
1438
  ]
@@ -1433,7 +1454,7 @@ class DAGCircuit:
1433
1454
  raise DAGCircuitError(
1434
1455
  f"bit mapping invalid: {input_dag_wire} and {our_wire} are different bit types"
1435
1456
  )
1436
- if _may_have_additional_wires(node.op):
1457
+ if _may_have_additional_wires(node):
1437
1458
  node_vars = {var for var in _additional_wires(node.op) if isinstance(var, expr.Var)}
1438
1459
  else:
1439
1460
  node_vars = set()
@@ -1450,11 +1471,7 @@ class DAGCircuit:
1450
1471
  reverse_wire_map = {b: a for a, b in wire_map.items()}
1451
1472
  # It doesn't make sense to try and propagate a condition from a control-flow op; a
1452
1473
  # replacement for the control-flow op should implement the operation completely.
1453
- if (
1454
- propagate_condition
1455
- and not isinstance(node.op, ControlFlowOp)
1456
- and (op_condition := getattr(node.op, "condition", None)) is not None
1457
- ):
1474
+ if propagate_condition and not node.is_control_flow() and node.condition is not None:
1458
1475
  in_dag = input_dag.copy_empty_like()
1459
1476
  # The remapping of `condition` below is still using the old code that assumes a 2-tuple.
1460
1477
  # This is because this remapping code only makes sense in the case of non-control-flow
@@ -1463,7 +1480,7 @@ class DAGCircuit:
1463
1480
  # in favour of the new-style conditional blocks. The extra logic in here to add
1464
1481
  # additional wires into the map as necessary would hugely complicate matters if we tried
1465
1482
  # to abstract it out into the `VariableMapper` used elsewhere.
1466
- target, value = op_condition
1483
+ target, value = node.condition
1467
1484
  if isinstance(target, Clbit):
1468
1485
  new_target = reverse_wire_map.get(target, Clbit())
1469
1486
  if new_target not in wire_map:
@@ -1533,7 +1550,7 @@ class DAGCircuit:
1533
1550
  )[0]
1534
1551
  self._multi_graph.add_edge(pred._node_id, succ._node_id, contracted_var)
1535
1552
 
1536
- # 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
1537
1554
  # wires outside the set specified by the wires kwarg
1538
1555
  def filter_fn(node):
1539
1556
  if not isinstance(node, DAGOpNode):
@@ -1573,7 +1590,7 @@ class DAGCircuit:
1573
1590
  node_map = self._multi_graph.substitute_node_with_subgraph(
1574
1591
  node._node_id, in_dag._multi_graph, edge_map_fn, filter_fn, edge_weight_map
1575
1592
  )
1576
- self._decrement_op(node.op)
1593
+ self._decrement_op(node.name)
1577
1594
 
1578
1595
  variable_mapper = _classical_resource_map.VariableMapper(
1579
1596
  self.cregs.values(), wire_map, add_register=self.add_creg
@@ -1583,28 +1600,34 @@ class DAGCircuit:
1583
1600
  for old_node_index, new_node_index in node_map.items():
1584
1601
  # update node attributes
1585
1602
  old_node = in_dag._multi_graph[old_node_index]
1586
- if isinstance(old_node.op, SwitchCaseOp):
1603
+ m_op = None
1604
+ if not old_node.is_standard_gate() and isinstance(old_node.op, SwitchCaseOp):
1587
1605
  m_op = SwitchCaseOp(
1588
1606
  variable_mapper.map_target(old_node.op.target),
1589
1607
  old_node.op.cases_specifier(),
1590
1608
  label=old_node.op.label,
1591
1609
  )
1592
- elif getattr(old_node.op, "condition", None) is not None:
1610
+ elif old_node.condition is not None:
1593
1611
  m_op = old_node.op
1594
- 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:
1595
1615
  new_condition = variable_mapper.map_condition(m_op.condition)
1596
1616
  if new_condition is not None:
1597
1617
  m_op = m_op.c_if(*new_condition)
1598
- else:
1599
- m_op.condition = variable_mapper.map_condition(m_op.condition)
1600
- else:
1601
- m_op = old_node.op
1602
1618
  m_qargs = [wire_map[x] for x in old_node.qargs]
1603
1619
  m_cargs = [wire_map[x] for x in old_node.cargs]
1604
- 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)
1605
1628
  new_node._node_id = new_node_index
1606
1629
  self._multi_graph[new_node_index] = new_node
1607
- self._increment_op(new_node.op)
1630
+ self._increment_op(new_node.name)
1608
1631
 
1609
1632
  return {k: self._multi_graph[v] for k, v in node_map.items()}
1610
1633
 
@@ -1623,7 +1646,7 @@ class DAGCircuit:
1623
1646
  be used.
1624
1647
  propagate_condition (bool): Optional, default True. If True, a condition on the
1625
1648
  ``node`` to be replaced will be applied to the new ``op``. This is the legacy
1626
- 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
1627
1650
  the ``op`` already has a condition, :exc:`.DAGCircuitError` is raised.
1628
1651
 
1629
1652
  Returns:
@@ -1639,10 +1662,10 @@ class DAGCircuit:
1639
1662
 
1640
1663
  if node.op.num_qubits != op.num_qubits or node.op.num_clbits != op.num_clbits:
1641
1664
  raise DAGCircuitError(
1642
- "Cannot replace node of width ({} qubits, {} clbits) with "
1643
- "operation of mismatched width ({} qubits, {} clbits).".format(
1644
- node.op.num_qubits, node.op.num_clbits, op.num_qubits, op.num_clbits
1645
- )
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)."
1646
1669
  )
1647
1670
 
1648
1671
  # This might include wires that are inherent to the node, like in its `condition` or
@@ -1676,17 +1699,17 @@ class DAGCircuit:
1676
1699
 
1677
1700
  if inplace:
1678
1701
  if op.name != node.op.name:
1679
- self._increment_op(op)
1680
- self._decrement_op(node.op)
1702
+ self._increment_op(op.name)
1703
+ self._decrement_op(node.name)
1681
1704
  node.op = op
1682
1705
  return node
1683
1706
 
1684
1707
  new_node = copy.copy(node)
1685
1708
  new_node.op = op
1686
1709
  self._multi_graph[node._node_id] = new_node
1687
- if op.name != node.op.name:
1688
- self._increment_op(op)
1689
- self._decrement_op(node.op)
1710
+ if op.name != node.name:
1711
+ self._increment_op(op.name)
1712
+ self._decrement_op(node.name)
1690
1713
  return new_node
1691
1714
 
1692
1715
  def separable_circuits(
@@ -1830,11 +1853,18 @@ class DAGCircuit:
1830
1853
  list[DAGOpNode]: the list of node ids containing the given op.
1831
1854
  """
1832
1855
  nodes = []
1856
+ filter_is_nonstandard = getattr(op, "_standard_gate", None) is None
1833
1857
  for node in self._multi_graph.nodes():
1834
1858
  if isinstance(node, DAGOpNode):
1835
- if not include_directives and getattr(node.op, "_directive", False):
1859
+ if not include_directives and node.is_directive():
1836
1860
  continue
1837
- 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
+ ):
1838
1868
  nodes.append(node)
1839
1869
  return nodes
1840
1870
 
@@ -1854,7 +1884,7 @@ class DAGCircuit:
1854
1884
  """Get the set of "op" nodes with the given name."""
1855
1885
  named_nodes = []
1856
1886
  for node in self._multi_graph.nodes():
1857
- if isinstance(node, DAGOpNode) and node.op.name in names:
1887
+ if isinstance(node, DAGOpNode) and node.name in names:
1858
1888
  named_nodes.append(node)
1859
1889
  return named_nodes
1860
1890
 
@@ -1960,14 +1990,12 @@ class DAGCircuit:
1960
1990
  """
1961
1991
  if not isinstance(node, DAGOpNode):
1962
1992
  raise DAGCircuitError(
1963
- 'The method remove_op_node only works on DAGOpNodes. A "%s" '
1964
- "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."
1965
1995
  )
1966
1996
 
1967
- self._multi_graph.remove_node_retain_edges(
1968
- node._node_id, use_outgoing=False, condition=lambda edge1, edge2: edge1 == edge2
1969
- )
1970
- self._decrement_op(node.op)
1997
+ self._multi_graph.remove_node_retain_edges_by_id(node._node_id)
1998
+ self._decrement_op(node.name)
1971
1999
 
1972
2000
  def remove_ancestors_of(self, node):
1973
2001
  """Remove all of the ancestor operation nodes of node."""
@@ -2062,14 +2090,11 @@ class DAGCircuit:
2062
2090
  new_layer = self.copy_empty_like(vars_mode=vars_mode)
2063
2091
 
2064
2092
  for node in op_nodes:
2065
- # this creates new DAGOpNodes in the new_layer
2066
- new_layer.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
2093
+ new_layer._apply_op_node_back(node, check=False)
2067
2094
 
2068
2095
  # The quantum registers that have an operation in this layer.
2069
2096
  support_list = [
2070
- op_node.qargs
2071
- for op_node in new_layer.op_nodes()
2072
- 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()
2073
2098
  ]
2074
2099
 
2075
2100
  yield {"graph": new_layer, "partition": support_list}
@@ -2121,56 +2146,25 @@ class DAGCircuit:
2121
2146
  """
2122
2147
 
2123
2148
  def filter_fn(node):
2124
- return (
2125
- isinstance(node, DAGOpNode)
2126
- and node.op.name in namelist
2127
- and getattr(node.op, "condition", None) is None
2128
- )
2149
+ return isinstance(node, DAGOpNode) and node.name in namelist and node.condition is None
2129
2150
 
2130
2151
  group_list = rx.collect_runs(self._multi_graph, filter_fn)
2131
2152
  return {tuple(x) for x in group_list}
2132
2153
 
2133
2154
  def collect_1q_runs(self) -> list[list[DAGOpNode]]:
2134
2155
  """Return a set of non-conditional runs of 1q "op" nodes."""
2135
-
2136
- def filter_fn(node):
2137
- return (
2138
- isinstance(node, DAGOpNode)
2139
- and len(node.qargs) == 1
2140
- and len(node.cargs) == 0
2141
- and isinstance(node.op, Gate)
2142
- and hasattr(node.op, "__array__")
2143
- and getattr(node.op, "condition", None) is None
2144
- and not node.op.is_parameterized()
2145
- )
2146
-
2147
- return rx.collect_runs(self._multi_graph, filter_fn)
2156
+ return rx.collect_runs(self._multi_graph, collect_1q_runs_filter)
2148
2157
 
2149
2158
  def collect_2q_runs(self):
2150
2159
  """Return a set of non-conditional runs of 2q "op" nodes."""
2151
2160
 
2152
- to_qid = {}
2153
- for i, qubit in enumerate(self.qubits):
2154
- to_qid[qubit] = i
2155
-
2156
- def filter_fn(node):
2157
- if isinstance(node, DAGOpNode):
2158
- return (
2159
- isinstance(node.op, Gate)
2160
- and len(node.qargs) <= 2
2161
- and not getattr(node.op, "condition", None)
2162
- and not node.op.is_parameterized()
2163
- )
2164
- else:
2165
- return None
2166
-
2167
2161
  def color_fn(edge):
2168
2162
  if isinstance(edge, Qubit):
2169
- return to_qid[edge]
2163
+ return self.find_bit(edge).index
2170
2164
  else:
2171
2165
  return None
2172
2166
 
2173
- 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)
2174
2168
 
2175
2169
  def nodes_on_wire(self, wire, only_ops=False):
2176
2170
  """
@@ -2189,7 +2183,7 @@ class DAGCircuit:
2189
2183
  current_node = self.input_map.get(wire, None)
2190
2184
 
2191
2185
  if not current_node:
2192
- 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")
2193
2187
 
2194
2188
  more_nodes = True
2195
2189
  while more_nodes:
@@ -2272,36 +2266,44 @@ class DAGCircuit:
2272
2266
  output_node = self.output_map.get(qubit, None)
2273
2267
  if not output_node:
2274
2268
  raise DAGCircuitError(f"Qubit {qubit} is not part of this circuit.")
2275
- # Add the qubit to the causal cone.
2276
- qubits_to_check = {qubit}
2277
- # Add predecessors of output node to the queue.
2278
- queue = deque(self.predecessors(output_node))
2279
2269
 
2280
- # 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
+
2281
2281
  while queue:
2282
- # Pop first element.
2283
2282
  node_to_check = queue.popleft()
2284
- # Check whether element is input or output node.
2283
+
2285
2284
  if isinstance(node_to_check, DAGOpNode):
2286
- # Keep all the qubits in the operation inside a set.
2287
- qubit_set = set(node_to_check.qargs)
2288
- # Check if there are any qubits in common and that the operation is not a barrier.
2289
- if (
2290
- len(qubit_set.intersection(qubits_to_check)) > 0
2291
- and node_to_check.op.name != "barrier"
2292
- and not getattr(node_to_check.op, "_directive")
2293
- ):
2294
- # If so, add all the qubits to the causal cone.
2295
- qubits_to_check = qubits_to_check.union(qubit_set)
2296
- # For each predecessor of the current node, filter input/output nodes,
2297
- # also make sure it has at least one qubit in common. Then append.
2298
- for node in self.quantum_predecessors(node_to_check):
2299
- if (
2300
- isinstance(node, DAGOpNode)
2301
- and len(qubits_to_check.intersection(set(node.qargs))) > 0
2302
- ):
2303
- queue.append(node)
2304
- 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
2305
2307
 
2306
2308
  def properties(self):
2307
2309
  """Return a dictionary of circuit properties."""
@@ -2359,24 +2361,25 @@ class _DAGVarInfo:
2359
2361
  self.out_node = out_node
2360
2362
 
2361
2363
 
2362
- def _may_have_additional_wires(operation) -> bool:
2363
- """Return whether a given :class:`.Operation` may contain references to additional wires
2364
- locations within itself. If this is ``False``, it doesn't necessarily mean that the operation
2365
- _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.
2366
2369
 
2367
2370
  The memory might be classical bits or classical variables, such as a control-flow operation or a
2368
2371
  store.
2369
2372
 
2370
2373
  Args:
2371
- operation (qiskit.circuit.Operation): the operation to check.
2374
+ operation (qiskit.dagcircuit.DAGOpNode): the operation to check.
2372
2375
  """
2373
2376
  # This is separate to `_additional_wires` because most of the time there won't be any extra
2374
2377
  # wires beyond the explicit `qargs` and `cargs` so we want a fast path to be able to skip
2375
2378
  # creating and testing a generator for emptiness.
2376
2379
  #
2377
2380
  # If updating this, you most likely also need to update `_additional_wires`.
2378
- return getattr(operation, "condition", None) is not None or isinstance(
2379
- operation, (ControlFlowOp, Store)
2381
+ return node.condition is not None or (
2382
+ not node.is_standard_gate() and isinstance(node.op, (ControlFlowOp, Store))
2380
2383
  )
2381
2384
 
2382
2385