qiskit 1.4.2__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 (459) 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 +7 -1
  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/compiler/__init__.py +1 -7
  104. qiskit/compiler/transpiler.py +38 -196
  105. qiskit/converters/circuit_to_dag.py +6 -4
  106. qiskit/converters/circuit_to_dagdependency.py +0 -2
  107. qiskit/converters/circuit_to_dagdependency_v2.py +0 -1
  108. qiskit/converters/circuit_to_gate.py +1 -1
  109. qiskit/converters/circuit_to_instruction.py +16 -29
  110. qiskit/converters/dag_to_circuit.py +7 -8
  111. qiskit/converters/dag_to_dagdependency.py +0 -1
  112. qiskit/converters/dag_to_dagdependency_v2.py +0 -1
  113. qiskit/converters/dagdependency_to_circuit.py +0 -6
  114. qiskit/converters/dagdependency_to_dag.py +0 -6
  115. qiskit/dagcircuit/collect_blocks.py +32 -20
  116. qiskit/dagcircuit/dagdependency.py +3 -37
  117. qiskit/dagcircuit/dagdependency_v2.py +5 -82
  118. qiskit/dagcircuit/dagnode.py +14 -2
  119. qiskit/passmanager/__init__.py +24 -6
  120. qiskit/passmanager/passmanager.py +26 -24
  121. qiskit/primitives/__init__.py +44 -35
  122. qiskit/primitives/backend_estimator_v2.py +102 -23
  123. qiskit/primitives/backend_sampler_v2.py +5 -20
  124. qiskit/primitives/base/__init__.py +4 -4
  125. qiskit/primitives/base/base_estimator.py +77 -82
  126. qiskit/primitives/base/base_primitive_job.py +2 -2
  127. qiskit/primitives/base/{base_primitive.py → base_primitive_v1.py} +1 -1
  128. qiskit/primitives/base/{base_result.py → base_result_v1.py} +1 -1
  129. qiskit/primitives/base/base_sampler.py +52 -60
  130. qiskit/primitives/base/{estimator_result.py → estimator_result_v1.py} +2 -2
  131. qiskit/primitives/base/{sampler_result.py → sampler_result_v1.py} +2 -2
  132. qiskit/primitives/base/{validation.py → validation_v1.py} +34 -15
  133. qiskit/primitives/containers/bindings_array.py +3 -1
  134. qiskit/primitives/containers/bit_array.py +23 -0
  135. qiskit/primitives/containers/data_bin.py +3 -1
  136. qiskit/primitives/containers/observables_array.py +19 -2
  137. qiskit/primitives/statevector_sampler.py +6 -8
  138. qiskit/primitives/utils.py +14 -189
  139. qiskit/providers/__init__.py +4 -130
  140. qiskit/providers/backend.py +11 -314
  141. qiskit/providers/basic_provider/__init__.py +3 -1
  142. qiskit/providers/basic_provider/basic_provider.py +29 -9
  143. qiskit/providers/basic_provider/basic_simulator.py +158 -298
  144. qiskit/providers/exceptions.py +0 -33
  145. qiskit/providers/fake_provider/__init__.py +0 -37
  146. qiskit/providers/fake_provider/generic_backend_v2.py +32 -693
  147. qiskit/qasm2/__init__.py +21 -6
  148. qiskit/qasm2/export.py +2 -10
  149. qiskit/qasm2/parse.py +11 -25
  150. qiskit/qasm3/__init__.py +5 -1
  151. qiskit/qasm3/ast.py +44 -0
  152. qiskit/qasm3/exporter.py +65 -27
  153. qiskit/qasm3/printer.py +35 -4
  154. qiskit/qpy/__init__.py +162 -19
  155. qiskit/qpy/binary_io/__init__.py +0 -1
  156. qiskit/qpy/binary_io/circuits.py +98 -130
  157. qiskit/qpy/binary_io/schedules.py +69 -439
  158. qiskit/qpy/binary_io/value.py +154 -31
  159. qiskit/qpy/common.py +10 -7
  160. qiskit/qpy/formats.py +41 -0
  161. qiskit/qpy/interface.py +34 -81
  162. qiskit/qpy/type_keys.py +58 -221
  163. qiskit/quantum_info/analysis/distance.py +3 -1
  164. qiskit/quantum_info/operators/dihedral/dihedral.py +3 -1
  165. qiskit/quantum_info/operators/operator.py +6 -2
  166. qiskit/quantum_info/operators/symplectic/clifford.py +3 -1
  167. qiskit/quantum_info/operators/symplectic/pauli.py +4 -2
  168. qiskit/quantum_info/operators/symplectic/pauli_list.py +17 -5
  169. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +40 -6
  170. qiskit/quantum_info/states/densitymatrix.py +16 -6
  171. qiskit/quantum_info/states/stabilizerstate.py +35 -4
  172. qiskit/quantum_info/states/statevector.py +16 -6
  173. qiskit/result/__init__.py +5 -17
  174. qiskit/result/models.py +18 -11
  175. qiskit/result/result.py +38 -134
  176. qiskit/result/sampled_expval.py +1 -2
  177. qiskit/result/utils.py +3 -4
  178. qiskit/synthesis/__init__.py +21 -1
  179. qiskit/synthesis/arithmetic/__init__.py +3 -1
  180. qiskit/synthesis/arithmetic/adders/cdkm_ripple_carry_adder.py +1 -1
  181. qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +1 -1
  182. qiskit/synthesis/arithmetic/adders/vbe_ripple_carry_adder.py +2 -2
  183. qiskit/{providers/fake_provider/backends_v1/fake_20q → synthesis/arithmetic/comparators}/__init__.py +4 -6
  184. qiskit/synthesis/arithmetic/comparators/compare_2s.py +112 -0
  185. qiskit/synthesis/arithmetic/comparators/compare_greedy.py +66 -0
  186. qiskit/synthesis/arithmetic/multipliers/hrs_cumulative_multiplier.py +1 -1
  187. qiskit/synthesis/arithmetic/multipliers/rg_qft_multiplier.py +1 -1
  188. qiskit/synthesis/arithmetic/weighted_sum.py +155 -0
  189. qiskit/{result/mitigation → synthesis/boolean}/__init__.py +2 -2
  190. qiskit/synthesis/boolean/boolean_expression.py +231 -0
  191. qiskit/synthesis/boolean/boolean_expression_synth.py +124 -0
  192. qiskit/synthesis/boolean/boolean_expression_visitor.py +96 -0
  193. qiskit/synthesis/evolution/lie_trotter.py +10 -7
  194. qiskit/synthesis/evolution/product_formula.py +44 -35
  195. qiskit/synthesis/evolution/qdrift.py +17 -24
  196. qiskit/synthesis/evolution/suzuki_trotter.py +20 -27
  197. qiskit/synthesis/linear/linear_depth_lnn.py +6 -221
  198. qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py +4 -205
  199. qiskit/synthesis/multi_controlled/__init__.py +1 -0
  200. qiskit/synthesis/multi_controlled/mcx_synthesis.py +5 -2
  201. qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +206 -0
  202. qiskit/synthesis/one_qubit/one_qubit_decompose.py +1 -1
  203. qiskit/synthesis/two_qubit/__init__.py +1 -0
  204. qiskit/synthesis/two_qubit/two_qubit_decompose.py +28 -145
  205. qiskit/transpiler/__init__.py +32 -232
  206. qiskit/transpiler/basepasses.py +20 -51
  207. qiskit/transpiler/layout.py +1 -1
  208. qiskit/transpiler/passes/__init__.py +4 -40
  209. qiskit/transpiler/passes/basis/basis_translator.py +5 -4
  210. qiskit/transpiler/passes/basis/decompose.py +1 -15
  211. qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -5
  212. qiskit/transpiler/passes/basis/unroll_custom_definitions.py +3 -2
  213. qiskit/transpiler/passes/layout/apply_layout.py +4 -0
  214. qiskit/transpiler/passes/layout/dense_layout.py +2 -39
  215. qiskit/transpiler/passes/layout/full_ancilla_allocation.py +3 -4
  216. qiskit/transpiler/passes/layout/sabre_layout.py +7 -3
  217. qiskit/transpiler/passes/layout/vf2_layout.py +2 -20
  218. qiskit/transpiler/passes/layout/vf2_post_layout.py +60 -125
  219. qiskit/transpiler/passes/layout/vf2_utils.py +2 -26
  220. qiskit/transpiler/passes/optimization/__init__.py +2 -3
  221. qiskit/transpiler/passes/optimization/collect_and_collapse.py +2 -0
  222. qiskit/transpiler/passes/optimization/collect_cliffords.py +5 -0
  223. qiskit/transpiler/passes/optimization/collect_linear_functions.py +5 -0
  224. qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +16 -1
  225. qiskit/transpiler/passes/optimization/commutation_analysis.py +3 -3
  226. qiskit/transpiler/passes/optimization/consolidate_blocks.py +41 -19
  227. qiskit/transpiler/passes/optimization/contract_idle_wires_in_control_flow.py +104 -0
  228. qiskit/transpiler/passes/optimization/light_cone.py +135 -0
  229. qiskit/transpiler/passes/optimization/optimize_1q_commutation.py +0 -1
  230. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +18 -22
  231. qiskit/transpiler/passes/optimization/optimize_annotated.py +3 -2
  232. qiskit/transpiler/passes/optimization/remove_identity_equiv.py +6 -4
  233. qiskit/transpiler/passes/optimization/reset_after_measure_simplification.py +5 -2
  234. qiskit/transpiler/passes/optimization/split_2q_unitaries.py +26 -3
  235. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +1 -0
  236. qiskit/transpiler/passes/routing/__init__.py +0 -1
  237. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +3 -1
  238. qiskit/transpiler/passes/routing/sabre_swap.py +14 -6
  239. qiskit/transpiler/passes/routing/star_prerouting.py +1 -1
  240. qiskit/transpiler/passes/scheduling/__init__.py +1 -7
  241. qiskit/transpiler/passes/scheduling/alignments/__init__.py +2 -4
  242. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -9
  243. qiskit/transpiler/passes/scheduling/alignments/reschedule.py +17 -16
  244. qiskit/transpiler/passes/scheduling/padding/base_padding.py +32 -4
  245. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +25 -63
  246. qiskit/transpiler/passes/scheduling/padding/pad_delay.py +12 -4
  247. qiskit/transpiler/passes/scheduling/scheduling/alap.py +5 -39
  248. qiskit/transpiler/passes/scheduling/scheduling/asap.py +4 -35
  249. qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +10 -16
  250. qiskit/transpiler/passes/scheduling/time_unit_conversion.py +134 -62
  251. qiskit/transpiler/passes/synthesis/default_unitary_synth_plugin.py +653 -0
  252. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +176 -601
  253. qiskit/transpiler/passes/synthesis/hls_plugins.py +294 -1
  254. qiskit/transpiler/passes/synthesis/plugin.py +4 -0
  255. qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +16 -10
  256. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +34 -697
  257. qiskit/transpiler/passes/utils/__init__.py +0 -1
  258. qiskit/transpiler/passes/utils/check_gate_direction.py +13 -5
  259. qiskit/transpiler/passes/utils/control_flow.py +2 -6
  260. qiskit/transpiler/passes/utils/gate_direction.py +7 -0
  261. qiskit/transpiler/passes/utils/remove_final_measurements.py +40 -33
  262. qiskit/transpiler/passmanager.py +13 -0
  263. qiskit/transpiler/passmanager_config.py +5 -81
  264. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +225 -344
  265. qiskit/transpiler/preset_passmanagers/common.py +140 -167
  266. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +107 -322
  267. qiskit/transpiler/preset_passmanagers/level0.py +2 -11
  268. qiskit/transpiler/preset_passmanagers/level1.py +2 -14
  269. qiskit/transpiler/preset_passmanagers/level2.py +2 -12
  270. qiskit/transpiler/preset_passmanagers/level3.py +2 -11
  271. qiskit/transpiler/preset_passmanagers/plugin.py +5 -3
  272. qiskit/transpiler/target.py +78 -524
  273. qiskit/user_config.py +8 -4
  274. qiskit/utils/__init__.py +13 -12
  275. qiskit/utils/deprecation.py +4 -112
  276. qiskit/utils/optionals.py +11 -4
  277. qiskit/utils/parallel.py +214 -87
  278. qiskit/utils/units.py +4 -1
  279. qiskit/visualization/__init__.py +3 -7
  280. qiskit/visualization/array.py +4 -1
  281. qiskit/visualization/bloch.py +1 -1
  282. qiskit/visualization/circuit/_utils.py +19 -19
  283. qiskit/visualization/circuit/circuit_visualization.py +11 -4
  284. qiskit/visualization/circuit/matplotlib.py +13 -23
  285. qiskit/visualization/circuit/text.py +7 -3
  286. qiskit/visualization/counts_visualization.py +4 -0
  287. qiskit/visualization/dag_visualization.py +2 -1
  288. qiskit/visualization/gate_map.py +39 -154
  289. qiskit/visualization/library.py +4 -1
  290. qiskit/visualization/pass_manager_visualization.py +6 -2
  291. qiskit/visualization/state_visualization.py +19 -2
  292. qiskit/visualization/timeline/core.py +19 -13
  293. qiskit/visualization/timeline/interface.py +19 -18
  294. qiskit/visualization/timeline/plotters/matplotlib.py +4 -1
  295. {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/METADATA +4 -3
  296. {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/RECORD +300 -447
  297. {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/WHEEL +2 -1
  298. {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/entry_points.txt +8 -2
  299. qiskit/assembler/__init__.py +0 -42
  300. qiskit/assembler/assemble_circuits.py +0 -451
  301. qiskit/assembler/assemble_schedules.py +0 -367
  302. qiskit/assembler/disassemble.py +0 -310
  303. qiskit/assembler/run_config.py +0 -77
  304. qiskit/circuit/bit.py +0 -106
  305. qiskit/circuit/classicalfunction/__init__.py +0 -152
  306. qiskit/circuit/classicalfunction/boolean_expression.py +0 -138
  307. qiskit/circuit/classicalfunction/classical_element.py +0 -54
  308. qiskit/circuit/classicalfunction/classical_function_visitor.py +0 -155
  309. qiskit/circuit/classicalfunction/classicalfunction.py +0 -182
  310. qiskit/circuit/classicalfunction/exceptions.py +0 -41
  311. qiskit/circuit/classicalfunction/types.py +0 -18
  312. qiskit/circuit/classicalfunction/utils.py +0 -91
  313. qiskit/circuit/classicalregister.py +0 -57
  314. qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +0 -405
  315. qiskit/circuit/quantumregister.py +0 -75
  316. qiskit/circuit/register.py +0 -246
  317. qiskit/compiler/assembler.py +0 -689
  318. qiskit/compiler/scheduler.py +0 -109
  319. qiskit/compiler/sequencer.py +0 -71
  320. qiskit/primitives/backend_estimator.py +0 -486
  321. qiskit/primitives/backend_sampler.py +0 -222
  322. qiskit/primitives/estimator.py +0 -172
  323. qiskit/primitives/sampler.py +0 -162
  324. qiskit/providers/backend_compat.py +0 -507
  325. qiskit/providers/fake_provider/backends_v1/__init__.py +0 -22
  326. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/__init__.py +0 -18
  327. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/conf_washington.json +0 -1
  328. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/defs_washington.json +0 -1
  329. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/fake_127q_pulse_v1.py +0 -37
  330. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/props_washington.json +0 -1
  331. qiskit/providers/fake_provider/backends_v1/fake_20q/conf_singapore.json +0 -1
  332. qiskit/providers/fake_provider/backends_v1/fake_20q/fake_20q.py +0 -43
  333. qiskit/providers/fake_provider/backends_v1/fake_20q/props_singapore.json +0 -1
  334. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/__init__.py +0 -18
  335. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/conf_hanoi.json +0 -1
  336. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/defs_hanoi.json +0 -1
  337. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/fake_27q_pulse_v1.py +0 -50
  338. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/props_hanoi.json +0 -1
  339. qiskit/providers/fake_provider/backends_v1/fake_5q/__init__.py +0 -18
  340. qiskit/providers/fake_provider/backends_v1/fake_5q/conf_yorktown.json +0 -1
  341. qiskit/providers/fake_provider/backends_v1/fake_5q/fake_5q_v1.py +0 -41
  342. qiskit/providers/fake_provider/backends_v1/fake_5q/props_yorktown.json +0 -1
  343. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/__init__.py +0 -18
  344. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/conf_nairobi.json +0 -1
  345. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/defs_nairobi.json +0 -1
  346. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/fake_7q_pulse_v1.py +0 -44
  347. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/props_nairobi.json +0 -1
  348. qiskit/providers/fake_provider/fake_1q.py +0 -91
  349. qiskit/providers/fake_provider/fake_backend.py +0 -165
  350. qiskit/providers/fake_provider/fake_openpulse_2q.py +0 -391
  351. qiskit/providers/fake_provider/fake_openpulse_3q.py +0 -340
  352. qiskit/providers/fake_provider/fake_pulse_backend.py +0 -49
  353. qiskit/providers/fake_provider/fake_qasm_backend.py +0 -77
  354. qiskit/providers/fake_provider/utils/backend_converter.py +0 -150
  355. qiskit/providers/fake_provider/utils/json_decoder.py +0 -109
  356. qiskit/providers/models/__init__.py +0 -89
  357. qiskit/providers/models/backendconfiguration.py +0 -1040
  358. qiskit/providers/models/backendproperties.py +0 -535
  359. qiskit/providers/models/backendstatus.py +0 -104
  360. qiskit/providers/models/jobstatus.py +0 -77
  361. qiskit/providers/models/pulsedefaults.py +0 -305
  362. qiskit/providers/provider.py +0 -95
  363. qiskit/pulse/__init__.py +0 -158
  364. qiskit/pulse/builder.py +0 -2262
  365. qiskit/pulse/calibration_entries.py +0 -381
  366. qiskit/pulse/channels.py +0 -227
  367. qiskit/pulse/configuration.py +0 -245
  368. qiskit/pulse/exceptions.py +0 -45
  369. qiskit/pulse/filters.py +0 -309
  370. qiskit/pulse/instruction_schedule_map.py +0 -424
  371. qiskit/pulse/instructions/__init__.py +0 -67
  372. qiskit/pulse/instructions/acquire.py +0 -150
  373. qiskit/pulse/instructions/delay.py +0 -71
  374. qiskit/pulse/instructions/directives.py +0 -154
  375. qiskit/pulse/instructions/frequency.py +0 -135
  376. qiskit/pulse/instructions/instruction.py +0 -270
  377. qiskit/pulse/instructions/phase.py +0 -152
  378. qiskit/pulse/instructions/play.py +0 -99
  379. qiskit/pulse/instructions/reference.py +0 -100
  380. qiskit/pulse/instructions/snapshot.py +0 -82
  381. qiskit/pulse/library/__init__.py +0 -97
  382. qiskit/pulse/library/continuous.py +0 -430
  383. qiskit/pulse/library/pulse.py +0 -148
  384. qiskit/pulse/library/samplers/__init__.py +0 -15
  385. qiskit/pulse/library/samplers/decorators.py +0 -295
  386. qiskit/pulse/library/samplers/strategies.py +0 -71
  387. qiskit/pulse/library/symbolic_pulses.py +0 -1989
  388. qiskit/pulse/library/waveform.py +0 -136
  389. qiskit/pulse/macros.py +0 -262
  390. qiskit/pulse/parameter_manager.py +0 -445
  391. qiskit/pulse/parser.py +0 -314
  392. qiskit/pulse/reference_manager.py +0 -58
  393. qiskit/pulse/schedule.py +0 -1854
  394. qiskit/pulse/transforms/__init__.py +0 -106
  395. qiskit/pulse/transforms/alignments.py +0 -406
  396. qiskit/pulse/transforms/base_transforms.py +0 -71
  397. qiskit/pulse/transforms/canonicalization.py +0 -498
  398. qiskit/pulse/transforms/dag.py +0 -122
  399. qiskit/pulse/utils.py +0 -149
  400. qiskit/qobj/__init__.py +0 -75
  401. qiskit/qobj/common.py +0 -81
  402. qiskit/qobj/converters/__init__.py +0 -18
  403. qiskit/qobj/converters/lo_config.py +0 -177
  404. qiskit/qobj/converters/pulse_instruction.py +0 -897
  405. qiskit/qobj/pulse_qobj.py +0 -709
  406. qiskit/qobj/qasm_qobj.py +0 -708
  407. qiskit/qobj/utils.py +0 -46
  408. qiskit/result/mitigation/base_readout_mitigator.py +0 -79
  409. qiskit/result/mitigation/correlated_readout_mitigator.py +0 -277
  410. qiskit/result/mitigation/local_readout_mitigator.py +0 -328
  411. qiskit/result/mitigation/utils.py +0 -217
  412. qiskit/scheduler/__init__.py +0 -40
  413. qiskit/scheduler/config.py +0 -37
  414. qiskit/scheduler/lowering.py +0 -187
  415. qiskit/scheduler/methods/__init__.py +0 -15
  416. qiskit/scheduler/methods/basic.py +0 -140
  417. qiskit/scheduler/schedule_circuit.py +0 -69
  418. qiskit/scheduler/sequence.py +0 -104
  419. qiskit/transpiler/passes/calibration/__init__.py +0 -17
  420. qiskit/transpiler/passes/calibration/base_builder.py +0 -79
  421. qiskit/transpiler/passes/calibration/builders.py +0 -20
  422. qiskit/transpiler/passes/calibration/exceptions.py +0 -22
  423. qiskit/transpiler/passes/calibration/pulse_gate.py +0 -100
  424. qiskit/transpiler/passes/calibration/rx_builder.py +0 -164
  425. qiskit/transpiler/passes/calibration/rzx_builder.py +0 -411
  426. qiskit/transpiler/passes/calibration/rzx_templates.py +0 -58
  427. qiskit/transpiler/passes/optimization/cx_cancellation.py +0 -65
  428. qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py +0 -162
  429. qiskit/transpiler/passes/optimization/normalize_rx_angle.py +0 -157
  430. qiskit/transpiler/passes/routing/stochastic_swap.py +0 -532
  431. qiskit/transpiler/passes/scheduling/alap.py +0 -153
  432. qiskit/transpiler/passes/scheduling/alignments/align_measures.py +0 -255
  433. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +0 -107
  434. qiskit/transpiler/passes/scheduling/asap.py +0 -175
  435. qiskit/transpiler/passes/scheduling/base_scheduler.py +0 -310
  436. qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +0 -313
  437. qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +0 -93
  438. qiskit/utils/deprecate_pulse.py +0 -119
  439. qiskit/utils/multiprocessing.py +0 -56
  440. qiskit/visualization/pulse_v2/__init__.py +0 -21
  441. qiskit/visualization/pulse_v2/core.py +0 -901
  442. qiskit/visualization/pulse_v2/device_info.py +0 -173
  443. qiskit/visualization/pulse_v2/drawings.py +0 -253
  444. qiskit/visualization/pulse_v2/events.py +0 -254
  445. qiskit/visualization/pulse_v2/generators/__init__.py +0 -40
  446. qiskit/visualization/pulse_v2/generators/barrier.py +0 -76
  447. qiskit/visualization/pulse_v2/generators/chart.py +0 -208
  448. qiskit/visualization/pulse_v2/generators/frame.py +0 -436
  449. qiskit/visualization/pulse_v2/generators/snapshot.py +0 -133
  450. qiskit/visualization/pulse_v2/generators/waveform.py +0 -645
  451. qiskit/visualization/pulse_v2/interface.py +0 -459
  452. qiskit/visualization/pulse_v2/layouts.py +0 -387
  453. qiskit/visualization/pulse_v2/plotters/__init__.py +0 -17
  454. qiskit/visualization/pulse_v2/plotters/base_plotter.py +0 -53
  455. qiskit/visualization/pulse_v2/plotters/matplotlib.py +0 -201
  456. qiskit/visualization/pulse_v2/stylesheet.py +0 -312
  457. qiskit/visualization/pulse_v2/types.py +0 -242
  458. {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info/licenses}/LICENSE.txt +0 -0
  459. {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/top_level.txt +0 -0
qiskit/pulse/schedule.py DELETED
@@ -1,1854 +0,0 @@
1
- # This code is part of Qiskit.
2
- #
3
- # (C) Copyright IBM 2019.
4
- #
5
- # This code is licensed under the Apache License, Version 2.0. You may
6
- # obtain a copy of this license in the LICENSE.txt file in the root directory
7
- # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8
- #
9
- # Any modifications or derivative works of this code must retain this
10
- # copyright notice, and modified files need to carry a notice indicating
11
- # that they have been altered from the originals.
12
-
13
- # pylint: disable=cyclic-import
14
-
15
- """
16
- =========
17
- Schedules
18
- =========
19
-
20
- .. currentmodule:: qiskit.pulse
21
-
22
- Schedules are Pulse programs. They describe instruction sequences for the control hardware.
23
- The Schedule is one of the most fundamental objects to this pulse-level programming module.
24
- A ``Schedule`` is a representation of a *program* in Pulse. Each schedule tracks the time of each
25
- instruction occuring in parallel over multiple signal *channels*.
26
-
27
- .. autosummary::
28
- :toctree: ../stubs/
29
-
30
- Schedule
31
- ScheduleBlock
32
- """
33
- from __future__ import annotations
34
- import abc
35
- import copy
36
- import functools
37
- import itertools
38
- import multiprocessing as mp
39
- import sys
40
- import warnings
41
- from collections.abc import Callable, Iterable
42
- from typing import List, Tuple, Union, Dict, Any, Sequence
43
-
44
- import numpy as np
45
- import rustworkx as rx
46
-
47
- from qiskit.circuit import ParameterVector
48
- from qiskit.circuit.parameter import Parameter
49
- from qiskit.circuit.parameterexpression import ParameterExpression, ParameterValueType
50
- from qiskit.pulse.channels import Channel
51
- from qiskit.pulse.exceptions import PulseError, UnassignedReferenceError
52
- from qiskit.pulse.instructions import Instruction, Reference
53
- from qiskit.pulse.utils import instruction_duration_validation
54
- from qiskit.pulse.reference_manager import ReferenceManager
55
- from qiskit.utils.multiprocessing import is_main_process
56
- from qiskit.utils import deprecate_arg
57
- from qiskit.utils.deprecate_pulse import deprecate_pulse_func
58
-
59
-
60
- Interval = Tuple[int, int]
61
- """An interval type is a tuple of a start time (inclusive) and an end time (exclusive)."""
62
-
63
- TimeSlots = Dict[Channel, List[Interval]]
64
- """List of timeslots occupied by instructions for each channel."""
65
-
66
-
67
- class Schedule:
68
- """A quantum program *schedule* with exact time constraints for its instructions, operating
69
- over all input signal *channels* and supporting special syntaxes for building.
70
-
71
- Pulse program representation for the original Qiskit Pulse model [1].
72
- Instructions are not allowed to overlap in time
73
- on the same channel. This overlap constraint is immediately
74
- evaluated when a new instruction is added to the ``Schedule`` object.
75
-
76
- It is necessary to specify the absolute start time and duration
77
- for each instruction so as to deterministically fix its execution time.
78
-
79
- The ``Schedule`` program supports some syntax sugar for easier programming.
80
-
81
- - Appending an instruction to the end of a channel
82
-
83
- .. code-block:: python
84
-
85
- from qiskit.pulse import Schedule, Gaussian, DriveChannel, Play
86
- sched = Schedule()
87
- sched += Play(Gaussian(160, 0.1, 40), DriveChannel(0))
88
-
89
- - Appending an instruction shifted in time by a given amount
90
-
91
- .. code-block:: python
92
-
93
- sched = Schedule()
94
- sched += Play(Gaussian(160, 0.1, 40), DriveChannel(0)) << 30
95
-
96
- - Merge two schedules
97
-
98
- .. code-block:: python
99
-
100
- sched1 = Schedule()
101
- sched1 += Play(Gaussian(160, 0.1, 40), DriveChannel(0))
102
-
103
- sched2 = Schedule()
104
- sched2 += Play(Gaussian(160, 0.1, 40), DriveChannel(1))
105
- sched2 = sched1 | sched2
106
-
107
- A :obj:`.PulseError` is immediately raised when the overlap constraint is violated.
108
-
109
- In the schedule representation, we cannot parametrize the duration of instructions.
110
- Thus, we need to create a new schedule object for each duration.
111
- To parametrize an instruction's duration, the :class:`~qiskit.pulse.ScheduleBlock`
112
- representation may be used instead.
113
-
114
- References:
115
- [1]: https://arxiv.org/abs/2004.06755
116
-
117
- """
118
-
119
- # Prefix to use for auto naming.
120
- prefix = "sched"
121
-
122
- # Counter to count instance number.
123
- instances_counter = itertools.count()
124
-
125
- @deprecate_pulse_func
126
- def __init__(
127
- self,
128
- *schedules: "ScheduleComponent" | tuple[int, "ScheduleComponent"],
129
- name: str | None = None,
130
- metadata: dict | None = None,
131
- ):
132
- """Create an empty schedule.
133
-
134
- Args:
135
- *schedules: Child Schedules of this parent Schedule. May either be passed as
136
- the list of schedules, or a list of ``(start_time, schedule)`` pairs.
137
- name: Name of this schedule. Defaults to an autogenerated string if not provided.
138
- metadata: Arbitrary key value metadata to associate with the schedule. This gets
139
- stored as free-form data in a dict in the
140
- :attr:`~qiskit.pulse.Schedule.metadata` attribute. It will not be directly
141
- used in the schedule.
142
- Raises:
143
- TypeError: if metadata is not a dict.
144
- """
145
- from qiskit.pulse.parameter_manager import ParameterManager
146
-
147
- if name is None:
148
- name = self.prefix + str(next(self.instances_counter))
149
- if sys.platform != "win32" and not is_main_process():
150
- name += f"-{mp.current_process().pid}"
151
-
152
- self._name = name
153
- self._parameter_manager = ParameterManager()
154
-
155
- if not isinstance(metadata, dict) and metadata is not None:
156
- raise TypeError("Only a dictionary or None is accepted for schedule metadata")
157
- self._metadata = metadata or {}
158
-
159
- self._duration = 0
160
-
161
- # These attributes are populated by ``_mutable_insert``
162
- self._timeslots: TimeSlots = {}
163
- self._children: list[tuple[int, "ScheduleComponent"]] = []
164
- for sched_pair in schedules:
165
- try:
166
- time, sched = sched_pair
167
- except TypeError:
168
- # recreate as sequence starting at 0.
169
- time, sched = 0, sched_pair
170
- self._mutable_insert(time, sched)
171
-
172
- @classmethod
173
- def initialize_from(cls, other_program: Any, name: str | None = None) -> "Schedule":
174
- """Create new schedule object with metadata of another schedule object.
175
-
176
- Args:
177
- other_program: Qiskit program that provides metadata to new object.
178
- name: Name of new schedule. Name of ``schedule`` is used by default.
179
-
180
- Returns:
181
- New schedule object with name and metadata.
182
-
183
- Raises:
184
- PulseError: When `other_program` does not provide necessary information.
185
- """
186
- try:
187
- name = name or other_program.name
188
-
189
- if other_program.metadata:
190
- metadata = other_program.metadata.copy()
191
- else:
192
- metadata = None
193
-
194
- return cls(name=name, metadata=metadata)
195
- except AttributeError as ex:
196
- raise PulseError(
197
- f"{cls.__name__} cannot be initialized from the program data "
198
- f"{other_program.__class__.__name__}."
199
- ) from ex
200
-
201
- @property
202
- def name(self) -> str:
203
- """Name of this Schedule"""
204
- return self._name
205
-
206
- @property
207
- def metadata(self) -> dict[str, Any]:
208
- """The user provided metadata associated with the schedule.
209
-
210
- User provided ``dict`` of metadata for the schedule.
211
- The metadata contents do not affect the semantics of the program
212
- but are used to influence the execution of the schedule. It is expected
213
- to be passed between all transforms of the schedule and that providers
214
- will associate any schedule metadata with the results it returns from the
215
- execution of that schedule.
216
- """
217
- return self._metadata
218
-
219
- @metadata.setter
220
- def metadata(self, metadata):
221
- """Update the schedule metadata"""
222
- if not isinstance(metadata, dict) and metadata is not None:
223
- raise TypeError("Only a dictionary or None is accepted for schedule metadata")
224
- self._metadata = metadata or {}
225
-
226
- @property
227
- def timeslots(self) -> TimeSlots:
228
- """Time keeping attribute."""
229
- return self._timeslots
230
-
231
- @property
232
- def duration(self) -> int:
233
- """Duration of this schedule."""
234
- return self._duration
235
-
236
- @property
237
- def start_time(self) -> int:
238
- """Starting time of this schedule."""
239
- return self.ch_start_time(*self.channels)
240
-
241
- @property
242
- def stop_time(self) -> int:
243
- """Stopping time of this schedule."""
244
- return self.duration
245
-
246
- @property
247
- def channels(self) -> tuple[Channel, ...]:
248
- """Returns channels that this schedule uses."""
249
- return tuple(self._timeslots.keys())
250
-
251
- @property
252
- def children(self) -> tuple[tuple[int, "ScheduleComponent"], ...]:
253
- """Return the child schedule components of this ``Schedule`` in the
254
- order they were added to the schedule.
255
-
256
- Notes:
257
- Nested schedules are returned as-is. If you want to collect only instructions,
258
- use :py:meth:`~Schedule.instructions` instead.
259
-
260
- Returns:
261
- A tuple, where each element is a two-tuple containing the initial
262
- scheduled time of each ``NamedValue`` and the component
263
- itself.
264
- """
265
- return tuple(self._children)
266
-
267
- @property
268
- def instructions(self) -> tuple[tuple[int, Instruction], ...]:
269
- """Get the time-ordered instructions from self."""
270
-
271
- def key(time_inst_pair):
272
- inst = time_inst_pair[1]
273
- return time_inst_pair[0], inst.duration, sorted(chan.name for chan in inst.channels)
274
-
275
- return tuple(sorted(self._instructions(), key=key))
276
-
277
- @property
278
- def parameters(self) -> set[Parameter]:
279
- """Parameters which determine the schedule behavior."""
280
- return self._parameter_manager.parameters
281
-
282
- def ch_duration(self, *channels: Channel) -> int:
283
- """Return the time of the end of the last instruction over the supplied channels.
284
-
285
- Args:
286
- *channels: Channels within ``self`` to include.
287
- """
288
- return self.ch_stop_time(*channels)
289
-
290
- def ch_start_time(self, *channels: Channel) -> int:
291
- """Return the time of the start of the first instruction over the supplied channels.
292
-
293
- Args:
294
- *channels: Channels within ``self`` to include.
295
- """
296
- try:
297
- chan_intervals = (self._timeslots[chan] for chan in channels if chan in self._timeslots)
298
- return min(intervals[0][0] for intervals in chan_intervals)
299
- except ValueError:
300
- # If there are no instructions over channels
301
- return 0
302
-
303
- def ch_stop_time(self, *channels: Channel) -> int:
304
- """Return maximum start time over supplied channels.
305
-
306
- Args:
307
- *channels: Channels within ``self`` to include.
308
- """
309
- try:
310
- chan_intervals = (self._timeslots[chan] for chan in channels if chan in self._timeslots)
311
- return max(intervals[-1][1] for intervals in chan_intervals)
312
- except ValueError:
313
- # If there are no instructions over channels
314
- return 0
315
-
316
- def _instructions(self, time: int = 0):
317
- """Iterable for flattening Schedule tree.
318
-
319
- Args:
320
- time: Shifted time due to parent.
321
-
322
- Yields:
323
- Iterable[Tuple[int, Instruction]]: Tuple containing the time each
324
- :class:`~qiskit.pulse.Instruction`
325
- starts at and the flattened :class:`~qiskit.pulse.Instruction` s.
326
- """
327
- for insert_time, child_sched in self.children:
328
- yield from child_sched._instructions(time + insert_time)
329
-
330
- def shift(self, time: int, name: str | None = None, inplace: bool = False) -> "Schedule":
331
- """Return a schedule shifted forward by ``time``.
332
-
333
- Args:
334
- time: Time to shift by.
335
- name: Name of the new schedule. Defaults to the name of self.
336
- inplace: Perform operation inplace on this schedule. Otherwise
337
- return a new ``Schedule``.
338
- """
339
- if inplace:
340
- return self._mutable_shift(time)
341
- return self._immutable_shift(time, name=name)
342
-
343
- def _immutable_shift(self, time: int, name: str | None = None) -> "Schedule":
344
- """Return a new schedule shifted forward by `time`.
345
-
346
- Args:
347
- time: Time to shift by
348
- name: Name of the new schedule if call was mutable. Defaults to name of self
349
- """
350
- shift_sched = Schedule.initialize_from(self, name)
351
- shift_sched.insert(time, self, inplace=True)
352
-
353
- return shift_sched
354
-
355
- def _mutable_shift(self, time: int) -> "Schedule":
356
- """Return this schedule shifted forward by `time`.
357
-
358
- Args:
359
- time: Time to shift by
360
-
361
- Raises:
362
- PulseError: if ``time`` is not an integer.
363
- """
364
- if not isinstance(time, int):
365
- raise PulseError("Schedule start time must be an integer.")
366
-
367
- timeslots = {}
368
- for chan, ch_timeslots in self._timeslots.items():
369
- timeslots[chan] = [(ts[0] + time, ts[1] + time) for ts in ch_timeslots]
370
-
371
- _check_nonnegative_timeslot(timeslots)
372
-
373
- self._duration = self._duration + time
374
- self._timeslots = timeslots
375
- self._children = [(orig_time + time, child) for orig_time, child in self.children]
376
- return self
377
-
378
- def insert(
379
- self,
380
- start_time: int,
381
- schedule: "ScheduleComponent",
382
- name: str | None = None,
383
- inplace: bool = False,
384
- ) -> "Schedule":
385
- """Return a new schedule with ``schedule`` inserted into ``self`` at ``start_time``.
386
-
387
- Args:
388
- start_time: Time to insert the schedule.
389
- schedule: Schedule to insert.
390
- name: Name of the new schedule. Defaults to the name of self.
391
- inplace: Perform operation inplace on this schedule. Otherwise
392
- return a new ``Schedule``.
393
- """
394
- if inplace:
395
- return self._mutable_insert(start_time, schedule)
396
- return self._immutable_insert(start_time, schedule, name=name)
397
-
398
- def _mutable_insert(self, start_time: int, schedule: "ScheduleComponent") -> "Schedule":
399
- """Mutably insert `schedule` into `self` at `start_time`.
400
-
401
- Args:
402
- start_time: Time to insert the second schedule.
403
- schedule: Schedule to mutably insert.
404
- """
405
- self._add_timeslots(start_time, schedule)
406
- self._children.append((start_time, schedule))
407
- self._parameter_manager.update_parameter_table(schedule)
408
- return self
409
-
410
- def _immutable_insert(
411
- self,
412
- start_time: int,
413
- schedule: "ScheduleComponent",
414
- name: str | None = None,
415
- ) -> "Schedule":
416
- """Return a new schedule with ``schedule`` inserted into ``self`` at ``start_time``.
417
- Args:
418
- start_time: Time to insert the schedule.
419
- schedule: Schedule to insert.
420
- name: Name of the new ``Schedule``. Defaults to name of ``self``.
421
- """
422
- new_sched = Schedule.initialize_from(self, name)
423
- new_sched._mutable_insert(0, self)
424
- new_sched._mutable_insert(start_time, schedule)
425
- return new_sched
426
-
427
- def append(
428
- self, schedule: "ScheduleComponent", name: str | None = None, inplace: bool = False
429
- ) -> "Schedule":
430
- r"""Return a new schedule with ``schedule`` inserted at the maximum time over
431
- all channels shared between ``self`` and ``schedule``.
432
-
433
- .. math::
434
-
435
- t = \textrm{max}(\texttt{x.stop_time} |\texttt{x} \in
436
- \texttt{self.channels} \cap \texttt{schedule.channels})
437
-
438
- Args:
439
- schedule: Schedule to be appended.
440
- name: Name of the new ``Schedule``. Defaults to name of ``self``.
441
- inplace: Perform operation inplace on this schedule. Otherwise
442
- return a new ``Schedule``.
443
- """
444
- common_channels = set(self.channels) & set(schedule.channels)
445
- time = self.ch_stop_time(*common_channels)
446
- return self.insert(time, schedule, name=name, inplace=inplace)
447
-
448
- def filter(
449
- self,
450
- *filter_funcs: Callable,
451
- channels: Iterable[Channel] | None = None,
452
- instruction_types: Iterable[abc.ABCMeta] | abc.ABCMeta = None,
453
- time_ranges: Iterable[tuple[int, int]] | None = None,
454
- intervals: Iterable[Interval] | None = None,
455
- check_subroutine: bool = True,
456
- ) -> "Schedule":
457
- """Return a new ``Schedule`` with only the instructions from this ``Schedule`` which pass
458
- though the provided filters; i.e. an instruction will be retained iff every function in
459
- ``filter_funcs`` returns ``True``, the instruction occurs on a channel type contained in
460
- ``channels``, the instruction type is contained in ``instruction_types``, and the period
461
- over which the instruction operates is *fully* contained in one specified in
462
- ``time_ranges`` or ``intervals``.
463
-
464
- If no arguments are provided, ``self`` is returned.
465
-
466
- Args:
467
- filter_funcs: A list of Callables which take a (int, Union['Schedule', Instruction])
468
- tuple and return a bool.
469
- channels: For example, ``[DriveChannel(0), AcquireChannel(0)]``.
470
- instruction_types: For example, ``[PulseInstruction, AcquireInstruction]``.
471
- time_ranges: For example, ``[(0, 5), (6, 10)]``.
472
- intervals: For example, ``[(0, 5), (6, 10)]``.
473
- check_subroutine: Set `True` to individually filter instructions inside of a subroutine
474
- defined by the :py:class:`~qiskit.pulse.instructions.Call` instruction.
475
- """
476
- from qiskit.pulse.filters import composite_filter, filter_instructions
477
-
478
- filters = composite_filter(channels, instruction_types, time_ranges, intervals)
479
- filters.extend(filter_funcs)
480
-
481
- return filter_instructions(
482
- self, filters=filters, negate=False, recurse_subroutines=check_subroutine
483
- )
484
-
485
- def exclude(
486
- self,
487
- *filter_funcs: Callable,
488
- channels: Iterable[Channel] | None = None,
489
- instruction_types: Iterable[abc.ABCMeta] | abc.ABCMeta = None,
490
- time_ranges: Iterable[tuple[int, int]] | None = None,
491
- intervals: Iterable[Interval] | None = None,
492
- check_subroutine: bool = True,
493
- ) -> "Schedule":
494
- """Return a ``Schedule`` with only the instructions from this Schedule *failing*
495
- at least one of the provided filters.
496
- This method is the complement of :py:meth:`~Schedule.filter`, so that::
497
-
498
- self.filter(args) | self.exclude(args) == self
499
-
500
- Args:
501
- filter_funcs: A list of Callables which take a (int, Union['Schedule', Instruction])
502
- tuple and return a bool.
503
- channels: For example, ``[DriveChannel(0), AcquireChannel(0)]``.
504
- instruction_types: For example, ``[PulseInstruction, AcquireInstruction]``.
505
- time_ranges: For example, ``[(0, 5), (6, 10)]``.
506
- intervals: For example, ``[(0, 5), (6, 10)]``.
507
- check_subroutine: Set `True` to individually filter instructions inside of a subroutine
508
- defined by the :py:class:`~qiskit.pulse.instructions.Call` instruction.
509
- """
510
- from qiskit.pulse.filters import composite_filter, filter_instructions
511
-
512
- filters = composite_filter(channels, instruction_types, time_ranges, intervals)
513
- filters.extend(filter_funcs)
514
-
515
- return filter_instructions(
516
- self, filters=filters, negate=True, recurse_subroutines=check_subroutine
517
- )
518
-
519
- def _add_timeslots(self, time: int, schedule: "ScheduleComponent") -> None:
520
- """Update all time tracking within this schedule based on the given schedule.
521
-
522
- Args:
523
- time: The time to insert the schedule into self.
524
- schedule: The schedule to insert into self.
525
-
526
- Raises:
527
- PulseError: If timeslots overlap or an invalid start time is provided.
528
- """
529
- if not np.issubdtype(type(time), np.integer):
530
- raise PulseError("Schedule start time must be an integer.")
531
-
532
- other_timeslots = _get_timeslots(schedule)
533
- self._duration = max(self._duration, time + schedule.duration)
534
-
535
- for channel in schedule.channels:
536
- if channel not in self._timeslots:
537
- if time == 0:
538
- self._timeslots[channel] = copy.copy(other_timeslots[channel])
539
- else:
540
- self._timeslots[channel] = [
541
- (i[0] + time, i[1] + time) for i in other_timeslots[channel]
542
- ]
543
- continue
544
-
545
- for idx, interval in enumerate(other_timeslots[channel]):
546
- if interval[0] + time >= self._timeslots[channel][-1][1]:
547
- # Can append the remaining intervals
548
- self._timeslots[channel].extend(
549
- [(i[0] + time, i[1] + time) for i in other_timeslots[channel][idx:]]
550
- )
551
- break
552
-
553
- try:
554
- interval = (interval[0] + time, interval[1] + time)
555
- index = _find_insertion_index(self._timeslots[channel], interval)
556
- self._timeslots[channel].insert(index, interval)
557
- except PulseError as ex:
558
- raise PulseError(
559
- f"Schedule(name='{schedule.name or ''}') cannot be inserted into "
560
- f"Schedule(name='{self.name or ''}') at "
561
- f"time {time} because its instruction on channel {channel} scheduled from time "
562
- f"{interval[0]} to {interval[1]} overlaps with an existing instruction."
563
- ) from ex
564
-
565
- _check_nonnegative_timeslot(self._timeslots)
566
-
567
- def _remove_timeslots(self, time: int, schedule: "ScheduleComponent"):
568
- """Delete the timeslots if present for the respective schedule component.
569
-
570
- Args:
571
- time: The time to remove the timeslots for the ``schedule`` component.
572
- schedule: The schedule to insert into self.
573
-
574
- Raises:
575
- PulseError: If timeslots overlap or an invalid start time is provided.
576
- """
577
- if not isinstance(time, int):
578
- raise PulseError("Schedule start time must be an integer.")
579
-
580
- for channel in schedule.channels:
581
-
582
- if channel not in self._timeslots:
583
- raise PulseError(f"The channel {channel} is not present in the schedule")
584
-
585
- channel_timeslots = self._timeslots[channel]
586
- other_timeslots = _get_timeslots(schedule)
587
-
588
- for interval in other_timeslots[channel]:
589
- if channel_timeslots:
590
- interval = (interval[0] + time, interval[1] + time)
591
- index = _interval_index(channel_timeslots, interval)
592
- if channel_timeslots[index] == interval:
593
- channel_timeslots.pop(index)
594
- continue
595
-
596
- raise PulseError(
597
- f"Cannot find interval ({interval[0]}, {interval[1]}) to remove from "
598
- f"channel {channel} in Schedule(name='{schedule.name}')."
599
- )
600
-
601
- if not channel_timeslots:
602
- self._timeslots.pop(channel)
603
-
604
- def _replace_timeslots(self, time: int, old: "ScheduleComponent", new: "ScheduleComponent"):
605
- """Replace the timeslots of ``old`` if present with the timeslots of ``new``.
606
-
607
- Args:
608
- time: The time to remove the timeslots for the ``schedule`` component.
609
- old: Instruction to replace.
610
- new: Instruction to replace with.
611
- """
612
- self._remove_timeslots(time, old)
613
- self._add_timeslots(time, new)
614
-
615
- def _renew_timeslots(self):
616
- """Regenerate timeslots based on current instructions."""
617
- self._timeslots.clear()
618
- for t0, inst in self.instructions:
619
- self._add_timeslots(t0, inst)
620
-
621
- def replace(
622
- self,
623
- old: "ScheduleComponent",
624
- new: "ScheduleComponent",
625
- inplace: bool = False,
626
- ) -> "Schedule":
627
- """Return a ``Schedule`` with the ``old`` instruction replaced with a ``new``
628
- instruction.
629
-
630
- The replacement matching is based on an instruction equality check.
631
-
632
- .. code-block::
633
-
634
- from qiskit import pulse
635
-
636
- d0 = pulse.DriveChannel(0)
637
-
638
- sched = pulse.Schedule()
639
-
640
- old = pulse.Play(pulse.Constant(100, 1.0), d0)
641
- new = pulse.Play(pulse.Constant(100, 0.1), d0)
642
-
643
- sched += old
644
-
645
- sched = sched.replace(old, new)
646
-
647
- assert sched == pulse.Schedule(new)
648
-
649
- Only matches at the top-level of the schedule tree. If you wish to
650
- perform this replacement over all instructions in the schedule tree.
651
- Flatten the schedule prior to running::
652
-
653
- .. code-block::
654
-
655
- sched = pulse.Schedule()
656
-
657
- sched += pulse.Schedule(old)
658
-
659
- sched = sched.replace(old, new)
660
-
661
- assert sched == pulse.Schedule(new)
662
-
663
- Args:
664
- old: Instruction to replace.
665
- new: Instruction to replace with.
666
- inplace: Replace instruction by mutably modifying this ``Schedule``.
667
-
668
- Returns:
669
- The modified schedule with ``old`` replaced by ``new``.
670
-
671
- Raises:
672
- PulseError: If the ``Schedule`` after replacements will has a timing overlap.
673
- """
674
- from qiskit.pulse.parameter_manager import ParameterManager
675
-
676
- new_children = []
677
- new_parameters = ParameterManager()
678
-
679
- for time, child in self.children:
680
- if child == old:
681
- new_children.append((time, new))
682
- new_parameters.update_parameter_table(new)
683
- else:
684
- new_children.append((time, child))
685
- new_parameters.update_parameter_table(child)
686
-
687
- if inplace:
688
- self._children = new_children
689
- self._parameter_manager = new_parameters
690
- self._renew_timeslots()
691
- return self
692
- else:
693
- try:
694
- new_sched = Schedule.initialize_from(self)
695
- for time, inst in new_children:
696
- new_sched.insert(time, inst, inplace=True)
697
- return new_sched
698
- except PulseError as err:
699
- raise PulseError(
700
- f"Replacement of {old} with {new} results in overlapping instructions."
701
- ) from err
702
-
703
- def is_parameterized(self) -> bool:
704
- """Return True iff the instruction is parameterized."""
705
- return self._parameter_manager.is_parameterized()
706
-
707
- def assign_parameters(
708
- self,
709
- value_dict: dict[
710
- ParameterExpression | ParameterVector | str,
711
- ParameterValueType | Sequence[ParameterValueType],
712
- ],
713
- inplace: bool = True,
714
- ) -> "Schedule":
715
- """Assign the parameters in this schedule according to the input.
716
-
717
- Args:
718
- value_dict: A mapping from parameters or parameter names (parameter vector
719
- or parameter vector name) to either numeric values (list of numeric values)
720
- or another parameter expression (list of parameter expressions).
721
- inplace: Set ``True`` to override this instance with new parameter.
722
-
723
- Returns:
724
- Schedule with updated parameters.
725
- """
726
- if not inplace:
727
- new_schedule = copy.deepcopy(self)
728
- return new_schedule.assign_parameters(value_dict, inplace=True)
729
-
730
- return self._parameter_manager.assign_parameters(pulse_program=self, value_dict=value_dict)
731
-
732
- def get_parameters(self, parameter_name: str) -> list[Parameter]:
733
- """Get parameter object bound to this schedule by string name.
734
-
735
- Because different ``Parameter`` objects can have the same name,
736
- this method returns a list of ``Parameter`` s for the provided name.
737
-
738
- Args:
739
- parameter_name: Name of parameter.
740
-
741
- Returns:
742
- Parameter objects that have corresponding name.
743
- """
744
- return self._parameter_manager.get_parameters(parameter_name)
745
-
746
- def __len__(self) -> int:
747
- """Return number of instructions in the schedule."""
748
- return len(self.instructions)
749
-
750
- def __add__(self, other: "ScheduleComponent") -> "Schedule":
751
- """Return a new schedule with ``other`` inserted within ``self`` at ``start_time``."""
752
- return self.append(other)
753
-
754
- def __or__(self, other: "ScheduleComponent") -> "Schedule":
755
- """Return a new schedule which is the union of `self` and `other`."""
756
- return self.insert(0, other)
757
-
758
- def __lshift__(self, time: int) -> "Schedule":
759
- """Return a new schedule which is shifted forward by ``time``."""
760
- return self.shift(time)
761
-
762
- def __eq__(self, other: object) -> bool:
763
- """Test if two Schedule are equal.
764
-
765
- Equality is checked by verifying there is an equal instruction at every time
766
- in ``other`` for every instruction in this ``Schedule``.
767
-
768
- .. warning::
769
-
770
- This does not check for logical equivalency. Ie.,
771
-
772
- ```python
773
- >>> Delay(10, DriveChannel(0)) + Delay(10, DriveChannel(0))
774
- == Delay(20, DriveChannel(0))
775
- False
776
- ```
777
- """
778
- # 0. type check, we consider Instruction is a subtype of schedule
779
- if not isinstance(other, (type(self), Instruction)):
780
- return False
781
-
782
- # 1. channel check
783
- if set(self.channels) != set(other.channels):
784
- return False
785
-
786
- # 2. size check
787
- if len(self.instructions) != len(other.instructions):
788
- return False
789
-
790
- # 3. instruction check
791
- return all(
792
- self_inst == other_inst
793
- for self_inst, other_inst in zip(self.instructions, other.instructions)
794
- )
795
-
796
- def __repr__(self) -> str:
797
- name = format(self._name) if self._name else ""
798
- instructions = ", ".join([repr(instr) for instr in self.instructions[:50]])
799
- if len(self.instructions) > 25:
800
- instructions += ", ..."
801
- return f'{self.__class__.__name__}({instructions}, name="{name}")'
802
-
803
-
804
- def _require_schedule_conversion(function: Callable) -> Callable:
805
- """A method decorator to convert schedule block to pulse schedule.
806
-
807
- This conversation is performed for backward compatibility only if all durations are assigned.
808
- """
809
-
810
- @functools.wraps(function)
811
- def wrapper(self, *args, **kwargs):
812
- from qiskit.pulse.transforms import block_to_schedule
813
-
814
- return function(block_to_schedule(self), *args, **kwargs)
815
-
816
- return wrapper
817
-
818
-
819
- class ScheduleBlock:
820
- """Time-ordered sequence of instructions with alignment context.
821
-
822
- :class:`.ScheduleBlock` supports lazy scheduling of context instructions,
823
- i.e. their timeslots is always generated at runtime.
824
- This indicates we can parametrize instruction durations as well as
825
- other parameters. In contrast to :class:`.Schedule` being somewhat static,
826
- :class:`.ScheduleBlock` is a dynamic representation of a pulse program.
827
-
828
- .. rubric:: Pulse Builder
829
-
830
- The Qiskit pulse builder is a domain specific language that is developed on top of
831
- the schedule block. Use of the builder syntax will improve the workflow of
832
- pulse programming. See :ref:`pulse_builder` for a user guide.
833
-
834
- .. rubric:: Alignment contexts
835
-
836
- A schedule block is always relatively scheduled.
837
- Instead of taking individual instructions with absolute execution time ``t0``,
838
- the schedule block defines a context of scheduling and instructions
839
- under the same context are scheduled in the same manner (alignment).
840
- Several contexts are available in :ref:`pulse_alignments`.
841
- A schedule block is instantiated with one of these alignment contexts.
842
- The default context is :class:`AlignLeft`, for which all instructions are left-justified,
843
- in other words, meaning they use as-soon-as-possible scheduling.
844
-
845
- If you need an absolute-time interval in between instructions, you can explicitly
846
- insert :class:`~qiskit.pulse.instructions.Delay` instructions.
847
-
848
- .. rubric:: Nested blocks
849
-
850
- A schedule block can contain other nested blocks with different alignment contexts.
851
- This enables advanced scheduling, where a subset of instructions is
852
- locally scheduled in a different manner.
853
- Note that a :class:`.Schedule` instance cannot be directly added to a schedule block.
854
- To add a :class:`.Schedule` instance, wrap it in a :class:`.Call` instruction.
855
- This is implicitly performed when a schedule is added through the :ref:`pulse_builder`.
856
-
857
- .. rubric:: Unsupported operations
858
-
859
- Because the schedule block representation lacks timeslots, it cannot
860
- perform particular :class:`.Schedule` operations such as :meth:`insert` or :meth:`shift` that
861
- require instruction start time ``t0``.
862
- In addition, :meth:`exclude` and :meth:`filter` methods are not supported
863
- because these operations may identify the target instruction with ``t0``.
864
- Except for these operations, :class:`.ScheduleBlock` provides full compatibility
865
- with :class:`.Schedule`.
866
-
867
- .. rubric:: Subroutine
868
-
869
- The timeslots-free representation offers much greater flexibility for writing pulse programs.
870
- Because :class:`.ScheduleBlock` only cares about the ordering of the child blocks
871
- we can add an undefined pulse sequence as a subroutine of the main program.
872
- If your program contains the same sequence multiple times, this representation may
873
- reduce the memory footprint required by the program construction.
874
- Such a subroutine is realized by the special compiler directive
875
- :class:`~qiskit.pulse.instructions.Reference` that is defined by
876
- a unique set of reference key strings to the subroutine.
877
- The (executable) subroutine is separately stored in the main program.
878
- Appended reference directives are resolved when the main program is executed.
879
- Subroutines must be assigned through :meth:`assign_references` before execution.
880
-
881
- One way to reference a subroutine in a schedule is to use the pulse
882
- builder's :func:`~qiskit.pulse.builder.reference` function to declare an
883
- unassigned reference. In this example, the program is called with the
884
- reference key "grand_child". You can call a subroutine without specifying
885
- a substantial program.
886
-
887
- .. code-block::
888
-
889
- from qiskit import pulse
890
- from qiskit.circuit.parameter import Parameter
891
-
892
- amp1 = Parameter("amp1")
893
- amp2 = Parameter("amp2")
894
-
895
- with pulse.build() as sched_inner:
896
- pulse.play(pulse.Constant(100, amp1), pulse.DriveChannel(0))
897
-
898
- with pulse.build() as sched_outer:
899
- with pulse.align_right():
900
- pulse.reference("grand_child")
901
- pulse.play(pulse.Constant(200, amp2), pulse.DriveChannel(0))
902
-
903
- # Now assign the inner pulse program to this reference
904
- sched_outer.assign_references({("grand_child",): sched_inner})
905
- print(sched_outer.parameters)
906
-
907
- .. code-block:: text
908
-
909
- {Parameter(amp1), Parameter(amp2)}
910
-
911
- The outer program now has the parameter ``amp2`` from the inner program,
912
- indicating that the inner program's data has been made available to the
913
- outer program.
914
- The program calling the "grand_child" has a reference program description
915
- which is accessed through :attr:`ScheduleBlock.references`.
916
-
917
- .. code-block::
918
-
919
- print(sched_outer.references)
920
-
921
- .. code-block:: text
922
-
923
- ReferenceManager:
924
- - ('grand_child',): ScheduleBlock(Play(Constant(duration=100, amp=amp1,...
925
-
926
- Finally, you may want to call this program from another program.
927
- Here we try a different approach to define subroutine. Namely, we call
928
- a subroutine from the root program with the actual program ``sched2``.
929
-
930
- .. code-block::
931
-
932
- amp3 = Parameter("amp3")
933
-
934
- with pulse.build() as main:
935
- pulse.play(pulse.Constant(300, amp3), pulse.DriveChannel(0))
936
- pulse.call(sched_outer, name="child")
937
-
938
- print(main.parameters)
939
-
940
- .. code-block:: text
941
-
942
- {Parameter(amp1), Parameter(amp2), Parameter(amp3}
943
-
944
- This implicitly creates a reference named "child" within
945
- the root program and assigns ``sched_outer`` to it.
946
-
947
- Note that the root program is only aware of its direct references.
948
-
949
- .. code-block::
950
-
951
- print(main.references)
952
-
953
- .. code-block:: text
954
-
955
- ReferenceManager:
956
- - ('child',): ScheduleBlock(ScheduleBlock(ScheduleBlock(Play(Con...
957
-
958
- As you can see the main program cannot directly assign a subroutine to the "grand_child" because
959
- this subroutine is not called within the root program, i.e. it is indirectly called by "child".
960
- However, the returned :class:`.ReferenceManager` is a dict-like object, and you can still
961
- reach to "grand_child" via the "child" program with the following chained dict access.
962
-
963
- .. code-block::
964
-
965
- main.references[("child", )].references[("grand_child", )]
966
-
967
- Note that :attr:`ScheduleBlock.parameters` still collects all parameters
968
- also from the subroutine once it's assigned.
969
- """
970
-
971
- __slots__ = (
972
- "_parent",
973
- "_name",
974
- "_reference_manager",
975
- "_parameter_manager",
976
- "_alignment_context",
977
- "_blocks",
978
- "_metadata",
979
- )
980
-
981
- # Prefix to use for auto naming.
982
- prefix = "block"
983
-
984
- # Counter to count instance number.
985
- instances_counter = itertools.count()
986
-
987
- @deprecate_pulse_func
988
- def __init__(
989
- self, name: str | None = None, metadata: dict | None = None, alignment_context=None
990
- ):
991
- """Create an empty schedule block.
992
-
993
- Args:
994
- name: Name of this schedule. Defaults to an autogenerated string if not provided.
995
- metadata: Arbitrary key value metadata to associate with the schedule. This gets
996
- stored as free-form data in a dict in the
997
- :attr:`~qiskit.pulse.ScheduleBlock.metadata` attribute. It will not be directly
998
- used in the schedule.
999
- alignment_context (AlignmentKind): ``AlignmentKind`` instance that manages
1000
- scheduling of instructions in this block.
1001
-
1002
- Raises:
1003
- TypeError: if metadata is not a dict.
1004
- """
1005
- from qiskit.pulse.parameter_manager import ParameterManager
1006
- from qiskit.pulse.transforms import AlignLeft
1007
-
1008
- if name is None:
1009
- name = self.prefix + str(next(self.instances_counter))
1010
- if sys.platform != "win32" and not is_main_process():
1011
- name += f"-{mp.current_process().pid}"
1012
-
1013
- # This points to the parent schedule object in the current scope.
1014
- # Note that schedule block can be nested without referencing, e.g. .append(child_block),
1015
- # and parent=None indicates the root program of the current scope.
1016
- # The nested schedule block objects should not have _reference_manager and
1017
- # should refer to the one of the root program.
1018
- # This also means referenced program should be assigned to the root program, not to child.
1019
- self._parent: ScheduleBlock | None = None
1020
-
1021
- self._name = name
1022
- self._parameter_manager = ParameterManager()
1023
- self._reference_manager = ReferenceManager()
1024
- self._alignment_context = alignment_context or AlignLeft()
1025
- self._blocks: list["BlockComponent"] = []
1026
-
1027
- # get parameters from context
1028
- self._parameter_manager.update_parameter_table(self._alignment_context)
1029
-
1030
- if not isinstance(metadata, dict) and metadata is not None:
1031
- raise TypeError("Only a dictionary or None is accepted for schedule metadata")
1032
- self._metadata = metadata or {}
1033
-
1034
- @classmethod
1035
- def initialize_from(cls, other_program: Any, name: str | None = None) -> "ScheduleBlock":
1036
- """Create new schedule object with metadata of another schedule object.
1037
-
1038
- Args:
1039
- other_program: Qiskit program that provides metadata to new object.
1040
- name: Name of new schedule. Name of ``block`` is used by default.
1041
-
1042
- Returns:
1043
- New block object with name and metadata.
1044
-
1045
- Raises:
1046
- PulseError: When ``other_program`` does not provide necessary information.
1047
- """
1048
- try:
1049
- name = name or other_program.name
1050
-
1051
- if other_program.metadata:
1052
- metadata = other_program.metadata.copy()
1053
- else:
1054
- metadata = None
1055
-
1056
- try:
1057
- alignment_context = other_program.alignment_context
1058
- except AttributeError:
1059
- alignment_context = None
1060
-
1061
- return cls(name=name, metadata=metadata, alignment_context=alignment_context)
1062
- except AttributeError as ex:
1063
- raise PulseError(
1064
- f"{cls.__name__} cannot be initialized from the program data "
1065
- f"{other_program.__class__.__name__}."
1066
- ) from ex
1067
-
1068
- @property
1069
- def name(self) -> str:
1070
- """Return name of this schedule"""
1071
- return self._name
1072
-
1073
- @property
1074
- def metadata(self) -> dict[str, Any]:
1075
- """The user provided metadata associated with the schedule.
1076
-
1077
- User provided ``dict`` of metadata for the schedule.
1078
- The metadata contents do not affect the semantics of the program
1079
- but are used to influence the execution of the schedule. It is expected
1080
- to be passed between all transforms of the schedule and that providers
1081
- will associate any schedule metadata with the results it returns from the
1082
- execution of that schedule.
1083
- """
1084
- return self._metadata
1085
-
1086
- @metadata.setter
1087
- def metadata(self, metadata):
1088
- """Update the schedule metadata"""
1089
- if not isinstance(metadata, dict) and metadata is not None:
1090
- raise TypeError("Only a dictionary or None is accepted for schedule metadata")
1091
- self._metadata = metadata or {}
1092
-
1093
- @property
1094
- def alignment_context(self):
1095
- """Return alignment instance that allocates block component to generate schedule."""
1096
- return self._alignment_context
1097
-
1098
- def is_schedulable(self) -> bool:
1099
- """Return ``True`` if all durations are assigned."""
1100
- # check context assignment
1101
- for context_param in self._alignment_context._context_params:
1102
- if isinstance(context_param, ParameterExpression):
1103
- return False
1104
-
1105
- # check duration assignment
1106
- for elm in self.blocks:
1107
- if isinstance(elm, ScheduleBlock):
1108
- if not elm.is_schedulable():
1109
- return False
1110
- else:
1111
- try:
1112
- if not isinstance(elm.duration, int):
1113
- return False
1114
- except UnassignedReferenceError:
1115
- return False
1116
- return True
1117
-
1118
- @property
1119
- @_require_schedule_conversion
1120
- def duration(self) -> int:
1121
- """Duration of this schedule block."""
1122
- return self.duration
1123
-
1124
- @property
1125
- def channels(self) -> tuple[Channel, ...]:
1126
- """Returns channels that this schedule block uses."""
1127
- chans: set[Channel] = set()
1128
- for elm in self.blocks:
1129
- if isinstance(elm, Reference):
1130
- raise UnassignedReferenceError(
1131
- f"This schedule contains unassigned reference {elm.ref_keys} "
1132
- "and channels are ambiguous. Please assign the subroutine first."
1133
- )
1134
- chans = chans | set(elm.channels)
1135
- return tuple(chans)
1136
-
1137
- @property
1138
- @_require_schedule_conversion
1139
- def instructions(self) -> tuple[tuple[int, Instruction]]:
1140
- """Get the time-ordered instructions from self."""
1141
- return self.instructions
1142
-
1143
- @property
1144
- def blocks(self) -> tuple["BlockComponent", ...]:
1145
- """Get the block elements added to self.
1146
-
1147
- .. note::
1148
-
1149
- The sequence of elements is returned in order of addition. Because the first element is
1150
- schedule first, e.g. FIFO, the returned sequence is roughly time-ordered.
1151
- However, in the parallel alignment context, especially in
1152
- the as-late-as-possible scheduling, or :class:`.AlignRight` context,
1153
- the actual timing of when the instructions are issued is unknown until
1154
- the :class:`.ScheduleBlock` is scheduled and converted into a :class:`.Schedule`.
1155
- """
1156
- blocks = []
1157
- for elm in self._blocks:
1158
- if isinstance(elm, Reference):
1159
- elm = self.references.get(elm.ref_keys, None) or elm
1160
- blocks.append(elm)
1161
- return tuple(blocks)
1162
-
1163
- @property
1164
- def parameters(self) -> set[Parameter]:
1165
- """Return unassigned parameters with raw names."""
1166
- # Need new object not to mutate parameter_manager.parameters
1167
- out_params = set()
1168
-
1169
- out_params |= self._parameter_manager.parameters
1170
- for subroutine in self.references.values():
1171
- if subroutine is None:
1172
- continue
1173
- out_params |= subroutine.parameters
1174
-
1175
- return out_params
1176
-
1177
- @property
1178
- def references(self) -> ReferenceManager:
1179
- """Return a reference manager of the current scope."""
1180
- if self._parent is not None:
1181
- return self._parent.references
1182
- return self._reference_manager
1183
-
1184
- @_require_schedule_conversion
1185
- def ch_duration(self, *channels: Channel) -> int:
1186
- """Return the time of the end of the last instruction over the supplied channels.
1187
-
1188
- Args:
1189
- *channels: Channels within ``self`` to include.
1190
- """
1191
- return self.ch_duration(*channels)
1192
-
1193
- def append(
1194
- self, block: "BlockComponent", name: str | None = None, inplace: bool = True
1195
- ) -> "ScheduleBlock":
1196
- """Return a new schedule block with ``block`` appended to the context block.
1197
- The execution time is automatically assigned when the block is converted into schedule.
1198
-
1199
- Args:
1200
- block: ScheduleBlock to be appended.
1201
- name: Name of the new ``Schedule``. Defaults to name of ``self``.
1202
- inplace: Perform operation inplace on this schedule. Otherwise,
1203
- return a new ``Schedule``.
1204
-
1205
- Returns:
1206
- Schedule block with appended schedule.
1207
-
1208
- Raises:
1209
- PulseError: When invalid schedule type is specified.
1210
- """
1211
- if not isinstance(block, (ScheduleBlock, Instruction)):
1212
- raise PulseError(
1213
- f"Appended `schedule` {block.__class__.__name__} is invalid type. "
1214
- "Only `Instruction` and `ScheduleBlock` can be accepted."
1215
- )
1216
-
1217
- if not inplace:
1218
- schedule = copy.deepcopy(self)
1219
- schedule._name = name or self.name
1220
- schedule.append(block, inplace=True)
1221
- return schedule
1222
-
1223
- if isinstance(block, Reference) and block.ref_keys not in self.references:
1224
- self.references[block.ref_keys] = None
1225
-
1226
- elif isinstance(block, ScheduleBlock):
1227
- block = copy.deepcopy(block)
1228
- # Expose subroutines to the current main scope.
1229
- # Note that this 'block' is not called.
1230
- # The block is just directly appended to the current scope.
1231
- if block.is_referenced():
1232
- if block._parent is not None:
1233
- # This is an edge case:
1234
- # If this is not a parent, block.references points to the parent's reference
1235
- # where subroutine not referred within the 'block' may exist.
1236
- # Move only references existing in the 'block'.
1237
- # See 'test.python.pulse.test_reference.TestReference.test_appending_child_block'
1238
- for ref in _get_references(block._blocks):
1239
- self.references[ref.ref_keys] = block.references[ref.ref_keys]
1240
- else:
1241
- # Avoid using dict.update and explicitly call __set_item__ for validation.
1242
- # Reference manager of appended block is cleared because of data reduction.
1243
- for ref_keys, ref in block._reference_manager.items():
1244
- self.references[ref_keys] = ref
1245
- block._reference_manager.clear()
1246
- # Now switch the parent because block is appended to self.
1247
- block._parent = self
1248
-
1249
- self._blocks.append(block)
1250
- self._parameter_manager.update_parameter_table(block)
1251
-
1252
- return self
1253
-
1254
- def filter(
1255
- self,
1256
- *filter_funcs: Callable[..., bool],
1257
- channels: Iterable[Channel] | None = None,
1258
- instruction_types: Iterable[abc.ABCMeta] | abc.ABCMeta = None,
1259
- check_subroutine: bool = True,
1260
- ):
1261
- """Return a new ``ScheduleBlock`` with only the instructions from this ``ScheduleBlock``
1262
- which pass though the provided filters; i.e. an instruction will be retained if
1263
- every function in ``filter_funcs`` returns ``True``, the instruction occurs on
1264
- a channel type contained in ``channels``, and the instruction type is contained
1265
- in ``instruction_types``.
1266
-
1267
- .. warning::
1268
- Because ``ScheduleBlock`` is not aware of the execution time of
1269
- the context instructions, filtering out some instructions may
1270
- change the execution time of the remaining instructions.
1271
-
1272
- If no arguments are provided, ``self`` is returned.
1273
-
1274
- Args:
1275
- filter_funcs: A list of Callables which take a ``Instruction`` and return a bool.
1276
- channels: For example, ``[DriveChannel(0), AcquireChannel(0)]``.
1277
- instruction_types: For example, ``[PulseInstruction, AcquireInstruction]``.
1278
- check_subroutine: Set `True` to individually filter instructions inside a subroutine
1279
- defined by the :py:class:`~qiskit.pulse.instructions.Call` instruction.
1280
-
1281
- Returns:
1282
- ``ScheduleBlock`` consisting of instructions that matches with filtering condition.
1283
- """
1284
- from qiskit.pulse.filters import composite_filter, filter_instructions
1285
-
1286
- filters = composite_filter(channels, instruction_types)
1287
- filters.extend(filter_funcs)
1288
-
1289
- return filter_instructions(
1290
- self, filters=filters, negate=False, recurse_subroutines=check_subroutine
1291
- )
1292
-
1293
- def exclude(
1294
- self,
1295
- *filter_funcs: Callable[..., bool],
1296
- channels: Iterable[Channel] | None = None,
1297
- instruction_types: Iterable[abc.ABCMeta] | abc.ABCMeta = None,
1298
- check_subroutine: bool = True,
1299
- ):
1300
- """Return a new ``ScheduleBlock`` with only the instructions from this ``ScheduleBlock``
1301
- *failing* at least one of the provided filters.
1302
- This method is the complement of :py:meth:`~ScheduleBlock.filter`, so that::
1303
-
1304
- self.filter(args) + self.exclude(args) == self in terms of instructions included.
1305
-
1306
- .. warning::
1307
- Because ``ScheduleBlock`` is not aware of the execution time of
1308
- the context instructions, excluding some instructions may
1309
- change the execution time of the remaining instructions.
1310
-
1311
- Args:
1312
- filter_funcs: A list of Callables which take a ``Instruction`` and return a bool.
1313
- channels: For example, ``[DriveChannel(0), AcquireChannel(0)]``.
1314
- instruction_types: For example, ``[PulseInstruction, AcquireInstruction]``.
1315
- check_subroutine: Set `True` to individually filter instructions inside of a subroutine
1316
- defined by the :py:class:`~qiskit.pulse.instructions.Call` instruction.
1317
-
1318
- Returns:
1319
- ``ScheduleBlock`` consisting of instructions that do not match with
1320
- at least one of filtering conditions.
1321
- """
1322
- from qiskit.pulse.filters import composite_filter, filter_instructions
1323
-
1324
- filters = composite_filter(channels, instruction_types)
1325
- filters.extend(filter_funcs)
1326
-
1327
- return filter_instructions(
1328
- self, filters=filters, negate=True, recurse_subroutines=check_subroutine
1329
- )
1330
-
1331
- def replace(
1332
- self,
1333
- old: "BlockComponent",
1334
- new: "BlockComponent",
1335
- inplace: bool = True,
1336
- ) -> "ScheduleBlock":
1337
- """Return a ``ScheduleBlock`` with the ``old`` component replaced with a ``new``
1338
- component.
1339
-
1340
- Args:
1341
- old: Schedule block component to replace.
1342
- new: Schedule block component to replace with.
1343
- inplace: Replace instruction by mutably modifying this ``ScheduleBlock``.
1344
-
1345
- Returns:
1346
- The modified schedule block with ``old`` replaced by ``new``.
1347
- """
1348
- if not inplace:
1349
- schedule = copy.deepcopy(self)
1350
- return schedule.replace(old, new, inplace=True)
1351
-
1352
- if old not in self._blocks:
1353
- # Avoid unnecessary update of reference and parameter manager
1354
- return self
1355
-
1356
- # Temporarily copies references
1357
- all_references = ReferenceManager()
1358
- if isinstance(new, ScheduleBlock):
1359
- new = copy.deepcopy(new)
1360
- all_references.update(new.references)
1361
- new._reference_manager.clear()
1362
- new._parent = self
1363
- for ref_key, subroutine in self.references.items():
1364
- if ref_key in all_references:
1365
- warnings.warn(
1366
- f"Reference {ref_key} conflicts with substituted program {new.name}. "
1367
- "Existing reference has been replaced with new reference.",
1368
- UserWarning,
1369
- )
1370
- continue
1371
- all_references[ref_key] = subroutine
1372
-
1373
- # Regenerate parameter table by regenerating elements.
1374
- # Note that removal of parameters in old is not sufficient,
1375
- # because corresponding parameters might be also used in another block element.
1376
- self._parameter_manager.clear()
1377
- self._parameter_manager.update_parameter_table(self._alignment_context)
1378
-
1379
- new_elms = []
1380
- for elm in self._blocks:
1381
- if elm == old:
1382
- elm = new
1383
- self._parameter_manager.update_parameter_table(elm)
1384
- new_elms.append(elm)
1385
- self._blocks = new_elms
1386
-
1387
- # Regenerate reference table
1388
- # Note that reference is attached to the outer schedule if nested.
1389
- # Thus, this investigates all references within the scope.
1390
- self.references.clear()
1391
- root = self
1392
- while root._parent is not None:
1393
- root = root._parent
1394
- for ref in _get_references(root._blocks):
1395
- self.references[ref.ref_keys] = all_references[ref.ref_keys]
1396
-
1397
- return self
1398
-
1399
- def is_parameterized(self) -> bool:
1400
- """Return True iff the instruction is parameterized."""
1401
- return any(self.parameters)
1402
-
1403
- def is_referenced(self) -> bool:
1404
- """Return True iff the current schedule block contains reference to subroutine."""
1405
- return len(self.references) > 0
1406
-
1407
- def assign_parameters(
1408
- self,
1409
- value_dict: dict[
1410
- ParameterExpression | ParameterVector | str,
1411
- ParameterValueType | Sequence[ParameterValueType],
1412
- ],
1413
- inplace: bool = True,
1414
- ) -> "ScheduleBlock":
1415
- """Assign the parameters in this schedule according to the input.
1416
-
1417
- Args:
1418
- value_dict: A mapping from parameters or parameter names (parameter vector
1419
- or parameter vector name) to either numeric values (list of numeric values)
1420
- or another parameter expression (list of parameter expressions).
1421
- inplace: Set ``True`` to override this instance with new parameter.
1422
-
1423
- Returns:
1424
- Schedule with updated parameters.
1425
-
1426
- Raises:
1427
- PulseError: When the block is nested into another block.
1428
- """
1429
- if not inplace:
1430
- new_schedule = copy.deepcopy(self)
1431
- return new_schedule.assign_parameters(value_dict, inplace=True)
1432
-
1433
- # Update parameters in the current scope
1434
- self._parameter_manager.assign_parameters(pulse_program=self, value_dict=value_dict)
1435
-
1436
- for subroutine in self._reference_manager.values():
1437
- # Also assigning parameters to the references associated with self.
1438
- # Note that references are always stored in the root program.
1439
- # So calling assign_parameters from nested block doesn't update references.
1440
- if subroutine is None:
1441
- continue
1442
- subroutine.assign_parameters(value_dict=value_dict, inplace=True)
1443
-
1444
- return self
1445
-
1446
- def assign_references(
1447
- self,
1448
- subroutine_dict: dict[str | tuple[str, ...], "ScheduleBlock"],
1449
- inplace: bool = True,
1450
- ) -> "ScheduleBlock":
1451
- """Assign schedules to references.
1452
-
1453
- It is only capable of assigning a schedule block to immediate references
1454
- which are directly referred within the current scope.
1455
- Let's see following example:
1456
-
1457
- .. code-block:: python
1458
-
1459
- from qiskit import pulse
1460
-
1461
- with pulse.build() as nested_prog:
1462
- pulse.delay(10, pulse.DriveChannel(0))
1463
-
1464
- with pulse.build() as sub_prog:
1465
- pulse.reference("A")
1466
-
1467
- with pulse.build() as main_prog:
1468
- pulse.reference("B")
1469
-
1470
- In above example, the ``main_prog`` can refer to the subroutine "root::B" and the
1471
- reference of "B" to program "A", i.e., "B::A", is not defined in the root namespace.
1472
- This prevents breaking the reference "root::B::A" by the assignment of "root::B".
1473
- For example, if a user could indirectly assign "root::B::A" from the root program,
1474
- one can later assign another program to "root::B" that doesn't contain "A" within it.
1475
- In this situation, a reference "root::B::A" would still live in
1476
- the reference manager of the root.
1477
- However, the subroutine "root::B::A" would no longer be used in the actual pulse program.
1478
- To assign subroutine "A" to ``nested_prog`` as a nested subprogram of ``main_prog``,
1479
- you must first assign "A" of the ``sub_prog``,
1480
- and then assign the ``sub_prog`` to the ``main_prog``.
1481
-
1482
- .. code-block:: python
1483
-
1484
- sub_prog.assign_references({("A", ): nested_prog}, inplace=True)
1485
- main_prog.assign_references({("B", ): sub_prog}, inplace=True)
1486
-
1487
- Alternatively, you can also write
1488
-
1489
- .. code-block:: python
1490
-
1491
- main_prog.assign_references({("B", ): sub_prog}, inplace=True)
1492
- main_prog.references[("B", )].assign_references({("A", ): nested_prog}, inplace=True)
1493
-
1494
- Here :attr:`.references` returns a dict-like object, and you can
1495
- mutably update the nested reference of the particular subroutine.
1496
-
1497
- .. note::
1498
-
1499
- Assigned programs are deep-copied to prevent an unexpected update.
1500
-
1501
- Args:
1502
- subroutine_dict: A mapping from reference key to schedule block of the subroutine.
1503
- inplace: Set ``True`` to override this instance with new subroutine.
1504
-
1505
- Returns:
1506
- Schedule block with assigned subroutine.
1507
-
1508
- Raises:
1509
- PulseError: When reference key is not defined in the current scope.
1510
- """
1511
- if not inplace:
1512
- new_schedule = copy.deepcopy(self)
1513
- return new_schedule.assign_references(subroutine_dict, inplace=True)
1514
-
1515
- for key, subroutine in subroutine_dict.items():
1516
- if key not in self.references:
1517
- unassigned_keys = ", ".join(map(repr, self.references.unassigned()))
1518
- raise PulseError(
1519
- f"Reference instruction with {key} doesn't exist "
1520
- f"in the current scope: {unassigned_keys}"
1521
- )
1522
- self.references[key] = copy.deepcopy(subroutine)
1523
-
1524
- return self
1525
-
1526
- def get_parameters(self, parameter_name: str) -> list[Parameter]:
1527
- """Get parameter object bound to this schedule by string name.
1528
-
1529
- Note that we can define different parameter objects with the same name,
1530
- because these different objects are identified by their unique uuid.
1531
- For example,
1532
-
1533
- .. code-block:: python
1534
-
1535
- from qiskit import pulse, circuit
1536
-
1537
- amp1 = circuit.Parameter("amp")
1538
- amp2 = circuit.Parameter("amp")
1539
-
1540
- with pulse.build() as sub_prog:
1541
- pulse.play(pulse.Constant(100, amp1), pulse.DriveChannel(0))
1542
-
1543
- with pulse.build() as main_prog:
1544
- pulse.call(sub_prog, name="sub")
1545
- pulse.play(pulse.Constant(100, amp2), pulse.DriveChannel(0))
1546
-
1547
- main_prog.get_parameters("amp")
1548
-
1549
- This returns a list of two parameters ``amp1`` and ``amp2``.
1550
-
1551
- Args:
1552
- parameter_name: Name of parameter.
1553
-
1554
- Returns:
1555
- Parameter objects that have corresponding name.
1556
- """
1557
- matched = [p for p in self.parameters if p.name == parameter_name]
1558
- return matched
1559
-
1560
- def __len__(self) -> int:
1561
- """Return number of instructions in the schedule."""
1562
- return len(self.blocks)
1563
-
1564
- def __eq__(self, other: object) -> bool:
1565
- """Test if two ScheduleBlocks are equal.
1566
-
1567
- Equality is checked by verifying there is an equal instruction at every time
1568
- in ``other`` for every instruction in this ``ScheduleBlock``. This check is
1569
- performed by converting the instruction representation into directed acyclic graph,
1570
- in which execution order of every instruction is evaluated correctly across all channels.
1571
- Also ``self`` and ``other`` should have the same alignment context.
1572
-
1573
- .. warning::
1574
-
1575
- This does not check for logical equivalency. Ie.,
1576
-
1577
- ```python
1578
- >>> Delay(10, DriveChannel(0)) + Delay(10, DriveChannel(0))
1579
- == Delay(20, DriveChannel(0))
1580
- False
1581
- ```
1582
- """
1583
- # 0. type check
1584
- if not isinstance(other, type(self)):
1585
- return False
1586
-
1587
- # 1. transformation check
1588
- if self.alignment_context != other.alignment_context:
1589
- return False
1590
-
1591
- # 2. size check
1592
- if len(self) != len(other):
1593
- return False
1594
-
1595
- # 3. instruction check with alignment
1596
- from qiskit.pulse.transforms.dag import block_to_dag as dag
1597
-
1598
- if not rx.is_isomorphic_node_match(dag(self), dag(other), lambda x, y: x == y):
1599
- return False
1600
-
1601
- return True
1602
-
1603
- def __repr__(self) -> str:
1604
- name = format(self._name) if self._name else ""
1605
- blocks = ", ".join([repr(instr) for instr in self.blocks[:50]])
1606
- if len(self.blocks) > 25:
1607
- blocks += ", ..."
1608
- return (
1609
- f'{self.__class__.__name__}({blocks}, name="{name}",'
1610
- f" transform={repr(self.alignment_context)})"
1611
- )
1612
-
1613
- def __add__(self, other: "BlockComponent") -> "ScheduleBlock":
1614
- """Return a new schedule with ``other`` inserted within ``self`` at ``start_time``."""
1615
- return self.append(other)
1616
-
1617
-
1618
- def _common_method(*classes):
1619
- """A function decorator to attach the function to specified classes as a method.
1620
-
1621
- .. note:: For developer: A method attached through this decorator may hurt readability
1622
- of the codebase, because the method may not be detected by a code editor.
1623
- Thus, this decorator should be used to a limited extent, i.e. huge helper method.
1624
- By using this decorator wisely, we can reduce code maintenance overhead without
1625
- losing readability of the codebase.
1626
- """
1627
-
1628
- def decorator(method):
1629
- @functools.wraps(method)
1630
- def wrapper(*args, **kwargs):
1631
- return method(*args, **kwargs)
1632
-
1633
- for cls in classes:
1634
- setattr(cls, method.__name__, wrapper)
1635
- return method
1636
-
1637
- return decorator
1638
-
1639
-
1640
- @deprecate_arg("show_barriers", new_alias="plot_barriers", since="1.4")
1641
- @_common_method(Schedule, ScheduleBlock)
1642
- def draw(
1643
- self,
1644
- style: dict[str, Any] | None = None,
1645
- backend=None, # importing backend causes cyclic import
1646
- time_range: tuple[int, int] | None = None,
1647
- time_unit: str = "dt",
1648
- disable_channels: list[Channel] | None = None,
1649
- show_snapshot: bool = True,
1650
- show_framechange: bool = True,
1651
- show_waveform_info: bool = True,
1652
- plot_barrier: bool = True,
1653
- plotter: str = "mpl2d",
1654
- axis: Any | None = None,
1655
- show_barrier: bool = True,
1656
- ):
1657
- """Plot the schedule.
1658
-
1659
- Args:
1660
- style: Stylesheet options. This can be dictionary or preset stylesheet classes. See
1661
- :py:class:`~qiskit.visualization.pulse_v2.stylesheets.IQXStandard`,
1662
- :py:class:`~qiskit.visualization.pulse_v2.stylesheets.IQXSimple`, and
1663
- :py:class:`~qiskit.visualization.pulse_v2.stylesheets.IQXDebugging` for details of
1664
- preset stylesheets.
1665
- backend (Optional[BaseBackend]): Backend object to play the input pulse program.
1666
- If provided, the plotter may use to make the visualization hardware aware.
1667
- time_range: Set horizontal axis limit. Tuple ``(tmin, tmax)``.
1668
- time_unit: The unit of specified time range either ``dt`` or ``ns``.
1669
- The unit of `ns` is available only when ``backend`` object is provided.
1670
- disable_channels: A control property to show specific pulse channel.
1671
- Pulse channel instances provided as a list are not shown in the output image.
1672
- show_snapshot: Show snapshot instructions.
1673
- show_framechange: Show frame change instructions. The frame change represents
1674
- instructions that modulate phase or frequency of pulse channels.
1675
- show_waveform_info: Show additional information about waveforms such as their name.
1676
- plot_barrier: Show barrier lines.
1677
- plotter: Name of plotter API to generate an output image.
1678
- One of following APIs should be specified::
1679
-
1680
- mpl2d: Matplotlib API for 2D image generation.
1681
- Matplotlib API to generate 2D image. Charts are placed along y axis with
1682
- vertical offset. This API takes matplotlib.axes.Axes as ``axis`` input.
1683
-
1684
- ``axis`` and ``style`` kwargs may depend on the plotter.
1685
- axis: Arbitrary object passed to the plotter. If this object is provided,
1686
- the plotters use a given ``axis`` instead of internally initializing
1687
- a figure object. This object format depends on the plotter.
1688
- See plotter argument for details.
1689
- show_barrier: DEPRECATED. Show barrier lines.
1690
-
1691
- Returns:
1692
- Visualization output data.
1693
- The returned data type depends on the ``plotter``.
1694
- If matplotlib family is specified, this will be a ``matplotlib.pyplot.Figure`` data.
1695
- """
1696
- # pylint: disable=cyclic-import
1697
- from qiskit.visualization import pulse_drawer
1698
-
1699
- del show_barrier
1700
- return pulse_drawer(
1701
- program=self,
1702
- style=style,
1703
- backend=backend,
1704
- time_range=time_range,
1705
- time_unit=time_unit,
1706
- disable_channels=disable_channels,
1707
- show_snapshot=show_snapshot,
1708
- show_framechange=show_framechange,
1709
- show_waveform_info=show_waveform_info,
1710
- plot_barrier=plot_barrier,
1711
- plotter=plotter,
1712
- axis=axis,
1713
- )
1714
-
1715
-
1716
- def _interval_index(intervals: list[Interval], interval: Interval) -> int:
1717
- """Find the index of an interval.
1718
-
1719
- Args:
1720
- intervals: A sorted list of non-overlapping Intervals.
1721
- interval: The interval for which the index into intervals will be found.
1722
-
1723
- Returns:
1724
- The index of the interval.
1725
-
1726
- Raises:
1727
- PulseError: If the interval does not exist.
1728
- """
1729
- index = _locate_interval_index(intervals, interval)
1730
- found_interval = intervals[index]
1731
- if found_interval != interval:
1732
- raise PulseError(f"The interval: {interval} does not exist in intervals: {intervals}")
1733
- return index
1734
-
1735
-
1736
- def _locate_interval_index(intervals: list[Interval], interval: Interval, index: int = 0) -> int:
1737
- """Using binary search on start times, find an interval.
1738
-
1739
- Args:
1740
- intervals: A sorted list of non-overlapping Intervals.
1741
- interval: The interval for which the index into intervals will be found.
1742
- index: A running tally of the index, for recursion. The user should not pass a value.
1743
-
1744
- Returns:
1745
- The index into intervals that new_interval would be inserted to maintain
1746
- a sorted list of intervals.
1747
- """
1748
- if not intervals or len(intervals) == 1:
1749
- return index
1750
-
1751
- mid_idx = len(intervals) // 2
1752
- mid = intervals[mid_idx]
1753
- if interval[1] <= mid[0] and (interval != mid):
1754
- return _locate_interval_index(intervals[:mid_idx], interval, index=index)
1755
- else:
1756
- return _locate_interval_index(intervals[mid_idx:], interval, index=index + mid_idx)
1757
-
1758
-
1759
- def _find_insertion_index(intervals: list[Interval], new_interval: Interval) -> int:
1760
- """Using binary search on start times, return the index into `intervals` where the new interval
1761
- belongs, or raise an error if the new interval overlaps with any existing ones.
1762
- Args:
1763
- intervals: A sorted list of non-overlapping Intervals.
1764
- new_interval: The interval for which the index into intervals will be found.
1765
- Returns:
1766
- The index into intervals that new_interval should be inserted to maintain a sorted list
1767
- of intervals.
1768
- Raises:
1769
- PulseError: If new_interval overlaps with the given intervals.
1770
- """
1771
- index = _locate_interval_index(intervals, new_interval)
1772
- if index < len(intervals):
1773
- if _overlaps(intervals[index], new_interval):
1774
- raise PulseError("New interval overlaps with existing.")
1775
- return index if new_interval[1] <= intervals[index][0] else index + 1
1776
- return index
1777
-
1778
-
1779
- def _overlaps(first: Interval, second: Interval) -> bool:
1780
- """Return True iff first and second overlap.
1781
- Note: first.stop may equal second.start, since Interval stop times are exclusive.
1782
- """
1783
- if first[0] == second[0] == second[1]:
1784
- # They fail to overlap if one of the intervals has duration 0
1785
- return False
1786
- if first[0] > second[0]:
1787
- first, second = second, first
1788
- return second[0] < first[1]
1789
-
1790
-
1791
- def _check_nonnegative_timeslot(timeslots: TimeSlots):
1792
- """Test that a channel has no negative timeslots.
1793
-
1794
- Raises:
1795
- PulseError: If a channel timeslot is negative.
1796
- """
1797
- for chan, chan_timeslots in timeslots.items():
1798
- if chan_timeslots:
1799
- if chan_timeslots[0][0] < 0:
1800
- raise PulseError(f"An instruction on {chan} has a negative starting time.")
1801
-
1802
-
1803
- def _get_timeslots(schedule: "ScheduleComponent") -> TimeSlots:
1804
- """Generate timeslots from given schedule component.
1805
-
1806
- Args:
1807
- schedule: Input schedule component.
1808
-
1809
- Raises:
1810
- PulseError: When invalid schedule type is specified.
1811
- """
1812
- if isinstance(schedule, Instruction):
1813
- duration = schedule.duration
1814
- instruction_duration_validation(duration)
1815
- timeslots = {channel: [(0, duration)] for channel in schedule.channels}
1816
- elif isinstance(schedule, Schedule):
1817
- timeslots = schedule.timeslots
1818
- else:
1819
- raise PulseError(f"Invalid schedule type {type(schedule)} is specified.")
1820
-
1821
- return timeslots
1822
-
1823
-
1824
- def _get_references(block_elms: list["BlockComponent"]) -> set[Reference]:
1825
- """Recursively get reference instructions in the current scope.
1826
-
1827
- Args:
1828
- block_elms: List of schedule block elements to investigate.
1829
-
1830
- Returns:
1831
- A set of unique reference instructions.
1832
- """
1833
- references = set()
1834
- for elm in block_elms:
1835
- if isinstance(elm, ScheduleBlock):
1836
- references |= _get_references(elm._blocks)
1837
- elif isinstance(elm, Reference):
1838
- references.add(elm)
1839
- return references
1840
-
1841
-
1842
- # These type aliases are defined at the bottom of the file, because as of 2022-01-18 they are
1843
- # imported into other parts of Terra. Previously, the aliases were at the top of the file and used
1844
- # forwards references within themselves. This was fine within the same file, but causes scoping
1845
- # issues when the aliases are imported into different scopes, in which the `ForwardRef` instances
1846
- # would no longer resolve. Instead, we only use forward references in the annotations of _this_
1847
- # file to reference the aliases, which are guaranteed to resolve in scope, so the aliases can all be
1848
- # concrete.
1849
-
1850
- ScheduleComponent = Union[Schedule, Instruction]
1851
- """An element that composes a pulse schedule."""
1852
-
1853
- BlockComponent = Union[ScheduleBlock, Instruction]
1854
- """An element that composes a pulse schedule block."""