qiskit 1.4.1__cp39-abi3-macosx_11_0_arm64.whl → 2.0.0__cp39-abi3-macosx_11_0_arm64.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 (462) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/__init__.py +3 -9
  3. qiskit/_accelerate.abi3.so +0 -0
  4. qiskit/circuit/__init__.py +35 -10
  5. qiskit/circuit/{add_control.py → _add_control.py} +32 -12
  6. qiskit/circuit/_classical_resource_map.py +5 -3
  7. qiskit/circuit/barrier.py +3 -7
  8. qiskit/circuit/classical/expr/__init__.py +31 -3
  9. qiskit/circuit/classical/expr/constructors.py +236 -28
  10. qiskit/circuit/classical/expr/expr.py +104 -3
  11. qiskit/circuit/classical/expr/visitors.py +75 -0
  12. qiskit/circuit/classical/types/__init__.py +12 -8
  13. qiskit/circuit/classical/types/ordering.py +14 -7
  14. qiskit/circuit/classical/types/types.py +36 -0
  15. qiskit/circuit/commutation_checker.py +34 -7
  16. qiskit/circuit/controlflow/__init__.py +32 -1
  17. qiskit/circuit/controlflow/_builder_utils.py +9 -5
  18. qiskit/circuit/controlflow/box.py +163 -0
  19. qiskit/circuit/controlflow/break_loop.py +1 -1
  20. qiskit/circuit/controlflow/builder.py +139 -39
  21. qiskit/circuit/controlflow/continue_loop.py +1 -3
  22. qiskit/circuit/controlflow/control_flow.py +10 -0
  23. qiskit/circuit/controlflow/for_loop.py +2 -1
  24. qiskit/circuit/controlflow/if_else.py +3 -16
  25. qiskit/circuit/controlflow/switch_case.py +2 -8
  26. qiskit/circuit/controlflow/while_loop.py +2 -7
  27. qiskit/circuit/controlledgate.py +2 -4
  28. qiskit/circuit/delay.py +40 -11
  29. qiskit/circuit/duration.py +0 -15
  30. qiskit/circuit/gate.py +2 -4
  31. qiskit/circuit/instruction.py +2 -141
  32. qiskit/circuit/instructionset.py +7 -54
  33. qiskit/circuit/library/__init__.py +469 -154
  34. qiskit/circuit/library/arithmetic/__init__.py +16 -10
  35. qiskit/circuit/library/arithmetic/adders/cdkm_ripple_carry_adder.py +1 -1
  36. qiskit/circuit/library/arithmetic/adders/draper_qft_adder.py +2 -2
  37. qiskit/circuit/library/arithmetic/adders/vbe_ripple_carry_adder.py +1 -1
  38. qiskit/circuit/library/arithmetic/exact_reciprocal.py +64 -21
  39. qiskit/circuit/library/arithmetic/integer_comparator.py +37 -80
  40. qiskit/circuit/library/arithmetic/linear_amplitude_function.py +169 -2
  41. qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +59 -5
  42. qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +154 -6
  43. qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +114 -4
  44. qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +191 -15
  45. qiskit/circuit/library/arithmetic/polynomial_pauli_rotations.py +93 -39
  46. qiskit/circuit/library/arithmetic/quadratic_form.py +168 -2
  47. qiskit/circuit/library/arithmetic/weighted_adder.py +73 -1
  48. qiskit/circuit/library/bit_flip_oracle.py +130 -0
  49. qiskit/circuit/library/blueprintcircuit.py +52 -16
  50. qiskit/circuit/library/data_preparation/initializer.py +1 -1
  51. qiskit/circuit/library/data_preparation/pauli_feature_map.py +4 -4
  52. qiskit/circuit/library/data_preparation/state_preparation.py +1 -1
  53. qiskit/circuit/library/generalized_gates/gms.py +1 -1
  54. qiskit/circuit/library/generalized_gates/isometry.py +1 -1
  55. qiskit/circuit/library/generalized_gates/pauli.py +1 -2
  56. qiskit/circuit/library/generalized_gates/uc.py +97 -7
  57. qiskit/circuit/library/generalized_gates/uc_pauli_rot.py +1 -1
  58. qiskit/circuit/library/generalized_gates/unitary.py +4 -2
  59. qiskit/circuit/library/graph_state.py +1 -0
  60. qiskit/circuit/library/hamiltonian_gate.py +1 -1
  61. qiskit/circuit/library/n_local/evolved_operator_ansatz.py +1 -1
  62. qiskit/circuit/library/n_local/n_local.py +1 -1
  63. qiskit/circuit/library/n_local/qaoa_ansatz.py +1 -1
  64. qiskit/circuit/library/overlap.py +2 -2
  65. qiskit/circuit/library/pauli_evolution.py +39 -24
  66. qiskit/circuit/library/phase_oracle.py +130 -51
  67. qiskit/circuit/library/standard_gates/__init__.py +0 -1
  68. qiskit/circuit/library/standard_gates/dcx.py +3 -4
  69. qiskit/circuit/library/standard_gates/ecr.py +3 -4
  70. qiskit/circuit/library/standard_gates/global_phase.py +5 -6
  71. qiskit/circuit/library/standard_gates/h.py +4 -9
  72. qiskit/circuit/library/standard_gates/i.py +2 -2
  73. qiskit/circuit/library/standard_gates/iswap.py +3 -4
  74. qiskit/circuit/library/standard_gates/p.py +15 -34
  75. qiskit/circuit/library/standard_gates/r.py +7 -10
  76. qiskit/circuit/library/standard_gates/rx.py +5 -15
  77. qiskit/circuit/library/standard_gates/rxx.py +3 -6
  78. qiskit/circuit/library/standard_gates/ry.py +5 -17
  79. qiskit/circuit/library/standard_gates/ryy.py +3 -6
  80. qiskit/circuit/library/standard_gates/rz.py +5 -17
  81. qiskit/circuit/library/standard_gates/rzx.py +3 -6
  82. qiskit/circuit/library/standard_gates/rzz.py +3 -6
  83. qiskit/circuit/library/standard_gates/s.py +6 -15
  84. qiskit/circuit/library/standard_gates/swap.py +4 -11
  85. qiskit/circuit/library/standard_gates/sx.py +7 -12
  86. qiskit/circuit/library/standard_gates/t.py +6 -7
  87. qiskit/circuit/library/standard_gates/u.py +2 -10
  88. qiskit/circuit/library/standard_gates/u1.py +5 -16
  89. qiskit/circuit/library/standard_gates/u2.py +2 -6
  90. qiskit/circuit/library/standard_gates/u3.py +3 -11
  91. qiskit/circuit/library/standard_gates/x.py +14 -62
  92. qiskit/circuit/library/standard_gates/xx_minus_yy.py +2 -5
  93. qiskit/circuit/library/standard_gates/xx_plus_yy.py +2 -5
  94. qiskit/circuit/library/standard_gates/y.py +4 -9
  95. qiskit/circuit/library/standard_gates/z.py +5 -15
  96. qiskit/circuit/measure.py +11 -2
  97. qiskit/circuit/parameterexpression.py +11 -0
  98. qiskit/circuit/quantumcircuit.py +890 -564
  99. qiskit/circuit/random/utils.py +12 -6
  100. qiskit/circuit/reset.py +5 -2
  101. qiskit/circuit/singleton.py +5 -11
  102. qiskit/circuit/store.py +0 -8
  103. qiskit/circuit/tools/pi_check.py +3 -0
  104. qiskit/compiler/__init__.py +1 -7
  105. qiskit/compiler/transpiler.py +38 -196
  106. qiskit/converters/circuit_to_dag.py +6 -4
  107. qiskit/converters/circuit_to_dagdependency.py +0 -2
  108. qiskit/converters/circuit_to_dagdependency_v2.py +0 -1
  109. qiskit/converters/circuit_to_gate.py +1 -1
  110. qiskit/converters/circuit_to_instruction.py +16 -29
  111. qiskit/converters/dag_to_circuit.py +7 -8
  112. qiskit/converters/dag_to_dagdependency.py +0 -1
  113. qiskit/converters/dag_to_dagdependency_v2.py +0 -1
  114. qiskit/converters/dagdependency_to_circuit.py +0 -6
  115. qiskit/converters/dagdependency_to_dag.py +0 -6
  116. qiskit/dagcircuit/collect_blocks.py +32 -20
  117. qiskit/dagcircuit/dagdependency.py +3 -37
  118. qiskit/dagcircuit/dagdependency_v2.py +5 -82
  119. qiskit/dagcircuit/dagnode.py +14 -2
  120. qiskit/passmanager/__init__.py +24 -6
  121. qiskit/passmanager/passmanager.py +26 -24
  122. qiskit/primitives/__init__.py +44 -35
  123. qiskit/primitives/backend_estimator_v2.py +102 -23
  124. qiskit/primitives/backend_sampler_v2.py +5 -20
  125. qiskit/primitives/base/__init__.py +4 -4
  126. qiskit/primitives/base/base_estimator.py +77 -82
  127. qiskit/primitives/base/base_primitive_job.py +2 -2
  128. qiskit/primitives/base/{base_primitive.py → base_primitive_v1.py} +1 -1
  129. qiskit/primitives/base/{base_result.py → base_result_v1.py} +1 -1
  130. qiskit/primitives/base/base_sampler.py +52 -60
  131. qiskit/primitives/base/{estimator_result.py → estimator_result_v1.py} +2 -2
  132. qiskit/primitives/base/{sampler_result.py → sampler_result_v1.py} +2 -2
  133. qiskit/primitives/base/{validation.py → validation_v1.py} +34 -15
  134. qiskit/primitives/containers/bindings_array.py +3 -1
  135. qiskit/primitives/containers/bit_array.py +23 -0
  136. qiskit/primitives/containers/data_bin.py +3 -1
  137. qiskit/primitives/containers/observables_array.py +19 -2
  138. qiskit/primitives/statevector_sampler.py +6 -8
  139. qiskit/primitives/utils.py +14 -189
  140. qiskit/providers/__init__.py +4 -130
  141. qiskit/providers/backend.py +11 -314
  142. qiskit/providers/basic_provider/__init__.py +3 -1
  143. qiskit/providers/basic_provider/basic_provider.py +29 -9
  144. qiskit/providers/basic_provider/basic_simulator.py +158 -298
  145. qiskit/providers/exceptions.py +0 -33
  146. qiskit/providers/fake_provider/__init__.py +0 -37
  147. qiskit/providers/fake_provider/generic_backend_v2.py +32 -693
  148. qiskit/qasm2/__init__.py +21 -6
  149. qiskit/qasm2/export.py +2 -10
  150. qiskit/qasm2/parse.py +11 -25
  151. qiskit/qasm3/__init__.py +5 -1
  152. qiskit/qasm3/ast.py +44 -0
  153. qiskit/qasm3/exporter.py +65 -27
  154. qiskit/qasm3/printer.py +35 -4
  155. qiskit/qpy/__init__.py +162 -19
  156. qiskit/qpy/binary_io/__init__.py +0 -1
  157. qiskit/qpy/binary_io/circuits.py +96 -116
  158. qiskit/qpy/binary_io/parse_sympy_repr.py +121 -0
  159. qiskit/qpy/binary_io/schedules.py +61 -388
  160. qiskit/qpy/binary_io/value.py +159 -33
  161. qiskit/qpy/common.py +10 -7
  162. qiskit/qpy/formats.py +41 -0
  163. qiskit/qpy/interface.py +29 -62
  164. qiskit/qpy/type_keys.py +58 -221
  165. qiskit/quantum_info/analysis/distance.py +3 -1
  166. qiskit/quantum_info/operators/dihedral/dihedral.py +3 -1
  167. qiskit/quantum_info/operators/operator.py +6 -2
  168. qiskit/quantum_info/operators/symplectic/clifford.py +3 -1
  169. qiskit/quantum_info/operators/symplectic/pauli.py +4 -2
  170. qiskit/quantum_info/operators/symplectic/pauli_list.py +17 -5
  171. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +40 -6
  172. qiskit/quantum_info/states/densitymatrix.py +16 -6
  173. qiskit/quantum_info/states/stabilizerstate.py +35 -4
  174. qiskit/quantum_info/states/statevector.py +16 -6
  175. qiskit/result/__init__.py +5 -17
  176. qiskit/result/models.py +18 -11
  177. qiskit/result/result.py +38 -134
  178. qiskit/result/sampled_expval.py +1 -2
  179. qiskit/result/utils.py +3 -4
  180. qiskit/synthesis/__init__.py +21 -1
  181. qiskit/synthesis/arithmetic/__init__.py +3 -1
  182. qiskit/synthesis/arithmetic/adders/cdkm_ripple_carry_adder.py +1 -1
  183. qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +1 -1
  184. qiskit/synthesis/arithmetic/adders/vbe_ripple_carry_adder.py +2 -2
  185. qiskit/{providers/fake_provider/backends_v1/fake_20q → synthesis/arithmetic/comparators}/__init__.py +4 -6
  186. qiskit/synthesis/arithmetic/comparators/compare_2s.py +112 -0
  187. qiskit/synthesis/arithmetic/comparators/compare_greedy.py +66 -0
  188. qiskit/synthesis/arithmetic/multipliers/hrs_cumulative_multiplier.py +1 -1
  189. qiskit/synthesis/arithmetic/multipliers/rg_qft_multiplier.py +1 -1
  190. qiskit/synthesis/arithmetic/weighted_sum.py +155 -0
  191. qiskit/{result/mitigation → synthesis/boolean}/__init__.py +2 -2
  192. qiskit/synthesis/boolean/boolean_expression.py +231 -0
  193. qiskit/synthesis/boolean/boolean_expression_synth.py +124 -0
  194. qiskit/synthesis/boolean/boolean_expression_visitor.py +96 -0
  195. qiskit/synthesis/discrete_basis/generate_basis_approximations.py +2 -0
  196. qiskit/synthesis/evolution/lie_trotter.py +10 -7
  197. qiskit/synthesis/evolution/product_formula.py +44 -35
  198. qiskit/synthesis/evolution/qdrift.py +17 -24
  199. qiskit/synthesis/evolution/suzuki_trotter.py +20 -27
  200. qiskit/synthesis/linear/linear_depth_lnn.py +6 -221
  201. qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py +4 -205
  202. qiskit/synthesis/multi_controlled/__init__.py +1 -0
  203. qiskit/synthesis/multi_controlled/mcx_synthesis.py +5 -2
  204. qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +206 -0
  205. qiskit/synthesis/one_qubit/one_qubit_decompose.py +1 -1
  206. qiskit/synthesis/two_qubit/__init__.py +1 -0
  207. qiskit/synthesis/two_qubit/two_qubit_decompose.py +28 -145
  208. qiskit/transpiler/__init__.py +32 -232
  209. qiskit/transpiler/basepasses.py +20 -51
  210. qiskit/transpiler/layout.py +1 -1
  211. qiskit/transpiler/passes/__init__.py +4 -40
  212. qiskit/transpiler/passes/basis/basis_translator.py +5 -4
  213. qiskit/transpiler/passes/basis/decompose.py +1 -15
  214. qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -5
  215. qiskit/transpiler/passes/basis/unroll_custom_definitions.py +3 -2
  216. qiskit/transpiler/passes/layout/apply_layout.py +4 -0
  217. qiskit/transpiler/passes/layout/dense_layout.py +2 -39
  218. qiskit/transpiler/passes/layout/full_ancilla_allocation.py +3 -4
  219. qiskit/transpiler/passes/layout/sabre_layout.py +7 -3
  220. qiskit/transpiler/passes/layout/vf2_layout.py +2 -20
  221. qiskit/transpiler/passes/layout/vf2_post_layout.py +60 -125
  222. qiskit/transpiler/passes/layout/vf2_utils.py +2 -26
  223. qiskit/transpiler/passes/optimization/__init__.py +2 -3
  224. qiskit/transpiler/passes/optimization/collect_and_collapse.py +2 -0
  225. qiskit/transpiler/passes/optimization/collect_cliffords.py +5 -0
  226. qiskit/transpiler/passes/optimization/collect_linear_functions.py +5 -0
  227. qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +16 -1
  228. qiskit/transpiler/passes/optimization/commutation_analysis.py +3 -3
  229. qiskit/transpiler/passes/optimization/consolidate_blocks.py +41 -19
  230. qiskit/transpiler/passes/optimization/contract_idle_wires_in_control_flow.py +104 -0
  231. qiskit/transpiler/passes/optimization/light_cone.py +135 -0
  232. qiskit/transpiler/passes/optimization/optimize_1q_commutation.py +0 -1
  233. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +18 -22
  234. qiskit/transpiler/passes/optimization/optimize_annotated.py +3 -2
  235. qiskit/transpiler/passes/optimization/remove_identity_equiv.py +6 -4
  236. qiskit/transpiler/passes/optimization/reset_after_measure_simplification.py +5 -2
  237. qiskit/transpiler/passes/optimization/split_2q_unitaries.py +26 -3
  238. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +3 -2
  239. qiskit/transpiler/passes/routing/__init__.py +0 -1
  240. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +3 -1
  241. qiskit/transpiler/passes/routing/sabre_swap.py +14 -6
  242. qiskit/transpiler/passes/routing/star_prerouting.py +1 -1
  243. qiskit/transpiler/passes/scheduling/__init__.py +1 -7
  244. qiskit/transpiler/passes/scheduling/alignments/__init__.py +2 -4
  245. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -9
  246. qiskit/transpiler/passes/scheduling/alignments/reschedule.py +17 -16
  247. qiskit/transpiler/passes/scheduling/padding/base_padding.py +32 -4
  248. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +25 -63
  249. qiskit/transpiler/passes/scheduling/padding/pad_delay.py +12 -4
  250. qiskit/transpiler/passes/scheduling/scheduling/alap.py +5 -39
  251. qiskit/transpiler/passes/scheduling/scheduling/asap.py +4 -35
  252. qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +10 -16
  253. qiskit/transpiler/passes/scheduling/time_unit_conversion.py +134 -62
  254. qiskit/transpiler/passes/synthesis/default_unitary_synth_plugin.py +653 -0
  255. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +176 -601
  256. qiskit/transpiler/passes/synthesis/hls_plugins.py +294 -1
  257. qiskit/transpiler/passes/synthesis/plugin.py +4 -0
  258. qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +16 -10
  259. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +34 -697
  260. qiskit/transpiler/passes/utils/__init__.py +0 -1
  261. qiskit/transpiler/passes/utils/check_gate_direction.py +13 -5
  262. qiskit/transpiler/passes/utils/control_flow.py +2 -6
  263. qiskit/transpiler/passes/utils/gate_direction.py +7 -0
  264. qiskit/transpiler/passes/utils/remove_final_measurements.py +40 -33
  265. qiskit/transpiler/passmanager.py +13 -0
  266. qiskit/transpiler/passmanager_config.py +5 -81
  267. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +225 -344
  268. qiskit/transpiler/preset_passmanagers/common.py +140 -167
  269. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +107 -322
  270. qiskit/transpiler/preset_passmanagers/level0.py +2 -11
  271. qiskit/transpiler/preset_passmanagers/level1.py +2 -14
  272. qiskit/transpiler/preset_passmanagers/level2.py +2 -12
  273. qiskit/transpiler/preset_passmanagers/level3.py +2 -11
  274. qiskit/transpiler/preset_passmanagers/plugin.py +5 -3
  275. qiskit/transpiler/target.py +78 -524
  276. qiskit/user_config.py +8 -4
  277. qiskit/utils/__init__.py +13 -12
  278. qiskit/utils/deprecation.py +4 -112
  279. qiskit/utils/optionals.py +11 -4
  280. qiskit/utils/parallel.py +214 -87
  281. qiskit/utils/units.py +4 -1
  282. qiskit/visualization/__init__.py +3 -7
  283. qiskit/visualization/array.py +4 -1
  284. qiskit/visualization/bloch.py +1 -1
  285. qiskit/visualization/circuit/_utils.py +19 -19
  286. qiskit/visualization/circuit/circuit_visualization.py +11 -4
  287. qiskit/visualization/circuit/matplotlib.py +13 -23
  288. qiskit/visualization/circuit/text.py +7 -3
  289. qiskit/visualization/counts_visualization.py +4 -0
  290. qiskit/visualization/dag_visualization.py +2 -1
  291. qiskit/visualization/gate_map.py +39 -154
  292. qiskit/visualization/library.py +4 -1
  293. qiskit/visualization/pass_manager_visualization.py +6 -2
  294. qiskit/visualization/state_visualization.py +19 -2
  295. qiskit/visualization/timeline/core.py +19 -13
  296. qiskit/visualization/timeline/interface.py +19 -18
  297. qiskit/visualization/timeline/plotters/matplotlib.py +4 -1
  298. {qiskit-1.4.1.dist-info → qiskit-2.0.0.dist-info}/METADATA +4 -3
  299. {qiskit-1.4.1.dist-info → qiskit-2.0.0.dist-info}/RECORD +303 -449
  300. {qiskit-1.4.1.dist-info → qiskit-2.0.0.dist-info}/WHEEL +2 -1
  301. {qiskit-1.4.1.dist-info → qiskit-2.0.0.dist-info}/entry_points.txt +8 -2
  302. qiskit/assembler/__init__.py +0 -42
  303. qiskit/assembler/assemble_circuits.py +0 -451
  304. qiskit/assembler/assemble_schedules.py +0 -367
  305. qiskit/assembler/disassemble.py +0 -310
  306. qiskit/assembler/run_config.py +0 -77
  307. qiskit/circuit/bit.py +0 -106
  308. qiskit/circuit/classicalfunction/__init__.py +0 -152
  309. qiskit/circuit/classicalfunction/boolean_expression.py +0 -138
  310. qiskit/circuit/classicalfunction/classical_element.py +0 -54
  311. qiskit/circuit/classicalfunction/classical_function_visitor.py +0 -155
  312. qiskit/circuit/classicalfunction/classicalfunction.py +0 -182
  313. qiskit/circuit/classicalfunction/exceptions.py +0 -41
  314. qiskit/circuit/classicalfunction/types.py +0 -18
  315. qiskit/circuit/classicalfunction/utils.py +0 -91
  316. qiskit/circuit/classicalregister.py +0 -57
  317. qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +0 -405
  318. qiskit/circuit/quantumregister.py +0 -75
  319. qiskit/circuit/register.py +0 -246
  320. qiskit/compiler/assembler.py +0 -689
  321. qiskit/compiler/scheduler.py +0 -109
  322. qiskit/compiler/sequencer.py +0 -71
  323. qiskit/primitives/backend_estimator.py +0 -486
  324. qiskit/primitives/backend_sampler.py +0 -222
  325. qiskit/primitives/estimator.py +0 -172
  326. qiskit/primitives/sampler.py +0 -162
  327. qiskit/providers/backend_compat.py +0 -507
  328. qiskit/providers/fake_provider/backends_v1/__init__.py +0 -22
  329. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/__init__.py +0 -18
  330. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/conf_washington.json +0 -1
  331. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/defs_washington.json +0 -1
  332. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/fake_127q_pulse_v1.py +0 -37
  333. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/props_washington.json +0 -1
  334. qiskit/providers/fake_provider/backends_v1/fake_20q/conf_singapore.json +0 -1
  335. qiskit/providers/fake_provider/backends_v1/fake_20q/fake_20q.py +0 -43
  336. qiskit/providers/fake_provider/backends_v1/fake_20q/props_singapore.json +0 -1
  337. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/__init__.py +0 -18
  338. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/conf_hanoi.json +0 -1
  339. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/defs_hanoi.json +0 -1
  340. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/fake_27q_pulse_v1.py +0 -50
  341. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/props_hanoi.json +0 -1
  342. qiskit/providers/fake_provider/backends_v1/fake_5q/__init__.py +0 -18
  343. qiskit/providers/fake_provider/backends_v1/fake_5q/conf_yorktown.json +0 -1
  344. qiskit/providers/fake_provider/backends_v1/fake_5q/fake_5q_v1.py +0 -41
  345. qiskit/providers/fake_provider/backends_v1/fake_5q/props_yorktown.json +0 -1
  346. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/__init__.py +0 -18
  347. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/conf_nairobi.json +0 -1
  348. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/defs_nairobi.json +0 -1
  349. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/fake_7q_pulse_v1.py +0 -44
  350. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/props_nairobi.json +0 -1
  351. qiskit/providers/fake_provider/fake_1q.py +0 -91
  352. qiskit/providers/fake_provider/fake_backend.py +0 -165
  353. qiskit/providers/fake_provider/fake_openpulse_2q.py +0 -391
  354. qiskit/providers/fake_provider/fake_openpulse_3q.py +0 -340
  355. qiskit/providers/fake_provider/fake_pulse_backend.py +0 -49
  356. qiskit/providers/fake_provider/fake_qasm_backend.py +0 -77
  357. qiskit/providers/fake_provider/utils/backend_converter.py +0 -150
  358. qiskit/providers/fake_provider/utils/json_decoder.py +0 -109
  359. qiskit/providers/models/__init__.py +0 -89
  360. qiskit/providers/models/backendconfiguration.py +0 -1040
  361. qiskit/providers/models/backendproperties.py +0 -535
  362. qiskit/providers/models/backendstatus.py +0 -104
  363. qiskit/providers/models/jobstatus.py +0 -77
  364. qiskit/providers/models/pulsedefaults.py +0 -305
  365. qiskit/providers/provider.py +0 -95
  366. qiskit/pulse/__init__.py +0 -158
  367. qiskit/pulse/builder.py +0 -2262
  368. qiskit/pulse/calibration_entries.py +0 -381
  369. qiskit/pulse/channels.py +0 -227
  370. qiskit/pulse/configuration.py +0 -245
  371. qiskit/pulse/exceptions.py +0 -45
  372. qiskit/pulse/filters.py +0 -309
  373. qiskit/pulse/instruction_schedule_map.py +0 -424
  374. qiskit/pulse/instructions/__init__.py +0 -67
  375. qiskit/pulse/instructions/acquire.py +0 -150
  376. qiskit/pulse/instructions/delay.py +0 -71
  377. qiskit/pulse/instructions/directives.py +0 -154
  378. qiskit/pulse/instructions/frequency.py +0 -135
  379. qiskit/pulse/instructions/instruction.py +0 -270
  380. qiskit/pulse/instructions/phase.py +0 -152
  381. qiskit/pulse/instructions/play.py +0 -99
  382. qiskit/pulse/instructions/reference.py +0 -100
  383. qiskit/pulse/instructions/snapshot.py +0 -82
  384. qiskit/pulse/library/__init__.py +0 -97
  385. qiskit/pulse/library/continuous.py +0 -430
  386. qiskit/pulse/library/pulse.py +0 -148
  387. qiskit/pulse/library/samplers/__init__.py +0 -15
  388. qiskit/pulse/library/samplers/decorators.py +0 -295
  389. qiskit/pulse/library/samplers/strategies.py +0 -71
  390. qiskit/pulse/library/symbolic_pulses.py +0 -1989
  391. qiskit/pulse/library/waveform.py +0 -136
  392. qiskit/pulse/macros.py +0 -262
  393. qiskit/pulse/parameter_manager.py +0 -445
  394. qiskit/pulse/parser.py +0 -314
  395. qiskit/pulse/reference_manager.py +0 -58
  396. qiskit/pulse/schedule.py +0 -1854
  397. qiskit/pulse/transforms/__init__.py +0 -106
  398. qiskit/pulse/transforms/alignments.py +0 -406
  399. qiskit/pulse/transforms/base_transforms.py +0 -71
  400. qiskit/pulse/transforms/canonicalization.py +0 -498
  401. qiskit/pulse/transforms/dag.py +0 -122
  402. qiskit/pulse/utils.py +0 -149
  403. qiskit/qobj/__init__.py +0 -75
  404. qiskit/qobj/common.py +0 -81
  405. qiskit/qobj/converters/__init__.py +0 -18
  406. qiskit/qobj/converters/lo_config.py +0 -177
  407. qiskit/qobj/converters/pulse_instruction.py +0 -897
  408. qiskit/qobj/pulse_qobj.py +0 -709
  409. qiskit/qobj/qasm_qobj.py +0 -708
  410. qiskit/qobj/utils.py +0 -46
  411. qiskit/result/mitigation/base_readout_mitigator.py +0 -79
  412. qiskit/result/mitigation/correlated_readout_mitigator.py +0 -277
  413. qiskit/result/mitigation/local_readout_mitigator.py +0 -328
  414. qiskit/result/mitigation/utils.py +0 -217
  415. qiskit/scheduler/__init__.py +0 -40
  416. qiskit/scheduler/config.py +0 -37
  417. qiskit/scheduler/lowering.py +0 -187
  418. qiskit/scheduler/methods/__init__.py +0 -15
  419. qiskit/scheduler/methods/basic.py +0 -140
  420. qiskit/scheduler/schedule_circuit.py +0 -69
  421. qiskit/scheduler/sequence.py +0 -104
  422. qiskit/transpiler/passes/calibration/__init__.py +0 -17
  423. qiskit/transpiler/passes/calibration/base_builder.py +0 -79
  424. qiskit/transpiler/passes/calibration/builders.py +0 -20
  425. qiskit/transpiler/passes/calibration/exceptions.py +0 -22
  426. qiskit/transpiler/passes/calibration/pulse_gate.py +0 -100
  427. qiskit/transpiler/passes/calibration/rx_builder.py +0 -164
  428. qiskit/transpiler/passes/calibration/rzx_builder.py +0 -411
  429. qiskit/transpiler/passes/calibration/rzx_templates.py +0 -58
  430. qiskit/transpiler/passes/optimization/cx_cancellation.py +0 -65
  431. qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py +0 -162
  432. qiskit/transpiler/passes/optimization/normalize_rx_angle.py +0 -157
  433. qiskit/transpiler/passes/routing/stochastic_swap.py +0 -532
  434. qiskit/transpiler/passes/scheduling/alap.py +0 -153
  435. qiskit/transpiler/passes/scheduling/alignments/align_measures.py +0 -255
  436. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +0 -107
  437. qiskit/transpiler/passes/scheduling/asap.py +0 -175
  438. qiskit/transpiler/passes/scheduling/base_scheduler.py +0 -310
  439. qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +0 -313
  440. qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +0 -93
  441. qiskit/utils/deprecate_pulse.py +0 -119
  442. qiskit/utils/multiprocessing.py +0 -56
  443. qiskit/visualization/pulse_v2/__init__.py +0 -21
  444. qiskit/visualization/pulse_v2/core.py +0 -901
  445. qiskit/visualization/pulse_v2/device_info.py +0 -173
  446. qiskit/visualization/pulse_v2/drawings.py +0 -253
  447. qiskit/visualization/pulse_v2/events.py +0 -254
  448. qiskit/visualization/pulse_v2/generators/__init__.py +0 -40
  449. qiskit/visualization/pulse_v2/generators/barrier.py +0 -76
  450. qiskit/visualization/pulse_v2/generators/chart.py +0 -208
  451. qiskit/visualization/pulse_v2/generators/frame.py +0 -436
  452. qiskit/visualization/pulse_v2/generators/snapshot.py +0 -133
  453. qiskit/visualization/pulse_v2/generators/waveform.py +0 -645
  454. qiskit/visualization/pulse_v2/interface.py +0 -459
  455. qiskit/visualization/pulse_v2/layouts.py +0 -387
  456. qiskit/visualization/pulse_v2/plotters/__init__.py +0 -17
  457. qiskit/visualization/pulse_v2/plotters/base_plotter.py +0 -53
  458. qiskit/visualization/pulse_v2/plotters/matplotlib.py +0 -201
  459. qiskit/visualization/pulse_v2/stylesheet.py +0 -312
  460. qiskit/visualization/pulse_v2/types.py +0 -242
  461. {qiskit-1.4.1.dist-info → qiskit-2.0.0.dist-info/licenses}/LICENSE.txt +0 -0
  462. {qiskit-1.4.1.dist-info → qiskit-2.0.0.dist-info}/top_level.txt +0 -0
@@ -18,10 +18,11 @@ from __future__ import annotations
18
18
 
19
19
  import collections.abc
20
20
  import copy as _copy
21
+
21
22
  import itertools
22
- import multiprocessing as mp
23
+ import multiprocessing
23
24
  import typing
24
- from collections import OrderedDict, defaultdict, namedtuple
25
+ from collections import OrderedDict
25
26
  from typing import (
26
27
  Union,
27
28
  Optional,
@@ -33,26 +34,36 @@ from typing import (
33
34
  Mapping,
34
35
  Iterable,
35
36
  Any,
36
- DefaultDict,
37
37
  Literal,
38
38
  overload,
39
39
  )
40
+ from math import pi
40
41
  import numpy as np
41
42
  from qiskit._accelerate.circuit import CircuitData
42
43
  from qiskit._accelerate.circuit import StandardGate
44
+ from qiskit._accelerate.circuit import BitLocations
43
45
  from qiskit._accelerate.circuit_duration import compute_estimated_duration
44
46
  from qiskit.exceptions import QiskitError
45
- from qiskit.utils.multiprocessing import is_main_process
46
47
  from qiskit.circuit.instruction import Instruction
47
48
  from qiskit.circuit.gate import Gate
48
49
  from qiskit.circuit.parameter import Parameter
49
50
  from qiskit.circuit.exceptions import CircuitError
50
51
  from qiskit.utils import deprecate_func
51
- from qiskit.utils.deprecate_pulse import deprecate_pulse_dependency
52
+ from . import ( # pylint: disable=cyclic-import
53
+ Bit,
54
+ QuantumRegister,
55
+ Qubit,
56
+ AncillaRegister,
57
+ AncillaQubit,
58
+ Clbit,
59
+ ClassicalRegister,
60
+ Register,
61
+ )
52
62
  from . import _classical_resource_map
53
63
  from .controlflow import ControlFlowOp, _builder_utils
54
64
  from .controlflow.builder import CircuitScopeInterface, ControlFlowBuilderBlock
55
65
  from .controlflow.break_loop import BreakLoopOp, BreakLoopPlaceholder
66
+ from .controlflow.box import BoxOp, BoxContext
56
67
  from .controlflow.continue_loop import ContinueLoopOp, ContinueLoopPlaceholder
57
68
  from .controlflow.for_loop import ForLoopOp, ForLoopContext
58
69
  from .controlflow.if_else import IfElseOp, IfContext
@@ -60,14 +71,10 @@ from .controlflow.switch_case import SwitchCaseOp, SwitchContext
60
71
  from .controlflow.while_loop import WhileLoopOp, WhileLoopContext
61
72
  from .classical import expr, types
62
73
  from .parameterexpression import ParameterExpression, ParameterValueType
63
- from .quantumregister import QuantumRegister, Qubit, AncillaRegister, AncillaQubit
64
- from .classicalregister import ClassicalRegister, Clbit
65
74
  from .parametertable import ParameterView
66
75
  from .parametervector import ParameterVector
67
76
  from .instructionset import InstructionSet
68
77
  from .operation import Operation
69
- from .register import Register
70
- from .bit import Bit
71
78
  from .quantumcircuitdata import QuantumCircuitData, CircuitInstruction
72
79
  from .delay import Delay
73
80
  from .store import Store
@@ -79,8 +86,6 @@ if typing.TYPE_CHECKING:
79
86
  from qiskit.quantum_info.operators.base_operator import BaseOperator
80
87
  from qiskit.quantum_info.states.statevector import Statevector # pylint: disable=cyclic-import
81
88
 
82
- BitLocations = namedtuple("BitLocations", ("index", "registers"))
83
-
84
89
 
85
90
  # The following types are not marked private to avoid leaking this "private/public" abstraction out
86
91
  # into the documentation. They are not imported by circuit.__init__, nor are they meant to be.
@@ -150,7 +155,6 @@ class QuantumCircuit:
150
155
  Immutable data attribute Summary
151
156
  ========================= ======================================================================
152
157
  :attr:`ancillas` List of :class:`AncillaQubit`\\ s tracked by the circuit.
153
- :attr:`calibrations` Custom user-supplied pulse calibrations for individual instructions.
154
158
  :attr:`cregs` List of :class:`ClassicalRegister`\\ s tracked by the circuit.
155
159
 
156
160
  :attr:`clbits` List of :class:`Clbit`\\ s tracked by the circuit.
@@ -231,12 +235,6 @@ class QuantumCircuit:
231
235
 
232
236
  .. autoattribute:: parameters
233
237
 
234
- The storage of any :ref:`manual pulse-level calibrations <circuit-calibrations>` for individual
235
- instructions on the circuit is in :attr:`calibrations`. This presents as a :class:`dict`, but
236
- should not be mutated directly; use the methods discussed in :ref:`circuit-calibrations`.
237
-
238
- .. autoattribute:: calibrations
239
-
240
238
  If you have transpiled your circuit, so you have a physical circuit, you can inspect the
241
239
  :attr:`layout` attribute for information stored by the transpiler about how the virtual qubits
242
240
  of the source circuit map to the hardware qubits of your physical circuit, both at the start and
@@ -746,13 +744,14 @@ class QuantumCircuit:
746
744
  ============================== ================================================================
747
745
  :class:`QuantumCircuit` method Control-flow instruction
748
746
  ============================== ================================================================
749
- :meth:`if_test` :class:`.IfElseOp` with only a ``True`` body.
750
- :meth:`if_else` :class:`.IfElseOp` with both ``True`` and ``False`` bodies.
751
- :meth:`while_loop` :class:`.WhileLoopOp`.
752
- :meth:`switch` :class:`.SwitchCaseOp`.
753
- :meth:`for_loop` :class:`.ForLoopOp`.
754
- :meth:`break_loop` :class:`.BreakLoopOp`.
755
- :meth:`continue_loop` :class:`.ContinueLoopOp`.
747
+ :meth:`if_test` :class:`.IfElseOp` with only a ``True`` body
748
+ :meth:`if_else` :class:`.IfElseOp` with both ``True`` and ``False`` bodies
749
+ :meth:`while_loop` :class:`.WhileLoopOp`
750
+ :meth:`switch` :class:`.SwitchCaseOp`
751
+ :meth:`for_loop` :class:`.ForLoopOp`
752
+ :meth:`box` :class:`.BoxOp`
753
+ :meth:`break_loop` :class:`.BreakLoopOp`
754
+ :meth:`continue_loop` :class:`.ContinueLoopOp`
756
755
  ============================== ================================================================
757
756
 
758
757
  :class:`QuantumCircuit` has corresponding methods for all of the control-flow operations that
@@ -771,9 +770,14 @@ class QuantumCircuit:
771
770
  ``with`` statement. It is far simpler and less error-prone to build control flow
772
771
  programmatically this way.
773
772
 
773
+ When using the control-flow builder interface, you may sometimes want a qubit to be included in
774
+ a block, even though it has no operations defined. In this case, you can use the :meth:`noop`
775
+ method.
776
+
774
777
  ..
775
778
  TODO: expand the examples of the builder interface.
776
779
 
780
+ .. automethod:: box
777
781
  .. automethod:: break_loop
778
782
  .. automethod:: continue_loop
779
783
  .. automethod:: for_loop
@@ -781,6 +785,7 @@ class QuantumCircuit:
781
785
  .. automethod:: if_test
782
786
  .. automethod:: switch
783
787
  .. automethod:: while_loop
788
+ .. automethod:: noop
784
789
 
785
790
 
786
791
  Converting circuits to single objects
@@ -810,17 +815,6 @@ class QuantumCircuit:
810
815
  .. automethod:: clear
811
816
  .. automethod:: remove_final_measurements
812
817
 
813
- .. _circuit-calibrations:
814
-
815
- Manual calibration of instructions
816
- ----------------------------------
817
-
818
- :class:`QuantumCircuit` can store :attr:`calibrations` of instructions that define the pulses
819
- used to run them on one particular hardware backend. You can
820
-
821
- .. automethod:: add_calibration
822
- .. automethod:: has_calibration_for
823
-
824
818
 
825
819
  Circuit properties
826
820
  ==================
@@ -956,19 +950,6 @@ class QuantumCircuit:
956
950
 
957
951
  .. automethod:: decompose
958
952
  .. automethod:: reverse_bits
959
-
960
- Internal utilities
961
- ==================
962
-
963
- These functions are not intended for public use, but were accidentally left documented in the
964
- public API during the 1.0 release. They will be removed in Qiskit 2.0, but will be supported
965
- until then.
966
-
967
- .. automethod:: cast
968
- .. automethod:: cbit_argument_conversion
969
- .. automethod:: cls_instances
970
- .. automethod:: cls_prefix
971
- .. automethod:: qbit_argument_conversion
972
953
  """
973
954
 
974
955
  instances = 0
@@ -981,7 +962,7 @@ class QuantumCircuit:
981
962
  global_phase: ParameterValueType = 0,
982
963
  metadata: dict | None = None,
983
964
  inputs: Iterable[expr.Var] = (),
984
- captures: Iterable[expr.Var] = (),
965
+ captures: Iterable[expr.Var | expr.Stretch] = (),
985
966
  declarations: Mapping[expr.Var, expr.Expr] | Iterable[Tuple[expr.Var, expr.Expr]] = (),
986
967
  ):
987
968
  """
@@ -1029,7 +1010,7 @@ class QuantumCircuit:
1029
1010
  :meth:`QuantumCircuit.add_input`. The variables given in this argument will be
1030
1011
  passed directly to :meth:`add_input`. A circuit cannot have both ``inputs`` and
1031
1012
  ``captures``.
1032
- captures: any variables that that this circuit scope should capture from a containing
1013
+ captures: any variables that this circuit scope should capture from a containing
1033
1014
  scope. The variables given here will be passed directly to :meth:`add_capture`. A
1034
1015
  circuit cannot have both ``inputs`` and ``captures``.
1035
1016
  declarations: any variables that this circuit should declare and initialize immediately.
@@ -1094,26 +1075,11 @@ class QuantumCircuit:
1094
1075
  "qiskit.circuit.controlflow.builder.ControlFlowBuilderBlock"
1095
1076
  ] = []
1096
1077
 
1097
- self.qregs: list[QuantumRegister] = []
1098
- """A list of the :class:`QuantumRegister`\\ s in this circuit. You should not mutate
1099
- this."""
1100
- self.cregs: list[ClassicalRegister] = []
1101
- """A list of the :class:`ClassicalRegister`\\ s in this circuit. You should not mutate
1102
- this."""
1103
-
1104
- # Dict mapping Qubit or Clbit instances to tuple comprised of 0) the
1105
- # corresponding index in circuit.{qubits,clbits} and 1) a list of
1106
- # Register-int pairs for each Register containing the Bit and its index
1107
- # within that register.
1108
- self._qubit_indices: dict[Qubit, BitLocations] = {}
1109
- self._clbit_indices: dict[Clbit, BitLocations] = {}
1110
-
1111
1078
  # Data contains a list of instructions and their contexts,
1112
1079
  # in the order they were applied.
1113
1080
  self._data: CircuitData = CircuitData()
1114
1081
 
1115
1082
  self._ancillas: list[AncillaQubit] = []
1116
- self._calibrations: DefaultDict[str, dict[tuple, Any]] = defaultdict(dict)
1117
1083
  self.add_register(*regs)
1118
1084
 
1119
1085
  self._layout = None
@@ -1124,6 +1090,8 @@ class QuantumCircuit:
1124
1090
  self._vars_input: dict[str, expr.Var] = {}
1125
1091
  self._vars_capture: dict[str, expr.Var] = {}
1126
1092
  self._vars_local: dict[str, expr.Var] = {}
1093
+ self._stretches_capture: dict[str, expr.Stretch] = {}
1094
+ self._stretches_local: dict[str, expr.Stretch] = {}
1127
1095
  for input_ in inputs:
1128
1096
  self.add_input(input_)
1129
1097
  for capture in captures:
@@ -1142,7 +1110,7 @@ class QuantumCircuit:
1142
1110
  transpiler and reattach it to the output, so you can track your own metadata."""
1143
1111
 
1144
1112
  @property
1145
- @deprecate_func(since="1.3.0", removal_timeline="in Qiskit 2.0.0", is_property=True)
1113
+ @deprecate_func(since="1.3.0", removal_timeline="in Qiskit 3.0.0", is_property=True)
1146
1114
  def duration(self):
1147
1115
  """The total duration of the circuit, set by a scheduling transpiler pass. Its unit is
1148
1116
  specified by :attr:`unit`."""
@@ -1153,7 +1121,7 @@ class QuantumCircuit:
1153
1121
  self._duration = value
1154
1122
 
1155
1123
  @property
1156
- @deprecate_func(since="1.3.0", removal_timeline="in Qiskit 2.0.0", is_property=True)
1124
+ @deprecate_func(since="1.3.0", removal_timeline="in Qiskit 3.0.0", is_property=True)
1157
1125
  def unit(self):
1158
1126
  """The unit that :attr:`duration` is specified in."""
1159
1127
  return self._unit
@@ -1171,27 +1139,11 @@ class QuantumCircuit:
1171
1139
 
1172
1140
  if data.num_qubits > 0:
1173
1141
  if add_regs:
1174
- qr = QuantumRegister(name="q", bits=data.qubits)
1175
- out.qregs = [qr]
1176
- out._qubit_indices = {
1177
- bit: BitLocations(index, [(qr, index)]) for index, bit in enumerate(data.qubits)
1178
- }
1179
- else:
1180
- out._qubit_indices = {
1181
- bit: BitLocations(index, []) for index, bit in enumerate(data.qubits)
1182
- }
1142
+ data.qregs = [QuantumRegister(name="q", bits=data.qubits)]
1183
1143
 
1184
1144
  if data.num_clbits > 0:
1185
1145
  if add_regs:
1186
- cr = ClassicalRegister(name="c", bits=data.clbits)
1187
- out.cregs = [cr]
1188
- out._clbit_indices = {
1189
- bit: BitLocations(index, [(cr, index)]) for index, bit in enumerate(data.clbits)
1190
- }
1191
- else:
1192
- out._clbit_indices = {
1193
- bit: BitLocations(index, []) for index, bit in enumerate(data.clbits)
1194
- }
1146
+ data.creg = [ClassicalRegister(name="c", bits=data.clbits)]
1195
1147
 
1196
1148
  out._data = data
1197
1149
 
@@ -1311,11 +1263,16 @@ class QuantumCircuit:
1311
1263
  def op_start_times(self) -> list[int]:
1312
1264
  """Return a list of operation start times.
1313
1265
 
1266
+ .. note::
1267
+ This attribute computes the estimate starting time of the operations in the scheduled circuit
1268
+ and only works for simple circuits that have no control flow or other classical feed-forward
1269
+ operations.
1270
+
1314
1271
  This attribute is enabled once one of scheduling analysis passes
1315
1272
  runs on the quantum circuit.
1316
1273
 
1317
1274
  Returns:
1318
- List of integers representing instruction start times.
1275
+ List of integers representing instruction estimated start times.
1319
1276
  The index corresponds to the index of instruction in :attr:`QuantumCircuit.data`.
1320
1277
 
1321
1278
  Raises:
@@ -1328,67 +1285,6 @@ class QuantumCircuit:
1328
1285
  )
1329
1286
  return self._op_start_times
1330
1287
 
1331
- @property
1332
- @deprecate_pulse_dependency(is_property=True)
1333
- def calibrations(self) -> dict:
1334
- """Return calibration dictionary.
1335
-
1336
- The custom pulse definition of a given gate is of the form
1337
- ``{'gate_name': {(qubits, params): schedule}}``
1338
- """
1339
- return self._calibrations_prop
1340
-
1341
- @calibrations.setter
1342
- @deprecate_pulse_dependency(is_property=True)
1343
- def calibrations(self, calibrations: dict):
1344
- """Set the circuit calibration data from a dictionary of calibration definition.
1345
-
1346
- Args:
1347
- calibrations (dict): A dictionary of input in the format
1348
- ``{'gate_name': {(qubits, gate_params): schedule}}``
1349
- """
1350
- self._calibrations_prop = calibrations
1351
-
1352
- @property
1353
- def _calibrations_prop(self) -> dict:
1354
- """An alternative private path to the `calibrations` property for
1355
- avoiding deprecation warnings."""
1356
- return dict(self._calibrations)
1357
-
1358
- @_calibrations_prop.setter
1359
- def _calibrations_prop(self, calibrations: dict):
1360
- """An alternative private path to the `calibrations` property for
1361
- avoiding deprecation warnings."""
1362
- self._calibrations = defaultdict(dict, calibrations)
1363
-
1364
- @deprecate_pulse_dependency
1365
- def has_calibration_for(self, instruction: CircuitInstruction | tuple):
1366
- """Return True if the circuit has a calibration defined for the instruction context. In this
1367
- case, the operation does not need to be translated to the device basis.
1368
- """
1369
-
1370
- return self._has_calibration_for(instruction)
1371
-
1372
- def _has_calibration_for(self, instruction: CircuitInstruction | tuple):
1373
- """An alternative private path to the `has_calibration_for` method for
1374
- avoiding deprecation warnings."""
1375
- if isinstance(instruction, CircuitInstruction):
1376
- operation = instruction.operation
1377
- qubits = instruction.qubits
1378
- else:
1379
- operation, qubits, _ = instruction
1380
- if not self._calibrations_prop or operation.name not in self._calibrations_prop:
1381
- return False
1382
- qubits = tuple(self.qubits.index(qubit) for qubit in qubits)
1383
- params = []
1384
- for p in operation.params:
1385
- if isinstance(p, ParameterExpression) and not p.parameters:
1386
- params.append(float(p))
1387
- else:
1388
- params.append(p)
1389
- params = tuple(params)
1390
- return (qubits, params) in self._calibrations_prop[operation.name]
1391
-
1392
1288
  @property
1393
1289
  def metadata(self) -> dict:
1394
1290
  """The user provided metadata associated with the circuit.
@@ -1443,6 +1339,8 @@ class QuantumCircuit:
1443
1339
  result._data.replace_bits(
1444
1340
  qubits=_copy.deepcopy(self._data.qubits, memo),
1445
1341
  clbits=_copy.deepcopy(self._data.clbits, memo),
1342
+ qregs=_copy.deepcopy(self._data.qregs, memo),
1343
+ cregs=_copy.deepcopy(self._data.cregs, memo),
1446
1344
  )
1447
1345
  return result
1448
1346
 
@@ -1450,35 +1348,12 @@ class QuantumCircuit:
1450
1348
  def _increment_instances(cls):
1451
1349
  cls.instances += 1
1452
1350
 
1453
- @classmethod
1454
- @deprecate_func(
1455
- since=1.2,
1456
- removal_timeline="in the 2.0 release",
1457
- additional_msg="This method is only used as an internal helper "
1458
- "and will be removed with no replacement.",
1459
- )
1460
- def cls_instances(cls) -> int:
1461
- """Return the current number of instances of this class,
1462
- useful for auto naming."""
1463
- return cls.instances
1464
-
1465
1351
  @classmethod
1466
1352
  def _cls_instances(cls) -> int:
1467
1353
  """Return the current number of instances of this class,
1468
1354
  useful for auto naming."""
1469
1355
  return cls.instances
1470
1356
 
1471
- @classmethod
1472
- @deprecate_func(
1473
- since=1.2,
1474
- removal_timeline="in the 2.0 release",
1475
- additional_msg="This method is only used as an internal helper "
1476
- "and will be removed with no replacement.",
1477
- )
1478
- def cls_prefix(cls) -> str:
1479
- """Return the prefix to use for auto naming."""
1480
- return cls.prefix
1481
-
1482
1357
  @classmethod
1483
1358
  def _cls_prefix(cls) -> str:
1484
1359
  """Return the prefix to use for auto naming."""
@@ -1486,11 +1361,10 @@ class QuantumCircuit:
1486
1361
 
1487
1362
  def _name_update(self) -> None:
1488
1363
  """update name of instance using instance number"""
1489
- if not is_main_process():
1490
- pid_name = f"-{mp.current_process().pid}"
1491
- else:
1364
+ if multiprocessing.parent_process() is None:
1492
1365
  pid_name = ""
1493
-
1366
+ else:
1367
+ pid_name = f"-{multiprocessing.current_process().pid}"
1494
1368
  self.name = f"{self._base_name}-{self._cls_instances()}{pid_name}"
1495
1369
 
1496
1370
  def has_register(self, register: Register) -> bool:
@@ -1546,8 +1420,8 @@ class QuantumCircuit:
1546
1420
  for instruction in reversed(self.data):
1547
1421
  reverse_circ._append(instruction.replace(operation=instruction.operation.reverse_ops()))
1548
1422
 
1549
- reverse_circ.duration = self.duration
1550
- reverse_circ.unit = self.unit
1423
+ reverse_circ._duration = self._duration
1424
+ reverse_circ._unit = self._unit
1551
1425
  return reverse_circ
1552
1426
 
1553
1427
  def reverse_bits(self) -> "QuantumCircuit":
@@ -1804,7 +1678,9 @@ class QuantumCircuit:
1804
1678
  wrap: bool = False,
1805
1679
  *,
1806
1680
  copy: bool = True,
1807
- var_remap: Mapping[str | expr.Var, str | expr.Var] | None = None,
1681
+ var_remap: (
1682
+ Mapping[str | expr.Var | expr.Stretch, str | expr.Var | expr.Stretch] | None
1683
+ ) = None,
1808
1684
  inline_captures: bool = False,
1809
1685
  ) -> Optional["QuantumCircuit"]:
1810
1686
  """Apply the instructions from one circuit onto specified qubits and/or clbits on another.
@@ -1848,23 +1724,25 @@ class QuantumCircuit:
1848
1724
  the base circuit, in order to avoid unnecessary copies; in this case, it is not
1849
1725
  valid to use ``other`` afterward, and some instructions may have been mutated in
1850
1726
  place.
1851
- var_remap (Mapping): mapping to use to rewrite :class:`.expr.Var` nodes in ``other`` as
1852
- they are inlined into ``self``. This can be used to avoid naming conflicts.
1853
-
1854
- Both keys and values can be given as strings or direct :class:`.expr.Var` instances.
1855
- If a key is a string, it matches any :class:`~.expr.Var` with the same name. If a
1856
- value is a string, whenever a new key matches a it, a new :class:`~.expr.Var` is
1857
- created with the correct type. If a value is a :class:`~.expr.Var`, its
1858
- :class:`~.expr.Expr.type` must exactly match that of the variable it is replacing.
1859
- inline_captures (bool): if ``True``, then all "captured" :class:`~.expr.Var` nodes in
1860
- the ``other`` :class:`.QuantumCircuit` are assumed to refer to variables already
1727
+ var_remap (Mapping): mapping to use to rewrite :class:`.expr.Var` and
1728
+ :class:`.expr.Stretch` nodes in ``other`` as they are inlined into ``self``.
1729
+ This can be used to avoid naming conflicts.
1730
+
1731
+ Both keys and values can be given as strings or direct identifier instances.
1732
+ If a key is a string, it matches any :class:`~.expr.Var` or :class:`~.expr.Stretch`
1733
+ with the same name. If a value is a string, whenever a new key matches it, a new
1734
+ :class:`~.expr.Var` or :class:`~.expr.Stretch` is created with the correct type.
1735
+ If a value is a :class:`~.expr.Var`, its :class:`~.expr.Expr.type` must exactly
1736
+ match that of the variable it is replacing.
1737
+ inline_captures (bool): if ``True``, then all "captured" identifier nodes in
1738
+ the ``other`` :class:`.QuantumCircuit` are assumed to refer to identifiers already
1861
1739
  declared in ``self`` (as any input/capture/local type), and the uses in ``other``
1862
- will apply to the existing variables. If you want to build up a layer for an
1740
+ will apply to the existing identifiers. If you want to build up a layer for an
1863
1741
  existing circuit to use with :meth:`compose`, you might find the
1864
1742
  ``vars_mode="captures"`` argument to :meth:`copy_empty_like` useful. Any remapping
1865
1743
  in ``vars_remap`` occurs before evaluating this variable inlining.
1866
1744
 
1867
- If this is ``False`` (the default), then all variables in ``other`` will be required
1745
+ If this is ``False`` (the default), then all identifiers in ``other`` will be required
1868
1746
  to be distinct from those in ``self``, and new declarations will be made for them.
1869
1747
  wrap (bool): If True, wraps the other circuit into a gate (or instruction, depending on
1870
1748
  whether it contains only unitary instructions) before composing it onto self.
@@ -1933,20 +1811,36 @@ class QuantumCircuit:
1933
1811
  # instructions. We cache all replacement lookups for a) speed and b) to ensure that
1934
1812
  # the same variable _always_ maps to the same replacement even if it's used in different
1935
1813
  # places in the recursion tree (such as being a captured variable).
1936
- def replace_var(var: expr.Var, cache: Mapping[expr.Var, expr.Var]) -> expr.Var:
1814
+ def replace_var(
1815
+ var: Union[expr.Var, expr.Stretch], cache: Mapping[expr.Var, expr.Var]
1816
+ ) -> Union[expr.Var | expr.Stretch]:
1937
1817
  # This is closing over an argument to `compose`.
1938
1818
  nonlocal var_remap
1939
1819
 
1940
1820
  if out := cache.get(var):
1941
1821
  return out
1942
1822
  if (replacement := var_remap.get(var)) or (replacement := var_remap.get(var.name)):
1943
- if isinstance(replacement, str):
1944
- replacement = expr.Var.new(replacement, var.type)
1945
- if replacement.type != var.type:
1946
- raise CircuitError(
1947
- f"mismatched types in replacement for '{var.name}':"
1948
- f" '{var.type}' cannot become '{replacement.type}'"
1949
- )
1823
+ if isinstance(var, expr.Var):
1824
+ if isinstance(replacement, expr.Stretch):
1825
+ raise CircuitError(
1826
+ "mismatched identifier kinds in replacement:"
1827
+ f" '{var}' cannot become '{replacement}'"
1828
+ )
1829
+ if isinstance(replacement, str):
1830
+ replacement = expr.Var.new(replacement, var.type)
1831
+ if replacement.type != var.type:
1832
+ raise CircuitError(
1833
+ f"mismatched types in replacement for '{var.name}':"
1834
+ f" '{var.type}' cannot become '{replacement.type}'"
1835
+ )
1836
+ else:
1837
+ if isinstance(replacement, expr.Var):
1838
+ raise CircuitError(
1839
+ "mismatched identifier kind in replacement:"
1840
+ f" '{var}' cannot become '{replacement}'"
1841
+ )
1842
+ if isinstance(replacement, str):
1843
+ replacement = expr.Stretch.new(replacement)
1950
1844
  else:
1951
1845
  replacement = var
1952
1846
  cache[var] = replacement
@@ -2028,9 +1922,6 @@ class QuantumCircuit:
2028
1922
  )
2029
1923
  edge_map.update(zip(other.clbits, dest._cbit_argument_conversion(clbits)))
2030
1924
 
2031
- for gate, cals in other._calibrations_prop.items():
2032
- dest._calibrations[gate].update(cals)
2033
-
2034
1925
  dest.duration = None
2035
1926
  dest.unit = "dt"
2036
1927
  dest.global_phase += other.global_phase
@@ -2048,9 +1939,9 @@ class QuantumCircuit:
2048
1939
  for var in source.iter_input_vars():
2049
1940
  dest.add_input(replace_var(var, var_map))
2050
1941
  if inline_captures:
2051
- for var in source.iter_captured_vars():
1942
+ for var in source.iter_captures():
2052
1943
  replacement = replace_var(var, var_map)
2053
- if not dest.has_var(replace_var(var, var_map)):
1944
+ if not dest.has_identifier(replace_var(var, var_map)):
2054
1945
  if var is replacement:
2055
1946
  raise CircuitError(
2056
1947
  f"Variable '{var}' to be inlined is not in the base circuit."
@@ -2062,10 +1953,12 @@ class QuantumCircuit:
2062
1953
  " base circuit. Is the replacement correct?"
2063
1954
  )
2064
1955
  else:
2065
- for var in source.iter_captured_vars():
1956
+ for var in source.iter_captures():
2066
1957
  dest.add_capture(replace_var(var, var_map))
2067
1958
  for var in source.iter_declared_vars():
2068
1959
  dest.add_uninitialized_var(replace_var(var, var_map))
1960
+ for stretch in source.iter_declared_stretches():
1961
+ dest.add_stretch(replace_var(stretch, var_map))
2069
1962
 
2070
1963
  def recurse_block(block):
2071
1964
  # Recurse the remapping into a control-flow block. Note that this doesn't remap the
@@ -2076,6 +1969,8 @@ class QuantumCircuit:
2076
1969
  new_block._vars_input = {}
2077
1970
  new_block._vars_capture = {}
2078
1971
  new_block._vars_local = {}
1972
+ new_block._stretches_capture = {}
1973
+ new_block._stretches_local = {}
2079
1974
  # For the recursion, we never want to inline captured variables because we're not
2080
1975
  # copying onto a base that has variables.
2081
1976
  copy_with_remapping(block, new_block, bit_map, var_map, inline_captures=False)
@@ -2087,14 +1982,7 @@ class QuantumCircuit:
2087
1982
 
2088
1983
  def map_vars(op):
2089
1984
  n_op = op
2090
- is_control_flow = isinstance(n_op, ControlFlowOp)
2091
- if (
2092
- not is_control_flow
2093
- and (condition := getattr(n_op, "_condition", None)) is not None
2094
- ):
2095
- n_op = n_op.copy() if n_op is op and copy else n_op
2096
- n_op.condition = variable_mapper.map_condition(condition)
2097
- elif is_control_flow:
1985
+ if isinstance(n_op, ControlFlowOp):
2098
1986
  n_op = n_op.replace_blocks(recurse_block(block) for block in n_op.blocks)
2099
1987
  if isinstance(n_op, (IfElseOp, WhileLoopOp)):
2100
1988
  n_op.condition = variable_mapper.map_condition(n_op._condition)
@@ -2223,6 +2111,22 @@ class QuantumCircuit:
2223
2111
  return None
2224
2112
  return dest
2225
2113
 
2114
+ @property
2115
+ def _clbit_indices(self) -> dict[Clbit, BitLocations]:
2116
+ """Dict mapping Clbit instances to an object comprised of `.index` the
2117
+ corresponding index in circuit. and `.registers` a list of
2118
+ Register-int pairs for each Register containing the Bit and its index
2119
+ within that register."""
2120
+ return self._data._clbit_indices
2121
+
2122
+ @property
2123
+ def _qubit_indices(self) -> dict[Qubit, BitLocations]:
2124
+ """Dict mapping Qubit instances to an object comprised of `.index` the
2125
+ corresponding index in circuit. and `.registers` a list of
2126
+ Register-int pairs for each Register containing the Bit and its index
2127
+ within that register."""
2128
+ return self._data._qubit_indices
2129
+
2226
2130
  @property
2227
2131
  def qubits(self) -> list[Qubit]:
2228
2132
  """A list of :class:`Qubit`\\ s in the order that they were added. You should not mutate
@@ -2235,6 +2139,26 @@ class QuantumCircuit:
2235
2139
  this."""
2236
2140
  return self._data.clbits
2237
2141
 
2142
+ @property
2143
+ def qregs(self) -> list[QuantumRegister]:
2144
+ """A list of :class:`Qubit`\\ s in the order that they were added. You should not mutate
2145
+ this."""
2146
+ return self._data.qregs
2147
+
2148
+ @qregs.setter
2149
+ def qregs(self, other: list[QuantumRegister]):
2150
+ self._data.qregs = other
2151
+
2152
+ @property
2153
+ def cregs(self) -> list[ClassicalRegister]:
2154
+ """A list of :class:`Clbit`\\ s in the order that they were added. You should not mutate
2155
+ this."""
2156
+ return self._data.cregs
2157
+
2158
+ @cregs.setter
2159
+ def cregs(self, other: list[ClassicalRegister]):
2160
+ self._data.cregs = other
2161
+
2238
2162
  @property
2239
2163
  def ancillas(self) -> list[AncillaQubit]:
2240
2164
  """A list of :class:`AncillaQubit`\\ s in the order that they were added. You should not
@@ -2248,6 +2172,22 @@ class QuantumCircuit:
2248
2172
  This is the length of the :meth:`iter_vars` iterable."""
2249
2173
  return self.num_input_vars + self.num_captured_vars + self.num_declared_vars
2250
2174
 
2175
+ @property
2176
+ def num_stretches(self) -> int:
2177
+ """The number of stretches in the circuit.
2178
+
2179
+ This is the length of the :meth:`iter_stretches` iterable."""
2180
+ return self.num_captured_stretches + self.num_declared_stretches
2181
+
2182
+ @property
2183
+ def num_identifiers(self) -> int:
2184
+ """The number of real-time classical variables and stretches in
2185
+ the circuit.
2186
+
2187
+ This is equal to :meth:`num_vars` + :meth:`num_stretches`.
2188
+ """
2189
+ return self.num_vars + self.num_stretches
2190
+
2251
2191
  @property
2252
2192
  def num_input_vars(self) -> int:
2253
2193
  """The number of real-time classical variables in the circuit marked as circuit inputs.
@@ -2265,6 +2205,15 @@ class QuantumCircuit:
2265
2205
  :attr:`num_input_vars` must be zero."""
2266
2206
  return len(self._vars_capture)
2267
2207
 
2208
+ @property
2209
+ def num_captured_stretches(self) -> int:
2210
+ """The number of stretches in the circuit marked as captured from an
2211
+ enclosing scope.
2212
+
2213
+ This is the length of the :meth:`iter_captured_stretches` iterable. If this is non-zero,
2214
+ :attr:`num_input_vars` must be zero."""
2215
+ return len(self._stretches_capture)
2216
+
2268
2217
  @property
2269
2218
  def num_declared_vars(self) -> int:
2270
2219
  """The number of real-time classical variables in the circuit that are declared by this
@@ -2273,6 +2222,14 @@ class QuantumCircuit:
2273
2222
  This is the length of the :meth:`iter_declared_vars` iterable."""
2274
2223
  return len(self._vars_local)
2275
2224
 
2225
+ @property
2226
+ def num_declared_stretches(self) -> int:
2227
+ """The number of stretches in the circuit that are declared by this
2228
+ circuit scope, excluding captures.
2229
+
2230
+ This is the length of the :meth:`iter_declared_stretches` iterable."""
2231
+ return len(self._stretches_local)
2232
+
2276
2233
  def iter_vars(self) -> typing.Iterable[expr.Var]:
2277
2234
  """Get an iterable over all real-time classical variables in scope within this circuit.
2278
2235
 
@@ -2285,6 +2242,18 @@ class QuantumCircuit:
2285
2242
  self._vars_input.values(), self._vars_capture.values(), self._vars_local.values()
2286
2243
  )
2287
2244
 
2245
+ def iter_stretches(self) -> typing.Iterable[expr.Stretch]:
2246
+ """Get an iterable over all stretches in scope within this circuit.
2247
+
2248
+ This method will iterate over all stretches in scope. For more fine-grained iterators, see
2249
+ :meth:`iter_declared_stretches` and :meth:`iter_captured_stretches`."""
2250
+ if self._control_flow_scopes:
2251
+ builder = self._control_flow_scopes[-1]
2252
+ return itertools.chain(
2253
+ builder.iter_captured_stretches(), builder.iter_local_stretches()
2254
+ )
2255
+ return itertools.chain(self._stretches_capture.values(), self._stretches_local.values())
2256
+
2288
2257
  def iter_declared_vars(self) -> typing.Iterable[expr.Var]:
2289
2258
  """Get an iterable over all real-time classical variables that are declared with automatic
2290
2259
  storage duration in this scope. This excludes input variables (see :meth:`iter_input_vars`)
@@ -2293,6 +2262,13 @@ class QuantumCircuit:
2293
2262
  return self._control_flow_scopes[-1].iter_local_vars()
2294
2263
  return self._vars_local.values()
2295
2264
 
2265
+ def iter_declared_stretches(self) -> typing.Iterable[expr.Stretch]:
2266
+ """Get an iterable over all stretches that are declared in this scope.
2267
+ This excludes captured stretches (see :meth:`iter_captured_stretches`)."""
2268
+ if self._control_flow_scopes:
2269
+ return self._control_flow_scopes[-1].iter_local_stretches()
2270
+ return self._stretches_local.values()
2271
+
2296
2272
  def iter_input_vars(self) -> typing.Iterable[expr.Var]:
2297
2273
  """Get an iterable over all real-time classical variables that are declared as inputs to
2298
2274
  this circuit scope. This excludes locally declared variables (see
@@ -2301,6 +2277,18 @@ class QuantumCircuit:
2301
2277
  return ()
2302
2278
  return self._vars_input.values()
2303
2279
 
2280
+ def iter_captures(self) -> typing.Iterable[typing.Union[expr.Var, expr.Stretch]]:
2281
+ """Get an iterable over all identifiers are captured by this circuit scope from a
2282
+ containing scope. This excludes input variables (see :meth:`iter_input_vars`)
2283
+ and locally declared variables and stretches (see :meth:`iter_declared_vars`
2284
+ and :meth:`iter_declared_stretches`)."""
2285
+ if self._control_flow_scopes:
2286
+ return itertools.chain(
2287
+ self._control_flow_scopes[-1].iter_captured_vars(),
2288
+ self._control_flow_scopes[-1].iter_captured_stretches(),
2289
+ )
2290
+ return itertools.chain(self._vars_capture.values(), self._stretches_capture.values())
2291
+
2304
2292
  def iter_captured_vars(self) -> typing.Iterable[expr.Var]:
2305
2293
  """Get an iterable over all real-time classical variables that are captured by this circuit
2306
2294
  scope from a containing scope. This excludes input variables (see :meth:`iter_input_vars`)
@@ -2309,6 +2297,14 @@ class QuantumCircuit:
2309
2297
  return self._control_flow_scopes[-1].iter_captured_vars()
2310
2298
  return self._vars_capture.values()
2311
2299
 
2300
+ def iter_captured_stretches(self) -> typing.Iterable[expr.Stretch]:
2301
+ """Get an iterable over stretches that are captured by this circuit
2302
+ scope from a containing scope. This excludes locally declared stretches
2303
+ (see :meth:`iter_declared_stretches`)."""
2304
+ if self._control_flow_scopes:
2305
+ return self._control_flow_scopes[-1].iter_captured_stretches()
2306
+ return self._stretches_capture.values()
2307
+
2312
2308
  def __and__(self, rhs: "QuantumCircuit") -> "QuantumCircuit":
2313
2309
  """Overload & to implement self.compose."""
2314
2310
  return self.compose(rhs)
@@ -2341,20 +2337,6 @@ class QuantumCircuit:
2341
2337
  """Return indexed operation."""
2342
2338
  return self._data[item]
2343
2339
 
2344
- @staticmethod
2345
- @deprecate_func(
2346
- since=1.2,
2347
- removal_timeline="in the 2.0 release",
2348
- additional_msg="This method is only used as an internal helper "
2349
- "and will be removed with no replacement.",
2350
- )
2351
- def cast(value: S, type_: Callable[..., T]) -> Union[S, T]:
2352
- """Best effort to cast value to type. Otherwise, returns the value."""
2353
- try:
2354
- return type_(value)
2355
- except (ValueError, TypeError):
2356
- return value
2357
-
2358
2340
  @staticmethod
2359
2341
  def _cast(value: S, type_: Callable[..., T]) -> Union[S, T]:
2360
2342
  """Best effort to cast value to type. Otherwise, returns the value."""
@@ -2363,26 +2345,6 @@ class QuantumCircuit:
2363
2345
  except (ValueError, TypeError):
2364
2346
  return value
2365
2347
 
2366
- @deprecate_func(
2367
- since=1.2,
2368
- removal_timeline="in the 2.0 release",
2369
- additional_msg="This method is only used as an internal helper "
2370
- "and will be removed with no replacement.",
2371
- )
2372
- def qbit_argument_conversion(self, qubit_representation: QubitSpecifier) -> list[Qubit]:
2373
- """
2374
- Converts several qubit representations (such as indexes, range, etc.)
2375
- into a list of qubits.
2376
-
2377
- Args:
2378
- qubit_representation: Representation to expand.
2379
-
2380
- Returns:
2381
- The resolved instances of the qubits.
2382
- """
2383
-
2384
- return self._qbit_argument_conversion(qubit_representation)
2385
-
2386
2348
  def _qbit_argument_conversion(self, qubit_representation: QubitSpecifier) -> list[Qubit]:
2387
2349
  """
2388
2350
  Converts several qubit representations (such as indexes, range, etc.)
@@ -2394,28 +2356,7 @@ class QuantumCircuit:
2394
2356
  Returns:
2395
2357
  The resolved instances of the qubits.
2396
2358
  """
2397
- return _bit_argument_conversion(
2398
- qubit_representation, self.qubits, self._qubit_indices, Qubit
2399
- )
2400
-
2401
- @deprecate_func(
2402
- since=1.2,
2403
- removal_timeline="in the 2.0 release",
2404
- additional_msg="This method is only used as an internal helper "
2405
- "and will be removed with no replacement.",
2406
- )
2407
- def cbit_argument_conversion(self, clbit_representation: ClbitSpecifier) -> list[Clbit]:
2408
- """
2409
- Converts several classical bit representations (such as indexes, range, etc.)
2410
- into a list of classical bits.
2411
-
2412
- Args:
2413
- clbit_representation : Representation to expand.
2414
-
2415
- Returns:
2416
- A list of tuples where each tuple is a classical bit.
2417
- """
2418
- return self._cbit_argument_conversion(clbit_representation)
2359
+ return self._data._qbit_argument_conversion(qubit_representation)
2419
2360
 
2420
2361
  def _cbit_argument_conversion(self, clbit_representation: ClbitSpecifier) -> list[Clbit]:
2421
2362
  """
@@ -2428,9 +2369,7 @@ class QuantumCircuit:
2428
2369
  Returns:
2429
2370
  A list of tuples where each tuple is a classical bit.
2430
2371
  """
2431
- return _bit_argument_conversion(
2432
- clbit_representation, self.clbits, self._clbit_indices, Clbit
2433
- )
2372
+ return self._data._cbit_argument_conversion(clbit_representation)
2434
2373
 
2435
2374
  def _append_standard_gate(
2436
2375
  self,
@@ -2535,9 +2474,9 @@ class QuantumCircuit:
2535
2474
  if bad_captures := {
2536
2475
  var
2537
2476
  for var in itertools.chain.from_iterable(
2538
- block.iter_captured_vars() for block in operation.blocks
2477
+ block.iter_captures() for block in operation.blocks
2539
2478
  )
2540
- if not self.has_var(var)
2479
+ if not self.has_identifier(var)
2541
2480
  }:
2542
2481
  raise CircuitError(
2543
2482
  f"Control-flow op attempts to capture '{bad_captures}'"
@@ -2588,8 +2527,8 @@ class QuantumCircuit:
2588
2527
 
2589
2528
  * all the qubits and clbits must already exist in the circuit and there can be no
2590
2529
  duplicates in the list.
2591
- * any control-flow operations or classically conditioned instructions must act only on
2592
- variables present in the circuit.
2530
+ * any control-flow operations instructions must act only on variables present in the
2531
+ circuit.
2593
2532
  * the circuit must not be within a control-flow builder context.
2594
2533
 
2595
2534
  .. note::
@@ -2620,8 +2559,8 @@ class QuantumCircuit:
2620
2559
  """
2621
2560
  if _standard_gate:
2622
2561
  self._data.append(instruction)
2623
- self.duration = None
2624
- self.unit = "dt"
2562
+ self._duration = None
2563
+ self._unit = "dt"
2625
2564
  return instruction
2626
2565
 
2627
2566
  old_style = not isinstance(instruction, CircuitInstruction)
@@ -2643,8 +2582,8 @@ class QuantumCircuit:
2643
2582
  self._data.append_manual_params(instruction, params)
2644
2583
 
2645
2584
  # Invalidate whole circuit duration if an instruction is added
2646
- self.duration = None
2647
- self.unit = "dt"
2585
+ self._duration = None
2586
+ self._unit = "dt"
2648
2587
  return instruction.operation if old_style else instruction
2649
2588
 
2650
2589
  @typing.overload
@@ -2802,6 +2741,144 @@ class QuantumCircuit:
2802
2741
  return self.get_var(name_or_var, None) is not None
2803
2742
  return self.get_var(name_or_var.name, None) == name_or_var
2804
2743
 
2744
+ @typing.overload
2745
+ def get_stretch(self, name: str, default: T) -> Union[expr.Stretch, T]: ...
2746
+
2747
+ # The builtin `types` module has `EllipsisType`, but only from 3.10+!
2748
+ @typing.overload
2749
+ def get_stretch(self, name: str, default: type(...) = ...) -> expr.Stretch: ...
2750
+
2751
+ def get_stretch(self, name: str, default: typing.Any = ...):
2752
+ """Retrieve a stretch that is accessible in this circuit scope by name.
2753
+
2754
+ Args:
2755
+ name: the name of the stretch to retrieve.
2756
+ default: if given, this value will be returned if the variable is not present. If it
2757
+ is not given, a :exc:`KeyError` is raised instead.
2758
+
2759
+ Returns:
2760
+ The corresponding stretch.
2761
+
2762
+ Raises:
2763
+ KeyError: if no default is given, but the variable does not exist.
2764
+
2765
+ Examples:
2766
+ Retrieve a stretch by name from a circuit::
2767
+
2768
+ from qiskit.circuit import QuantumCircuit
2769
+
2770
+ # Create a circuit and create a variable in it.
2771
+ qc = QuantumCircuit()
2772
+ my_stretch = qc.add_stretch("my_stretch")
2773
+
2774
+ # We can use 'my_stretch' as a variable, but let's say we've lost the Python object and
2775
+ # need to retrieve it.
2776
+ my_stretch_again = qc.get_stretch("my_stretch")
2777
+
2778
+ assert my_stretch is my_stretch_again
2779
+
2780
+ Get a variable from a circuit by name, returning some default if it is not present::
2781
+
2782
+ assert qc.get_stretch("my_stretch", None) is my_stretch
2783
+ assert qc.get_stretch("unknown_stretch", None) is None
2784
+ """
2785
+ if (out := self._current_scope().get_stretch(name)) is not None:
2786
+ return out
2787
+ if default is Ellipsis:
2788
+ raise KeyError(f"no stretch named '{name}' is present")
2789
+ return default
2790
+
2791
+ def has_stretch(self, name_or_stretch: str | expr.Stretch, /) -> bool:
2792
+ """Check whether a stretch is accessible in this scope.
2793
+
2794
+ Args:
2795
+ name_or_stretch: the stretch, or name of a stretch to check. If this is a
2796
+ :class:`.expr.Stretch` node, the stretch must be exactly the given one for this
2797
+ function to return ``True``.
2798
+
2799
+ Returns:
2800
+ whether a matching stretch is accessible.
2801
+
2802
+ See also:
2803
+ :meth:`QuantumCircuit.get_stretch`
2804
+ Retrieve the :class:`.expr.Stretch` instance from this circuit by name.
2805
+ """
2806
+ if isinstance(name_or_stretch, str):
2807
+ return self.get_stretch(name_or_stretch, None) is not None
2808
+ return self.get_stretch(name_or_stretch.name, None) == name_or_stretch
2809
+
2810
+ @typing.overload
2811
+ def get_identifier(self, name: str, default: T) -> Union[expr.Var | expr.Stretch, T]: ...
2812
+
2813
+ # The builtin `types` module has `EllipsisType`, but only from 3.10+!
2814
+ @typing.overload
2815
+ def get_identifier(
2816
+ self, name: str, default: type(...) = ...
2817
+ ) -> Union[expr.Var, expr.Stretch]: ...
2818
+
2819
+ # We use a _literal_ `Ellipsis` as the marker value to leave `None` available as a default.
2820
+ def get_identifier(self, name: str, default: typing.Any = ...):
2821
+ """Retrieve an identifier that is accessible in this circuit scope by name.
2822
+
2823
+ This currently includes both real-time classical variables and stretches.
2824
+
2825
+ Args:
2826
+ name: the name of the identifier to retrieve.
2827
+ default: if given, this value will be returned if the variable is not present. If it
2828
+ is not given, a :exc:`KeyError` is raised instead.
2829
+
2830
+ Returns:
2831
+ The corresponding variable.
2832
+
2833
+ Raises:
2834
+ KeyError: if no default is given, but the identifier does not exist.
2835
+
2836
+ See also:
2837
+ :meth:`get_var`
2838
+ Gets an identifier known to be a :class:`.expr.Var` instance.
2839
+ :meth:`get_stretch`
2840
+ Gets an identifier known to be a :class:`.expr.Stretch` instance.
2841
+ :meth:`get_parameter`
2842
+ A similar method, but for :class:`.Parameter` compile-time parameters instead of
2843
+ :class:`.expr.Var` run-time variables.
2844
+ """
2845
+ if (out := self._current_scope().get_var(name)) is not None:
2846
+ return out
2847
+ if (out := self._current_scope().get_stretch(name)) is not None:
2848
+ return out
2849
+ if default is Ellipsis:
2850
+ raise KeyError(f"no identifier named '{name}' is present")
2851
+ return default
2852
+
2853
+ def has_identifier(self, name_or_ident: str | expr.Var | expr.Stretch, /) -> bool:
2854
+ """Check whether an identifier is accessible in this scope.
2855
+
2856
+ Args:
2857
+ name_or_ident: the instance, or name of the identifier to check. If this is a
2858
+ :class:`.expr.Var` or :class:`.expr.Stretch` node, the matched instance must
2859
+ be exactly the given one for this function to return ``True``.
2860
+
2861
+ Returns:
2862
+ whether a matching identifier is accessible.
2863
+
2864
+ See also:
2865
+ :meth:`QuantumCircuit.get_identifier`
2866
+ Retrieve the :class:`.expr.Var` or :class:`.expr.Stretch` instance from this
2867
+ circuit by name.
2868
+ :meth:`QuantumCircuit.has_var`
2869
+ The same as this method, but ignoring anything that isn't a
2870
+ run-time :class:`expr.Var` variable.
2871
+ :meth:`QuantumCircuit.has_stretch`
2872
+ The same as this method, but ignoring anything that isn't a
2873
+ run-time :class:`expr.Stretch` variable.
2874
+ :meth:`QuantumCircuit.has_parameter`
2875
+ A similar method to this, but for compile-time :class:`.Parameter`\\ s instead of
2876
+ run-time :class:`.expr.Var` variables.
2877
+ """
2878
+ if isinstance(name_or_ident, str):
2879
+ return self.get_identifier(name_or_ident, None) is not None
2880
+ return self.get_identifier(name_or_ident.name, None) == name_or_ident
2881
+
2805
2882
  def _prepare_new_var(
2806
2883
  self, name_or_var: str | expr.Var, type_: types.Type | None, /
2807
2884
  ) -> expr.Var:
@@ -2826,12 +2903,63 @@ class QuantumCircuit:
2826
2903
 
2827
2904
  # The `var` is guaranteed to have a name because we already excluded the cases where it's
2828
2905
  # wrapping a bit/register.
2829
- if (previous := self.get_var(var.name, default=None)) is not None:
2906
+ if (previous := self.get_identifier(var.name, default=None)) is not None:
2830
2907
  if previous == var:
2831
2908
  raise CircuitError(f"'{var}' is already present in the circuit")
2832
2909
  raise CircuitError(f"cannot add '{var}' as its name shadows the existing '{previous}'")
2833
2910
  return var
2834
2911
 
2912
+ def _prepare_new_stretch(self, name_or_stretch: str | expr.Stretch, /) -> expr.Stretch:
2913
+ """The common logic for preparing and validating a new :class:`~.expr.Stretch` for the circuit.
2914
+
2915
+ Returns the validated stretch, which is guaranteed to be safe to add to the circuit."""
2916
+ if isinstance(name_or_stretch, str):
2917
+ stretch = expr.Stretch.new(name_or_stretch)
2918
+ else:
2919
+ stretch = name_or_stretch
2920
+
2921
+ if (previous := self.get_identifier(stretch.name, default=None)) is not None:
2922
+ if previous == stretch:
2923
+ raise CircuitError(f"'{stretch}' is already present in the circuit")
2924
+ raise CircuitError(
2925
+ f"cannot add '{stretch}' as its name shadows the existing '{previous}'"
2926
+ )
2927
+ return stretch
2928
+
2929
+ def add_stretch(self, name_or_stretch: str | expr.Stretch) -> expr.Stretch:
2930
+ """Declares a new stretch scoped to this circuit.
2931
+
2932
+ Args:
2933
+ name_or_stretch: either a string of the stretch name, or an existing instance of
2934
+ :class:`~.expr.Stretch` to re-use. Stretches cannot shadow names that are already in
2935
+ use within the circuit.
2936
+
2937
+ Returns:
2938
+ The created stretch. If a :class:`~.expr.Stretch` instance was given, the exact same
2939
+ object will be returned.
2940
+
2941
+ Raises:
2942
+ CircuitError: if the stretch cannot be created due to shadowing an existing
2943
+ identifier.
2944
+
2945
+ Examples:
2946
+ Define and use a new stretch given just a name::
2947
+
2948
+ from qiskit.circuit import QuantumCircuit, Duration
2949
+ from qiskit.circuit.classical import expr
2950
+
2951
+ qc = QuantumCircuit(2)
2952
+ my_stretch = qc.add_stretch("my_stretch")
2953
+
2954
+ qc.delay(expr.add(Duration.dt(200), my_stretch), 1)
2955
+ """
2956
+ if isinstance(name_or_stretch, str):
2957
+ stretch = expr.Stretch.new(name_or_stretch)
2958
+ else:
2959
+ stretch = name_or_stretch
2960
+ self._current_scope().add_stretch(stretch)
2961
+ return stretch
2962
+
2835
2963
  def add_var(self, name_or_var: str | expr.Var, /, initial: typing.Any) -> expr.Var:
2836
2964
  """Add a classical variable with automatic storage and scope to this circuit.
2837
2965
 
@@ -2857,7 +2985,7 @@ class QuantumCircuit:
2857
2985
  object will be returned.
2858
2986
 
2859
2987
  Raises:
2860
- CircuitError: if the variable cannot be created due to shadowing an existing variable.
2988
+ CircuitError: if the variable cannot be created due to shadowing an existing identifier.
2861
2989
 
2862
2990
  Examples:
2863
2991
  Define a new variable given just a name and an initializer expression::
@@ -2961,37 +3089,51 @@ class QuantumCircuit:
2961
3089
  raise CircuitError("cannot add a variable wrapping a bit or register to a circuit")
2962
3090
  self._builder_api.add_uninitialized_var(var)
2963
3091
 
2964
- def add_capture(self, var: expr.Var):
2965
- """Add a variable to the circuit that it should capture from a scope it will be contained
2966
- within.
3092
+ @typing.overload
3093
+ def add_capture(self, var: expr.Var): ...
3094
+
3095
+ @typing.overload
3096
+ def add_capture(self, stretch: expr.Stretch): ...
3097
+
3098
+ def add_capture(self, var):
3099
+ """Add an identifier to the circuit that it should capture from a scope it will
3100
+ be contained within.
2967
3101
 
2968
- This method requires a :class:`~.expr.Var` node to enforce that you've got a handle to one,
2969
- because you will need to declare the same variable using the same object into the outer
2970
- circuit.
3102
+ This method requires a :class:`~.expr.Var` or :class:`~.expr.Stretch` node to enforce that
3103
+ you've got a handle to an identifier, because you will need to declare the same identifier
3104
+ using the same object in the outer circuit.
2971
3105
 
2972
3106
  This is a low-level method, which is only really useful if you are manually constructing
2973
3107
  control-flow operations. You typically will not need to call this method, assuming you
2974
3108
  are using the builder interface for control-flow scopes (``with`` context-manager statements
2975
3109
  for :meth:`if_test` and the other scoping constructs). The builder interface will
2976
- automatically make the inner scopes closures on your behalf by capturing any variables that
2977
- are used within them.
3110
+ automatically make the inner scopes closures on your behalf by capturing any identifiers
3111
+ that are used within them.
2978
3112
 
2979
3113
  Args:
2980
- var: the variable to capture from an enclosing scope.
3114
+ var (Union[expr.Var, expr.Stretch]): the variable or stretch to capture from an
3115
+ enclosing scope.
2981
3116
 
2982
3117
  Raises:
2983
- CircuitError: if the variable cannot be created due to shadowing an existing variable.
3118
+ CircuitError: if the identifier cannot be created due to shadowing an existing
3119
+ identifier.
2984
3120
  """
2985
3121
  if self._control_flow_scopes:
2986
3122
  # Allow manual capturing. Not sure why it'd be useful, but there's a clear expected
2987
3123
  # behavior here.
2988
- self._control_flow_scopes[-1].use_var(var)
3124
+ if isinstance(var, expr.Stretch):
3125
+ self._control_flow_scopes[-1].use_stretch(var)
3126
+ else:
3127
+ self._control_flow_scopes[-1].use_var(var)
2989
3128
  return
2990
3129
  if self._vars_input:
2991
3130
  raise CircuitError(
2992
3131
  "circuits with input variables cannot be enclosed, so cannot be closures"
2993
3132
  )
2994
- self._vars_capture[var.name] = self._prepare_new_var(var, None)
3133
+ if isinstance(var, expr.Stretch):
3134
+ self._stretches_capture[var.name] = self._prepare_new_stretch(var)
3135
+ else:
3136
+ self._vars_capture[var.name] = self._prepare_new_var(var, None)
2995
3137
 
2996
3138
  @typing.overload
2997
3139
  def add_input(self, name_or_var: str, type_: types.Type, /) -> expr.Var: ...
@@ -3019,7 +3161,7 @@ class QuantumCircuit:
3019
3161
  """
3020
3162
  if self._control_flow_scopes:
3021
3163
  raise CircuitError("cannot add an input variable in a control-flow scope")
3022
- if self._vars_capture:
3164
+ if self._vars_capture or self._stretches_capture:
3023
3165
  raise CircuitError("circuits to be enclosed with captures cannot have input variables")
3024
3166
  if isinstance(name_or_var, expr.Var) and type_ is not None:
3025
3167
  raise ValueError("cannot give an explicit type with an existing Var")
@@ -3070,35 +3212,16 @@ class QuantumCircuit:
3070
3212
  self._ancillas.append(bit)
3071
3213
 
3072
3214
  if isinstance(register, QuantumRegister):
3073
- self._add_qreg(register)
3215
+ self._data.add_qreg(register)
3074
3216
 
3075
3217
  elif isinstance(register, ClassicalRegister):
3076
- self.cregs.append(register)
3077
-
3078
- for idx, bit in enumerate(register):
3079
- if bit in self._clbit_indices:
3080
- self._clbit_indices[bit].registers.append((register, idx))
3081
- else:
3082
- self._data.add_clbit(bit)
3083
- self._clbit_indices[bit] = BitLocations(
3084
- self._data.num_clbits - 1, [(register, idx)]
3085
- )
3218
+ self._data.add_creg(register)
3086
3219
 
3087
3220
  elif isinstance(register, list):
3088
3221
  self.add_bits(register)
3089
3222
  else:
3090
3223
  raise CircuitError("expected a register")
3091
3224
 
3092
- def _add_qreg(self, qreg: QuantumRegister) -> None:
3093
- self.qregs.append(qreg)
3094
-
3095
- for idx, bit in enumerate(qreg):
3096
- if bit in self._qubit_indices:
3097
- self._qubit_indices[bit].registers.append((qreg, idx))
3098
- else:
3099
- self._data.add_qubit(bit)
3100
- self._qubit_indices[bit] = BitLocations(self._data.num_qubits - 1, [(qreg, idx)])
3101
-
3102
3225
  def add_bits(self, bits: Iterable[Bit]) -> None:
3103
3226
  """Add Bits to the circuit."""
3104
3227
  duplicate_bits = {
@@ -3112,10 +3235,8 @@ class QuantumCircuit:
3112
3235
  self._ancillas.append(bit)
3113
3236
  if isinstance(bit, Qubit):
3114
3237
  self._data.add_qubit(bit)
3115
- self._qubit_indices[bit] = BitLocations(self._data.num_qubits - 1, [])
3116
3238
  elif isinstance(bit, Clbit):
3117
3239
  self._data.add_clbit(bit)
3118
- self._clbit_indices[bit] = BitLocations(self._data.num_clbits - 1, [])
3119
3240
  else:
3120
3241
  raise CircuitError(
3121
3242
  "Expected an instance of Qubit, Clbit, or "
@@ -3175,9 +3296,9 @@ class QuantumCircuit:
3175
3296
 
3176
3297
  try:
3177
3298
  if isinstance(bit, Qubit):
3178
- return self._qubit_indices[bit]
3299
+ return self._data._qubit_indices[bit]
3179
3300
  elif isinstance(bit, Clbit):
3180
- return self._clbit_indices[bit]
3301
+ return self._data._clbit_indices[bit]
3181
3302
  else:
3182
3303
  raise CircuitError(f"Could not locate bit of unknown type: {type(bit)}")
3183
3304
  except KeyError as err:
@@ -3187,9 +3308,7 @@ class QuantumCircuit:
3187
3308
 
3188
3309
  def _check_dups(self, qubits: Sequence[Qubit]) -> None:
3189
3310
  """Raise exception if list of qubits contains duplicates."""
3190
- squbits = set(qubits)
3191
- if len(squbits) != len(qubits):
3192
- raise CircuitError("duplicate qubit arguments")
3311
+ CircuitData._check_dups(qubits)
3193
3312
 
3194
3313
  def to_instruction(
3195
3314
  self,
@@ -3213,6 +3332,7 @@ class QuantumCircuit:
3213
3332
  qiskit.circuit.Instruction: a composite instruction encapsulating this circuit (can be
3214
3333
  decomposed back).
3215
3334
  """
3335
+ # pylint: disable=cyclic-import
3216
3336
  from qiskit.converters.circuit_to_instruction import circuit_to_instruction
3217
3337
 
3218
3338
  return circuit_to_instruction(self, parameter_map, label=label)
@@ -3238,6 +3358,7 @@ class QuantumCircuit:
3238
3358
  Returns:
3239
3359
  Gate: a composite gate encapsulating this circuit (can be decomposed back).
3240
3360
  """
3361
+ # pylint: disable=cyclic-import
3241
3362
  from qiskit.converters.circuit_to_gate import circuit_to_gate
3242
3363
 
3243
3364
  return circuit_to_gate(self, parameter_map, label=label)
@@ -3288,7 +3409,7 @@ class QuantumCircuit:
3288
3409
  reverse_bits: bool | None = None,
3289
3410
  justify: str | None = None,
3290
3411
  vertical_compression: str | None = "medium",
3291
- idle_wires: bool | None = None,
3412
+ idle_wires: bool | str | None = None,
3292
3413
  with_layout: bool = True,
3293
3414
  fold: int | None = None,
3294
3415
  # The type of ax is matplotlib.axes.Axes, but this is not a fixed dependency, so cannot be
@@ -3364,8 +3485,10 @@ class QuantumCircuit:
3364
3485
  merges the lines generated by the `text` output so the drawing
3365
3486
  will take less vertical room. Default is ``medium``. Only used by
3366
3487
  the ``text`` output, will be silently ignored otherwise.
3367
- idle_wires: Include idle wires (wires with no circuit elements)
3368
- in output visualization. Default is ``True`` unless the
3488
+ idle_wires: Include (or not) idle wires (wires with no circuit elements)
3489
+ in output visualization. The string ``"auto"`` is also possible, in which
3490
+ case idle wires are show except that the circuit has a layout attached.
3491
+ Default is ``"auto"`` unless the
3369
3492
  user config file (usually ``~/.qiskit/settings.conf``) has an
3370
3493
  alternative value set. For example, ``circuit_idle_wires = False``.
3371
3494
  with_layout: Include layout information, with labels on the
@@ -3623,23 +3746,13 @@ class QuantumCircuit:
3623
3746
  num_qargs = len(args)
3624
3747
  else:
3625
3748
  args = instruction.qubits + instruction.clbits
3626
- num_qargs = len(args) + (
3627
- 1 if getattr(instruction.operation, "_condition", None) else 0
3628
- )
3749
+ num_qargs = len(args)
3629
3750
 
3630
3751
  if num_qargs >= 2 and not getattr(instruction.operation, "_directive", False):
3631
3752
  graphs_touched = []
3632
3753
  num_touched = 0
3633
3754
  # Controls necessarily join all the cbits in the
3634
3755
  # register that they use.
3635
- if not unitary_only:
3636
- for bit in instruction.operation.condition_bits:
3637
- idx = bit_indices[bit]
3638
- for k in range(num_sub_graphs):
3639
- if idx in sub_graphs[k]:
3640
- graphs_touched.append(k)
3641
- break
3642
-
3643
3756
  for item in args:
3644
3757
  reg_int = bit_indices[item]
3645
3758
  for k in range(num_sub_graphs):
@@ -3710,7 +3823,7 @@ class QuantumCircuit:
3710
3823
 
3711
3824
  That structure includes:
3712
3825
 
3713
- * name, calibrations and other metadata
3826
+ * name and other metadata
3714
3827
  * global phase
3715
3828
  * all the qubits and clbits, including the registers
3716
3829
  * the realtime variables defined in the circuit, handled according to the ``vars`` keyword
@@ -3753,9 +3866,7 @@ class QuantumCircuit:
3753
3866
 
3754
3867
  _copy_metadata(self, cpy, vars_mode)
3755
3868
 
3756
- cpy._data = CircuitData(
3757
- self._data.qubits, self._data.clbits, global_phase=self._data.global_phase
3758
- )
3869
+ cpy._data = self._data.copy_empty_like()
3759
3870
 
3760
3871
  if name:
3761
3872
  cpy.name = name
@@ -3764,7 +3875,7 @@ class QuantumCircuit:
3764
3875
  def clear(self) -> None:
3765
3876
  """Clear all instructions in self.
3766
3877
 
3767
- Clearing the circuits will keep the metadata and calibrations.
3878
+ Clearing the circuits will keep the metadata.
3768
3879
 
3769
3880
  .. seealso::
3770
3881
  :meth:`copy_empty_like`
@@ -3778,10 +3889,7 @@ class QuantumCircuit:
3778
3889
  def _create_creg(self, length: int, name: str) -> ClassicalRegister:
3779
3890
  """Creates a creg, checking if ClassicalRegister with same name exists"""
3780
3891
  if name in [creg.name for creg in self.cregs]:
3781
- save_prefix = ClassicalRegister.prefix
3782
- ClassicalRegister.prefix = name
3783
- new_creg = ClassicalRegister(length)
3784
- ClassicalRegister.prefix = save_prefix
3892
+ new_creg = ClassicalRegister._new_with_prefix(length, name)
3785
3893
  else:
3786
3894
  new_creg = ClassicalRegister(length, name)
3787
3895
  return new_creg
@@ -3789,10 +3897,7 @@ class QuantumCircuit:
3789
3897
  def _create_qreg(self, length: int, name: str) -> QuantumRegister:
3790
3898
  """Creates a qreg, checking if QuantumRegister with same name exists"""
3791
3899
  if name in [qreg.name for qreg in self.qregs]:
3792
- save_prefix = QuantumRegister.prefix
3793
- QuantumRegister.prefix = name
3794
- new_qreg = QuantumRegister(length)
3795
- QuantumRegister.prefix = save_prefix
3900
+ new_qreg = QuantumRegister._new_with_prefix(length, name)
3796
3901
  else:
3797
3902
  new_qreg = QuantumRegister(length, name)
3798
3903
  return new_qreg
@@ -3863,7 +3968,10 @@ class QuantumCircuit:
3863
3968
  In this example, a qubit is measured and the result of that measurement is stored in the
3864
3969
  classical bit (usually expressed in diagrams as a double line):
3865
3970
 
3866
- .. code-block::
3971
+ .. plot::
3972
+ :include-source:
3973
+ :nofigs:
3974
+ :context: reset
3867
3975
 
3868
3976
  from qiskit import QuantumCircuit
3869
3977
  circuit = QuantumCircuit(1, 1)
@@ -3883,12 +3991,18 @@ class QuantumCircuit:
3883
3991
  It is possible to call ``measure`` with lists of ``qubits`` and ``cbits`` as a shortcut
3884
3992
  for one-to-one measurement. These two forms produce identical results:
3885
3993
 
3886
- .. code-block::
3994
+ .. plot::
3995
+ :include-source:
3996
+ :nofigs:
3997
+ :context:
3887
3998
 
3888
3999
  circuit = QuantumCircuit(2, 2)
3889
4000
  circuit.measure([0,1], [0,1])
3890
4001
 
3891
- .. code-block::
4002
+ .. plot::
4003
+ :include-source:
4004
+ :nofigs:
4005
+ :context:
3892
4006
 
3893
4007
  circuit = QuantumCircuit(2, 2)
3894
4008
  circuit.measure(0, 0)
@@ -3897,7 +4011,10 @@ class QuantumCircuit:
3897
4011
  Instead of lists, you can use :class:`~qiskit.circuit.QuantumRegister` and
3898
4012
  :class:`~qiskit.circuit.ClassicalRegister` under the same logic.
3899
4013
 
3900
- .. code-block::
4014
+ .. plot::
4015
+ :include-source:
4016
+ :nofigs:
4017
+ :context: reset
3901
4018
 
3902
4019
  from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
3903
4020
  qreg = QuantumRegister(2, "qreg")
@@ -3907,7 +4024,10 @@ class QuantumCircuit:
3907
4024
 
3908
4025
  This is equivalent to:
3909
4026
 
3910
- .. code-block::
4027
+ .. plot::
4028
+ :include-source:
4029
+ :nofigs:
4030
+ :context:
3911
4031
 
3912
4032
  circuit = QuantumCircuit(qreg, creg)
3913
4033
  circuit.measure(qreg[0], creg[0])
@@ -3930,6 +4050,7 @@ class QuantumCircuit:
3930
4050
  Returns:
3931
4051
  QuantumCircuit: Returns circuit with measurements when ``inplace = False``.
3932
4052
  """
4053
+ # pylint: disable=cyclic-import
3933
4054
  from qiskit.converters.circuit_to_dag import circuit_to_dag
3934
4055
 
3935
4056
  if inplace:
@@ -3938,7 +4059,7 @@ class QuantumCircuit:
3938
4059
  circ = self.copy()
3939
4060
  dag = circuit_to_dag(circ)
3940
4061
  qubits_to_measure = [qubit for qubit in circ.qubits if qubit not in dag.idle_wires()]
3941
- new_creg = circ._create_creg(len(qubits_to_measure), "measure")
4062
+ new_creg = circ._create_creg(len(qubits_to_measure), "meas")
3942
4063
  circ.add_register(new_creg)
3943
4064
  circ.barrier()
3944
4065
  circ.measure(qubits_to_measure, new_creg)
@@ -4050,15 +4171,18 @@ class QuantumCircuit:
4050
4171
  cregs_to_add = [creg for creg in circ.cregs if creg in kept_cregs]
4051
4172
  clbits_to_add = [clbit for clbit in circ._data.clbits if clbit in kept_clbits]
4052
4173
 
4053
- # Clear cregs and clbits
4054
- circ.cregs = []
4055
- circ._clbit_indices = {}
4174
+ # Save the old qregs
4175
+ old_qregs = circ.qregs
4056
4176
 
4057
4177
  # Clear instruction info
4058
4178
  circ._data = CircuitData(
4059
4179
  qubits=circ._data.qubits, reserve=len(circ._data), global_phase=circ.global_phase
4060
4180
  )
4061
4181
 
4182
+ # Re-add old registers
4183
+ for qreg in old_qregs:
4184
+ circ.add_register(qreg)
4185
+
4062
4186
  # We must add the clbits first to preserve the original circuit
4063
4187
  # order. This way, add_register never adds clbits and just
4064
4188
  # creates registers that point to them.
@@ -4156,7 +4280,9 @@ class QuantumCircuit:
4156
4280
 
4157
4281
  The snippet below shows that insertion order of parameters does not matter.
4158
4282
 
4159
- .. code-block:: python
4283
+ .. plot::
4284
+ :include-source:
4285
+ :nofigs:
4160
4286
 
4161
4287
  >>> from qiskit.circuit import QuantumCircuit, Parameter
4162
4288
  >>> a, b, elephant = Parameter("a"), Parameter("b"), Parameter("elephant")
@@ -4170,7 +4296,9 @@ class QuantumCircuit:
4170
4296
  Bear in mind that alphabetical sorting might be unintuitive when it comes to numbers.
4171
4297
  The literal "10" comes before "2" in strict alphabetical sorting.
4172
4298
 
4173
- .. code-block:: python
4299
+ .. plot::
4300
+ :include-source:
4301
+ :nofigs:
4174
4302
 
4175
4303
  >>> from qiskit.circuit import QuantumCircuit, Parameter
4176
4304
  >>> angles = [Parameter("angle_1"), Parameter("angle_2"), Parameter("angle_10")]
@@ -4185,7 +4313,9 @@ class QuantumCircuit:
4185
4313
 
4186
4314
  To respect numerical sorting, a :class:`.ParameterVector` can be used.
4187
4315
 
4188
- .. code-block:: python
4316
+ .. plot::
4317
+ :include-source:
4318
+ :nofigs:
4189
4319
 
4190
4320
  >>> from qiskit.circuit import QuantumCircuit, Parameter, ParameterVector
4191
4321
  >>> x = ParameterVector("x", 12)
@@ -4358,70 +4488,10 @@ class QuantumCircuit:
4358
4488
  " the circuit."
4359
4489
  )
4360
4490
 
4361
- def create_mapping_view():
4362
- return raw_mapping
4363
-
4364
4491
  target._data.assign_parameters_mapping(raw_mapping)
4365
4492
  else:
4366
- # This should be a cache retrieval, since we warmed the cache. We need to keep hold of
4367
- # what the parameters were before anything is assigned, because we assign parameters in
4368
- # the calibrations (which aren't tracked in the internal parameter table) after, which
4369
- # would change what we create. We don't make the full Python-space mapping object of
4370
- # parameters to values eagerly because 99.9% of the time we don't need it, and it's
4371
- # relatively expensive to do for large numbers of parameters.
4372
- initial_parameters = target._data.parameters
4373
-
4374
- def create_mapping_view():
4375
- return dict(zip(initial_parameters, parameters))
4376
-
4377
4493
  target._data.assign_parameters_iterable(parameters)
4378
4494
 
4379
- # Finally, assign the parameters inside any of the calibrations. We don't track these in
4380
- # the `ParameterTable`, so we manually reconstruct things. We lazily construct the mapping
4381
- # `{parameter: bound_value}` the first time we encounter a binding (we have to scan for
4382
- # this, because calibrations don't use a parameter-table lookup), rather than always paying
4383
- # the cost - most circuits don't have parametric calibrations, and it's expensive.
4384
- mapping_view = None
4385
-
4386
- def map_calibration(qubits, parameters, schedule):
4387
- # All calls to this function should share the same `{Parameter: bound_value}` mapping,
4388
- # which we only want to lazily construct a single time.
4389
- nonlocal mapping_view
4390
- if mapping_view is None:
4391
- mapping_view = create_mapping_view()
4392
-
4393
- modified = False
4394
- new_parameters = list(parameters)
4395
- for i, parameter in enumerate(new_parameters):
4396
- if not isinstance(parameter, ParameterExpression):
4397
- continue
4398
- if not (contained := parameter.parameters & mapping_view.keys()):
4399
- continue
4400
- for to_bind in contained:
4401
- parameter = parameter.assign(to_bind, mapping_view[to_bind])
4402
- if not parameter.parameters:
4403
- parameter = parameter.numeric()
4404
- if isinstance(parameter, complex):
4405
- raise TypeError(f"Calibration cannot use complex number: '{parameter}'")
4406
- new_parameters[i] = parameter
4407
- modified = True
4408
- if modified:
4409
- schedule.assign_parameters(mapping_view)
4410
- return (qubits, tuple(new_parameters)), schedule
4411
-
4412
- target._calibrations = defaultdict(
4413
- dict,
4414
- (
4415
- (
4416
- gate,
4417
- dict(
4418
- map_calibration(qubits, parameters, schedule)
4419
- for (qubits, parameters), schedule in calibrations.items()
4420
- ),
4421
- )
4422
- for gate, calibrations in target._calibrations.items()
4423
- ),
4424
- )
4425
4495
  return None if inplace else target
4426
4496
 
4427
4497
  def _unroll_param_dict(
@@ -4471,17 +4541,20 @@ class QuantumCircuit:
4471
4541
 
4472
4542
  def delay(
4473
4543
  self,
4474
- duration: ParameterValueType,
4544
+ duration: Union[ParameterValueType, expr.Expr],
4475
4545
  qarg: QubitSpecifier | None = None,
4476
- unit: str = "dt",
4546
+ unit: str | None = None,
4477
4547
  ) -> InstructionSet:
4478
4548
  """Apply :class:`~.circuit.Delay`. If qarg is ``None``, applies to all qubits.
4479
4549
  When applying to multiple qubits, delays with the same duration will be created.
4480
4550
 
4481
4551
  Args:
4482
- duration (int or float or ParameterExpression): duration of the delay.
4552
+ duration (Object):
4553
+ duration of the delay. If this is an :class:`~.expr.Expr`, it must be
4554
+ a constant expression of type :class:`~.types.Duration`.
4483
4555
  qarg (Object): qubit argument to apply this delay.
4484
- unit (str): unit of the duration. Supported units: ``'s'``, ``'ms'``, ``'us'``,
4556
+ unit (str | None): unit of the duration, unless ``duration`` is an :class:`~.expr.Expr`
4557
+ in which case it must not be specified. Supported units: ``'s'``, ``'ms'``, ``'us'``,
4485
4558
  ``'ns'``, ``'ps'``, and ``'dt'``. Default is ``'dt'``, i.e. integer time unit
4486
4559
  depending on the target backend.
4487
4560
 
@@ -4660,6 +4733,198 @@ class QuantumCircuit:
4660
4733
  copy=False,
4661
4734
  )
4662
4735
 
4736
+ def mcrx(
4737
+ self,
4738
+ theta: ParameterValueType,
4739
+ q_controls: Sequence[QubitSpecifier],
4740
+ q_target: QubitSpecifier,
4741
+ use_basis_gates: bool = False,
4742
+ ):
4743
+ """
4744
+ Apply Multiple-Controlled X rotation gate
4745
+
4746
+ Args:
4747
+ theta: The angle of the rotation.
4748
+ q_controls: The qubits used as the controls.
4749
+ q_target: The qubit targeted by the gate.
4750
+ use_basis_gates: use p, u, cx basis gates.
4751
+ """
4752
+ # pylint: disable=cyclic-import
4753
+ from .library.standard_gates.rx import RXGate
4754
+ from qiskit.synthesis.multi_controlled import (
4755
+ _apply_cu,
4756
+ _apply_mcu_graycode,
4757
+ _mcsu2_real_diagonal,
4758
+ )
4759
+
4760
+ control_qubits = self._qbit_argument_conversion(q_controls)
4761
+ target_qubit = self._qbit_argument_conversion(q_target)
4762
+ if len(target_qubit) != 1:
4763
+ raise QiskitError("The mcrx gate needs a single qubit as target.")
4764
+ all_qubits = control_qubits + target_qubit
4765
+ target_qubit = target_qubit[0]
4766
+ self._check_dups(all_qubits)
4767
+
4768
+ n_c = len(control_qubits)
4769
+ if n_c == 1: # cu
4770
+ _apply_cu(
4771
+ self,
4772
+ theta,
4773
+ -pi / 2,
4774
+ pi / 2,
4775
+ control_qubits[0],
4776
+ target_qubit,
4777
+ use_basis_gates=use_basis_gates,
4778
+ )
4779
+ elif n_c < 4:
4780
+ theta_step = theta * (1 / (2 ** (n_c - 1)))
4781
+ _apply_mcu_graycode(
4782
+ self,
4783
+ theta_step,
4784
+ -pi / 2,
4785
+ pi / 2,
4786
+ control_qubits,
4787
+ target_qubit,
4788
+ use_basis_gates=use_basis_gates,
4789
+ )
4790
+ else:
4791
+ cgate = _mcsu2_real_diagonal(
4792
+ RXGate(theta),
4793
+ num_controls=len(control_qubits),
4794
+ use_basis_gates=use_basis_gates,
4795
+ )
4796
+ self.compose(cgate, control_qubits + [target_qubit], inplace=True)
4797
+
4798
+ def mcry(
4799
+ self,
4800
+ theta: ParameterValueType,
4801
+ q_controls: Sequence[QubitSpecifier],
4802
+ q_target: QubitSpecifier,
4803
+ q_ancillae: QubitSpecifier | Sequence[QubitSpecifier] | None = None,
4804
+ mode: str | None = None,
4805
+ use_basis_gates: bool = False,
4806
+ ):
4807
+ """
4808
+ Apply Multiple-Controlled Y rotation gate
4809
+
4810
+ Args:
4811
+ theta: The angle of the rotation.
4812
+ q_controls: The qubits used as the controls.
4813
+ q_target: The qubit targeted by the gate.
4814
+ q_ancillae: The list of ancillary qubits.
4815
+ mode: The implementation mode to use.
4816
+ use_basis_gates: use p, u, cx basis gates
4817
+ """
4818
+ # pylint: disable=cyclic-import
4819
+ from .library.standard_gates.ry import RYGate
4820
+ from .library.standard_gates.x import MCXGate
4821
+ from qiskit.synthesis.multi_controlled import (
4822
+ _apply_cu,
4823
+ _apply_mcu_graycode,
4824
+ _mcsu2_real_diagonal,
4825
+ )
4826
+
4827
+ control_qubits = self._qbit_argument_conversion(q_controls)
4828
+ target_qubit = self._qbit_argument_conversion(q_target)
4829
+ if len(target_qubit) != 1:
4830
+ raise QiskitError("The mcry gate needs a single qubit as target.")
4831
+ ancillary_qubits = [] if q_ancillae is None else self._qbit_argument_conversion(q_ancillae)
4832
+ all_qubits = control_qubits + target_qubit + ancillary_qubits
4833
+ target_qubit = target_qubit[0]
4834
+ self._check_dups(all_qubits)
4835
+
4836
+ # auto-select the best mode
4837
+ if mode is None:
4838
+ # if enough ancillary qubits are provided, use the 'v-chain' method
4839
+ additional_vchain = MCXGate.get_num_ancilla_qubits(len(control_qubits), "v-chain")
4840
+ if len(ancillary_qubits) >= additional_vchain:
4841
+ mode = "basic"
4842
+ else:
4843
+ mode = "noancilla"
4844
+
4845
+ if mode == "basic":
4846
+ self.ry(theta / 2, q_target)
4847
+ self.mcx(list(q_controls), q_target, q_ancillae, mode="v-chain")
4848
+ self.ry(-theta / 2, q_target)
4849
+ self.mcx(list(q_controls), q_target, q_ancillae, mode="v-chain")
4850
+ elif mode == "noancilla":
4851
+ n_c = len(control_qubits)
4852
+ if n_c == 1: # cu
4853
+ _apply_cu(
4854
+ self,
4855
+ theta,
4856
+ 0,
4857
+ 0,
4858
+ control_qubits[0],
4859
+ target_qubit,
4860
+ use_basis_gates=use_basis_gates,
4861
+ )
4862
+ elif n_c < 4:
4863
+ theta_step = theta * (1 / (2 ** (n_c - 1)))
4864
+ _apply_mcu_graycode(
4865
+ self,
4866
+ theta_step,
4867
+ 0,
4868
+ 0,
4869
+ control_qubits,
4870
+ target_qubit,
4871
+ use_basis_gates=use_basis_gates,
4872
+ )
4873
+ else:
4874
+ cgate = _mcsu2_real_diagonal(
4875
+ RYGate(theta),
4876
+ num_controls=len(control_qubits),
4877
+ use_basis_gates=use_basis_gates,
4878
+ )
4879
+ self.compose(cgate, control_qubits + [target_qubit], inplace=True)
4880
+ else:
4881
+ raise QiskitError(f"Unrecognized mode for building MCRY circuit: {mode}.")
4882
+
4883
+ def mcrz(
4884
+ self,
4885
+ lam: ParameterValueType,
4886
+ q_controls: Sequence[QubitSpecifier],
4887
+ q_target: QubitSpecifier,
4888
+ use_basis_gates: bool = False,
4889
+ ):
4890
+ """
4891
+ Apply Multiple-Controlled Z rotation gate
4892
+
4893
+ Args:
4894
+ lam: The angle of the rotation.
4895
+ q_controls: The qubits used as the controls.
4896
+ q_target: The qubit targeted by the gate.
4897
+ use_basis_gates: use p, u, cx basis gates.
4898
+ """
4899
+ # pylint: disable=cyclic-import
4900
+ from .library.standard_gates.rz import CRZGate, RZGate
4901
+ from qiskit.synthesis.multi_controlled import _mcsu2_real_diagonal
4902
+
4903
+ control_qubits = self._qbit_argument_conversion(q_controls)
4904
+ target_qubit = self._qbit_argument_conversion(q_target)
4905
+ if len(target_qubit) != 1:
4906
+ raise QiskitError("The mcrz gate needs a single qubit as target.")
4907
+ all_qubits = control_qubits + target_qubit
4908
+ target_qubit = target_qubit[0]
4909
+ self._check_dups(all_qubits)
4910
+
4911
+ n_c = len(control_qubits)
4912
+ if n_c == 1:
4913
+ if use_basis_gates:
4914
+ self.u(0, 0, lam / 2, target_qubit)
4915
+ self.cx(control_qubits[0], target_qubit)
4916
+ self.u(0, 0, -lam / 2, target_qubit)
4917
+ self.cx(control_qubits[0], target_qubit)
4918
+ else:
4919
+ self.append(CRZGate(lam), control_qubits + [target_qubit])
4920
+ else:
4921
+ cgate = _mcsu2_real_diagonal(
4922
+ RZGate(lam),
4923
+ num_controls=len(control_qubits),
4924
+ use_basis_gates=use_basis_gates,
4925
+ )
4926
+ self.compose(cgate, control_qubits + [target_qubit], inplace=True)
4927
+
4663
4928
  def r(
4664
4929
  self, theta: ParameterValueType, phi: ParameterValueType, qubit: QubitSpecifier
4665
4930
  ) -> InstructionSet:
@@ -5718,7 +5983,9 @@ class QuantumCircuit:
5718
5983
  Examples:
5719
5984
  Prepare a qubit in the state :math:`(|0\rangle - |1\rangle) / \sqrt{2}`.
5720
5985
 
5721
- .. code-block::
5986
+ .. plot::
5987
+ :include-source:
5988
+ :nofigs:
5722
5989
 
5723
5990
  import numpy as np
5724
5991
  from qiskit import QuantumCircuit
@@ -5741,7 +6008,9 @@ class QuantumCircuit:
5741
6008
  More information about labels for basis states are in
5742
6009
  :meth:`.Statevector.from_label`.
5743
6010
 
5744
- .. code-block::
6011
+ .. plot::
6012
+ :include-source:
6013
+ :nofigs:
5745
6014
 
5746
6015
  import numpy as np
5747
6016
  from qiskit import QuantumCircuit
@@ -5762,7 +6031,10 @@ class QuantumCircuit:
5762
6031
 
5763
6032
 
5764
6033
  Initialize two qubits from an array of complex amplitudes
5765
- .. code-block::
6034
+
6035
+ .. plot::
6036
+ :include-source:
6037
+ :nofigs:
5766
6038
 
5767
6039
  import numpy as np
5768
6040
  from qiskit import QuantumCircuit
@@ -5833,7 +6105,9 @@ class QuantumCircuit:
5833
6105
  Examples:
5834
6106
  Prepare a qubit in the state :math:`(|0\rangle - |1\rangle) / \sqrt{2}`.
5835
6107
 
5836
- .. code-block::
6108
+ .. plot::
6109
+ :include-source:
6110
+ :nofigs:
5837
6111
 
5838
6112
  import numpy as np
5839
6113
  from qiskit import QuantumCircuit
@@ -5856,7 +6130,9 @@ class QuantumCircuit:
5856
6130
  More information about labels for basis states are in
5857
6131
  :meth:`.Statevector.from_label`.
5858
6132
 
5859
- .. code-block::
6133
+ .. plot::
6134
+ :include-source:
6135
+ :nofigs:
5860
6136
 
5861
6137
  import numpy as np
5862
6138
  from qiskit import QuantumCircuit
@@ -5877,7 +6153,9 @@ class QuantumCircuit:
5877
6153
 
5878
6154
  Initialize two qubits from an array of complex amplitudes.
5879
6155
 
5880
- .. code-block::
6156
+ .. plot::
6157
+ :include-source:
6158
+ :nofigs:
5881
6159
 
5882
6160
  import numpy as np
5883
6161
  from qiskit import QuantumCircuit
@@ -5928,7 +6206,9 @@ class QuantumCircuit:
5928
6206
 
5929
6207
  Apply a gate specified by a unitary matrix to a quantum circuit
5930
6208
 
5931
- .. code-block:: python
6209
+ .. plot::
6210
+ :include-source:
6211
+ :nofigs:
5932
6212
 
5933
6213
  from qiskit import QuantumCircuit
5934
6214
  matrix = [[0, 0, 0, 1],
@@ -5951,6 +6231,42 @@ class QuantumCircuit:
5951
6231
 
5952
6232
  return self.append(gate, qubits, [], copy=False)
5953
6233
 
6234
+ def noop(self, *qargs: QubitSpecifier):
6235
+ """Mark the given qubit(s) as used within the current scope, without adding an operation.
6236
+
6237
+ This has no effect (other than raising an exception on invalid input) when called in the
6238
+ top scope of a :class:`QuantumCircuit`. Within a control-flow builder, this causes the
6239
+ qubit to be "used" by the control-flow block, if it wouldn't already be used, without adding
6240
+ any additional operations on it.
6241
+
6242
+ For example::
6243
+
6244
+ from qiskit.circuit import QuantumCircuit
6245
+
6246
+ qc = QuantumCircuit(3)
6247
+ with qc.box():
6248
+ # This control-flow block will only use qubits 0 and 1.
6249
+ qc.cx(0, 1)
6250
+ with qc.box():
6251
+ # This control-flow block will contain only the same operation as the previous
6252
+ # block, but it will also mark qubit 2 as "used" by the box.
6253
+ qc.cx(0, 1)
6254
+ qc.noop(2)
6255
+
6256
+ Args:
6257
+ *qargs: variadic list of valid qubit specifiers. Anything that can be passed as a qubit
6258
+ or collection of qubits is valid for each argument here.
6259
+
6260
+ Raises:
6261
+ CircuitError: if any requested qubit is not valid for the circuit.
6262
+ """
6263
+ scope = self._current_scope()
6264
+ for qarg in qargs:
6265
+ for qubit in self._qbit_argument_conversion(qarg):
6266
+ # It doesn't matter if we pass duplicates along here, and the inner scope is going
6267
+ # to have to hash them to check anyway, so no point de-duplicating.
6268
+ scope.use_qubit(qubit)
6269
+
5954
6270
  def _current_scope(self) -> CircuitScopeInterface:
5955
6271
  if self._control_flow_scopes:
5956
6272
  return self._control_flow_scopes[-1]
@@ -6020,6 +6336,107 @@ class QuantumCircuit:
6020
6336
  instruction = self._data.pop()
6021
6337
  return instruction
6022
6338
 
6339
+ def box(
6340
+ self,
6341
+ # Forbidding passing `body` by keyword is in anticipation of the constructor expanding to
6342
+ # allow `annotations` to be passed as the positional argument in the context-manager form.
6343
+ body: QuantumCircuit | None = None,
6344
+ /,
6345
+ qubits: Sequence[QubitSpecifier] | None = None,
6346
+ clbits: Sequence[ClbitSpecifier] | None = None,
6347
+ *,
6348
+ label: str | None = None,
6349
+ duration: None = None,
6350
+ unit: Literal["dt", "s", "ms", "us", "ns", "ps"] = "dt",
6351
+ ):
6352
+ """Create a ``box`` of operations on this circuit that are treated atomically in the greater
6353
+ context.
6354
+
6355
+ A "box" is a control-flow construct that is entered unconditionally. The contents of the
6356
+ box behave somewhat as if the start and end of the box were barriers (see :meth:`barrier`),
6357
+ except it is permissible to commute operations "all the way" through the box. The box is
6358
+ also an explicit scope for the purposes of variables, stretches and compiler passes.
6359
+
6360
+ There are two forms for calling this function:
6361
+
6362
+ * Pass a :class:`QuantumCircuit` positionally, and the ``qubits`` and ``clbits`` it acts
6363
+ on. In this form, a :class:`.BoxOp` is immediately created and appended using the circuit
6364
+ as the body.
6365
+
6366
+ * Use in a ``with`` statement with no ``body``, ``qubits`` or ``clbits``. This is the
6367
+ "builder-interface form", where you then use other :class:`QuantumCircuit` methods within
6368
+ the Python ``with`` scope to add instructions to the ``box``. This is the preferred form,
6369
+ and much less error prone.
6370
+
6371
+ Examples:
6372
+
6373
+ Using the builder interface to add two boxes in sequence. The two boxes in this circuit
6374
+ can execute concurrently, and the second explicitly inserts a data-flow dependency on
6375
+ qubit 8 for the duration of the box, even though the qubit is idle.
6376
+
6377
+ .. code-block:: python
6378
+
6379
+ from qiskit.circuit import QuantumCircuit
6380
+
6381
+ qc = QuantumCircuit(9)
6382
+ with qc.box():
6383
+ qc.cz(0, 1)
6384
+ qc.cz(2, 3)
6385
+ with qc.box():
6386
+ qc.cz(4, 5)
6387
+ qc.cz(6, 7)
6388
+ qc.noop(8)
6389
+
6390
+ Using the explicit construction of box. This creates the same circuit as above, and
6391
+ should give an indication why the previous form is preferred for interactive use.
6392
+
6393
+ .. code-block:: python
6394
+
6395
+ from qiskit.circuit import QuantumCircuit, BoxOp
6396
+
6397
+ body_0 = QuantumCircuit(4)
6398
+ body_0.cz(0, 1)
6399
+ body_0.cz(2, 3)
6400
+
6401
+ # Note that the qubit indices inside a body related only to the body. The
6402
+ # association with qubits in the containing circuit is made by the ``qubits``
6403
+ # argument to `QuantumCircuit.box`.
6404
+ body_1 = QuantumCircuit(5)
6405
+ body_1.cz(0, 1)
6406
+ body_1.cz(2, 3)
6407
+
6408
+ qc = QuantumCircuit(9)
6409
+ qc.box(body_0, [0, 1, 2, 3], [])
6410
+ qc.box(body_1, [4, 5, 6, 7, 8], [])
6411
+
6412
+ Args:
6413
+ body: if given, the :class:`QuantumCircuit` to use as the box's body in the explicit
6414
+ construction. Not given in the context-manager form.
6415
+ qubits: the qubits to apply the :class:`.BoxOp` to, in the explicit form.
6416
+ clbits: the qubits to apply the :class:`.BoxOp` to, in the explicit form.
6417
+ label: an optional string label for the instruction.
6418
+ duration: an optional explicit duration for the :class:`.BoxOp`. Scheduling passes are
6419
+ constrained to schedule the contained scope to match a given duration, including
6420
+ delay insertion if required.
6421
+ unit: the unit of the ``duration``.
6422
+ """
6423
+ if isinstance(body, QuantumCircuit):
6424
+ # Explicit-body form.
6425
+ if qubits is None or clbits is None:
6426
+ raise CircuitError("When using 'box' with a body, you must pass qubits and clbits.")
6427
+ return self.append(
6428
+ BoxOp(body, duration=duration, unit=unit, label=label),
6429
+ qubits,
6430
+ clbits,
6431
+ copy=False,
6432
+ )
6433
+ # Context-manager form.
6434
+ if qubits is not None or clbits is not None:
6435
+ raise CircuitError(
6436
+ "When using 'box' as a context manager, you cannot pass qubits or clbits."
6437
+ )
6438
+ return BoxContext(self, duration=duration, unit=unit, label=label)
6439
+
6023
6440
  @typing.overload
6024
6441
  def while_loop(
6025
6442
  self,
@@ -6152,7 +6569,8 @@ class QuantumCircuit:
6152
6569
  qc.h(0)
6153
6570
  qc.cx(0, 1)
6154
6571
  qc.measure(0, 0)
6155
- qc.break_loop().c_if(0, True)
6572
+ with qc.if_test((0, True)):
6573
+ qc.break_loop()
6156
6574
 
6157
6575
  Args:
6158
6576
  indexset (Iterable[int]): A collection of integers to loop over. Always necessary.
@@ -6504,57 +6922,6 @@ class QuantumCircuit:
6504
6922
  ContinueLoopOp(self.num_qubits, self.num_clbits), self.qubits, self.clbits, copy=False
6505
6923
  )
6506
6924
 
6507
- @deprecate_pulse_dependency
6508
- def add_calibration(
6509
- self,
6510
- gate: Union[Gate, str],
6511
- qubits: Sequence[int],
6512
- # Schedule has the type `qiskit.pulse.Schedule`, but `qiskit.pulse` cannot be imported
6513
- # while this module is, and so Sphinx will not accept a forward reference to it. Sphinx
6514
- # needs the types available at runtime, whereas mypy will accept it, because it handles the
6515
- # type checking by static analysis.
6516
- schedule,
6517
- params: Sequence[ParameterValueType] | None = None,
6518
- ) -> None:
6519
- """Register a low-level, custom pulse definition for the given gate.
6520
-
6521
- Args:
6522
- gate (Union[Gate, str]): Gate information.
6523
- qubits (Union[int, Tuple[int]]): List of qubits to be measured.
6524
- schedule (Schedule): Schedule information.
6525
- params (Optional[List[Union[float, Parameter]]]): A list of parameters.
6526
-
6527
- Raises:
6528
- Exception: if the gate is of type string and params is None.
6529
- """
6530
-
6531
- def _format(operand):
6532
- try:
6533
- # Using float/complex value as a dict key is not good idea.
6534
- # This makes the mapping quite sensitive to the rounding error.
6535
- # However, the mechanism is already tied to the execution model (i.e. pulse gate)
6536
- # and we cannot easily update this rule.
6537
- # The same logic exists in DAGCircuit.add_calibration.
6538
- evaluated = complex(operand)
6539
- if np.isreal(evaluated):
6540
- evaluated = float(evaluated.real)
6541
- if evaluated.is_integer():
6542
- evaluated = int(evaluated)
6543
- return evaluated
6544
- except TypeError:
6545
- # Unassigned parameter
6546
- return operand
6547
-
6548
- if isinstance(gate, Gate):
6549
- params = gate.params
6550
- gate = gate.name
6551
- if params is not None:
6552
- params = tuple(map(_format, params))
6553
- else:
6554
- params = ()
6555
-
6556
- self._calibrations[gate][(tuple(qubits), params)] = schedule
6557
-
6558
6925
  # Functions only for scheduled circuits
6559
6926
  def qubit_duration(self, *qubits: Union[Qubit, int]) -> float:
6560
6927
  """Return the duration between the start and stop time of the first and last instructions,
@@ -6584,7 +6951,7 @@ class QuantumCircuit:
6584
6951
  Raises:
6585
6952
  CircuitError: if ``self`` is a not-yet scheduled circuit.
6586
6953
  """
6587
- if self.duration is None:
6954
+ if self._duration is None:
6588
6955
  # circuit has only delays, this is kind of scheduled
6589
6956
  for instruction in self._data:
6590
6957
  if not isinstance(instruction.operation, Delay):
@@ -6626,7 +6993,7 @@ class QuantumCircuit:
6626
6993
  Raises:
6627
6994
  CircuitError: if ``self`` is a not-yet scheduled circuit.
6628
6995
  """
6629
- if self.duration is None:
6996
+ if self._duration is None:
6630
6997
  # circuit has only delays, this is kind of scheduled
6631
6998
  for instruction in self._data:
6632
6999
  if not isinstance(instruction.operation, Delay):
@@ -6637,7 +7004,7 @@ class QuantumCircuit:
6637
7004
 
6638
7005
  qubits = [self.qubits[q] if isinstance(q, int) else q for q in qubits]
6639
7006
 
6640
- stops = {q: self.duration for q in qubits}
7007
+ stops = {q: self._duration for q in qubits}
6641
7008
  dones = {q: False for q in qubits}
6642
7009
  for instruction in reversed(self._data):
6643
7010
  for q in qubits:
@@ -6740,8 +7107,7 @@ class _OuterCircuitScopeInterface(CircuitScopeInterface):
6740
7107
  def resolve_classical_resource(self, specifier):
6741
7108
  # This is slightly different to cbit_argument_conversion, because it should not
6742
7109
  # unwrap :obj:`.ClassicalRegister` instances into lists, and in general it should not allow
6743
- # iterables or broadcasting. It is expected to be used as a callback for things like
6744
- # :meth:`.InstructionSet.c_if` to check the validity of their arguments.
7110
+ # iterables or broadcasting.
6745
7111
  if isinstance(specifier, Clbit):
6746
7112
  if specifier not in self.circuit._clbit_indices:
6747
7113
  raise CircuitError(f"Clbit {specifier} is not present in this circuit.")
@@ -6765,9 +7131,16 @@ class _OuterCircuitScopeInterface(CircuitScopeInterface):
6765
7131
  var = self.circuit._prepare_new_var(var, None)
6766
7132
  self.circuit._vars_local[var.name] = var
6767
7133
 
7134
+ def add_stretch(self, stretch):
7135
+ stretch = self.circuit._prepare_new_stretch(stretch)
7136
+ self.circuit._stretches_local[stretch.name] = stretch
7137
+
6768
7138
  def remove_var(self, var):
6769
7139
  self.circuit._vars_local.pop(var.name)
6770
7140
 
7141
+ def remove_stretch(self, stretch):
7142
+ self.circuit._stretches_local.pop(stretch.name)
7143
+
6771
7144
  def get_var(self, name):
6772
7145
  if (out := self.circuit._vars_local.get(name)) is not None:
6773
7146
  return out
@@ -6775,97 +7148,45 @@ class _OuterCircuitScopeInterface(CircuitScopeInterface):
6775
7148
  return out
6776
7149
  return self.circuit._vars_input.get(name)
6777
7150
 
7151
+ def get_stretch(self, name):
7152
+ if (out := self.circuit._stretches_local.get(name)) is not None:
7153
+ return out
7154
+ return self.circuit._stretches_capture.get(name)
7155
+
6778
7156
  def use_var(self, var):
6779
7157
  if self.get_var(var.name) != var:
6780
7158
  raise CircuitError(f"'{var}' is not present in this circuit")
6781
7159
 
7160
+ def use_stretch(self, stretch):
7161
+ if self.get_stretch(stretch.name) != stretch:
7162
+ raise CircuitError(f"'{stretch}' is not present in this circuit")
7163
+
7164
+ def use_qubit(self, qubit):
7165
+ # Since the qubit is guaranteed valid, there's nothing for us to do.
7166
+ pass
7167
+
6782
7168
 
6783
7169
  def _validate_expr(circuit_scope: CircuitScopeInterface, node: expr.Expr) -> expr.Expr:
6784
7170
  # This takes the `circuit_scope` object as an argument rather than being a circuit method and
6785
7171
  # inferring it because we may want to call this several times, and we almost invariably already
6786
7172
  # need the interface implementation for something else anyway.
6787
- for var in set(expr.iter_vars(node)):
6788
- if var.standalone:
6789
- circuit_scope.use_var(var)
7173
+ # If we're not in a capturing scope (i.e. we're in the root scope), then the
7174
+ # `use_{var,stretch}` calls are no-ops.
7175
+ for ident in set(expr.iter_identifiers(node)):
7176
+ if isinstance(ident, expr.Stretch):
7177
+ circuit_scope.use_stretch(ident)
6790
7178
  else:
6791
- circuit_scope.resolve_classical_resource(var.var)
7179
+ if ident.standalone:
7180
+ circuit_scope.use_var(ident)
7181
+ else:
7182
+ circuit_scope.resolve_classical_resource(ident.var)
6792
7183
  return node
6793
7184
 
6794
7185
 
6795
- def _bit_argument_conversion(specifier, bit_sequence, bit_set, type_) -> list[Bit]:
6796
- """Get the list of bits referred to by the specifier ``specifier``.
6797
-
6798
- Valid types for ``specifier`` are integers, bits of the correct type (as given in ``type_``), or
6799
- iterables of one of those two scalar types. Integers are interpreted as indices into the
6800
- sequence ``bit_sequence``. All allowed bits must be in ``bit_set`` (which should implement
6801
- fast lookup), which is assumed to contain the same bits as ``bit_sequence``.
6802
-
6803
- Returns:
6804
- List[Bit]: a list of the specified bits from ``bits``.
6805
-
6806
- Raises:
6807
- CircuitError: if an incorrect type or index is encountered, if the same bit is specified
6808
- more than once, or if the specifier is to a bit not in the ``bit_set``.
6809
- """
6810
- # The duplication between this function and `_bit_argument_conversion_scalar` is so that fast
6811
- # paths return as quickly as possible, and all valid specifiers will resolve without needing to
6812
- # try/catch exceptions (which is too slow for inner-loop code).
6813
- if isinstance(specifier, type_):
6814
- if specifier in bit_set:
6815
- return [specifier]
6816
- raise CircuitError(f"Bit '{specifier}' is not in the circuit.")
6817
- if isinstance(specifier, (int, np.integer)):
6818
- try:
6819
- return [bit_sequence[specifier]]
6820
- except IndexError as ex:
6821
- raise CircuitError(
6822
- f"Index {specifier} out of range for size {len(bit_sequence)}."
6823
- ) from ex
6824
- # Slices can't raise IndexError - they just return an empty list.
6825
- if isinstance(specifier, slice):
6826
- return bit_sequence[specifier]
6827
- try:
6828
- return [
6829
- _bit_argument_conversion_scalar(index, bit_sequence, bit_set, type_)
6830
- for index in specifier
6831
- ]
6832
- except TypeError as ex:
6833
- message = (
6834
- f"Incorrect bit type: expected '{type_.__name__}' but got '{type(specifier).__name__}'"
6835
- if isinstance(specifier, Bit)
6836
- else f"Invalid bit index: '{specifier}' of type '{type(specifier)}'"
6837
- )
6838
- raise CircuitError(message) from ex
6839
-
6840
-
6841
- def _bit_argument_conversion_scalar(specifier, bit_sequence, bit_set, type_):
6842
- if isinstance(specifier, type_):
6843
- if specifier in bit_set:
6844
- return specifier
6845
- raise CircuitError(f"Bit '{specifier}' is not in the circuit.")
6846
- if isinstance(specifier, (int, np.integer)):
6847
- try:
6848
- return bit_sequence[specifier]
6849
- except IndexError as ex:
6850
- raise CircuitError(
6851
- f"Index {specifier} out of range for size {len(bit_sequence)}."
6852
- ) from ex
6853
- message = (
6854
- f"Incorrect bit type: expected '{type_.__name__}' but got '{type(specifier).__name__}'"
6855
- if isinstance(specifier, Bit)
6856
- else f"Invalid bit index: '{specifier}' of type '{type(specifier)}'"
6857
- )
6858
- raise CircuitError(message)
6859
-
6860
-
6861
7186
  def _copy_metadata(original, cpy, vars_mode):
6862
7187
  # copy registers correctly, in copy.copy they are only copied via reference
6863
- cpy.qregs = original.qregs.copy()
6864
- cpy.cregs = original.cregs.copy()
6865
7188
  cpy._builder_api = _OuterCircuitScopeInterface(cpy)
6866
7189
  cpy._ancillas = original._ancillas.copy()
6867
- cpy._qubit_indices = original._qubit_indices.copy()
6868
- cpy._clbit_indices = original._clbit_indices.copy()
6869
7190
 
6870
7191
  if vars_mode == "alike":
6871
7192
  # Note that this causes the local variables to be uninitialised, because the stores are
@@ -6874,16 +7195,21 @@ def _copy_metadata(original, cpy, vars_mode):
6874
7195
  cpy._vars_local = original._vars_local.copy()
6875
7196
  cpy._vars_input = original._vars_input.copy()
6876
7197
  cpy._vars_capture = original._vars_capture.copy()
7198
+ cpy._stretches_local = original._stretches_local.copy()
7199
+ cpy._stretches_capture = original._stretches_capture.copy()
6877
7200
  elif vars_mode == "captures":
6878
7201
  cpy._vars_local = {}
6879
7202
  cpy._vars_input = {}
6880
7203
  cpy._vars_capture = {var.name: var for var in original.iter_vars()}
7204
+ cpy._stretches_local = {}
7205
+ cpy._stretches_capture = {stretch.name: stretch for stretch in original.iter_stretches()}
6881
7206
  elif vars_mode == "drop":
6882
7207
  cpy._vars_local = {}
6883
7208
  cpy._vars_input = {}
6884
7209
  cpy._vars_capture = {}
7210
+ cpy._stretches_local = {}
7211
+ cpy._stretches_capture = {}
6885
7212
  else: # pragma: no cover
6886
7213
  raise ValueError(f"unknown vars_mode: '{vars_mode}'")
6887
7214
 
6888
- cpy._calibrations = _copy.deepcopy(original._calibrations)
6889
7215
  cpy._metadata = _copy.deepcopy(original._metadata)