qiskit 1.4.1__cp39-abi3-macosx_11_0_arm64.whl → 2.0.0rc1__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 (456) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/__init__.py +2 -5
  3. qiskit/_accelerate.abi3.so +0 -0
  4. qiskit/circuit/__init__.py +24 -5
  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 +248 -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 +34 -5
  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/hamiltonian_gate.py +1 -1
  60. qiskit/circuit/library/n_local/evolved_operator_ansatz.py +1 -1
  61. qiskit/circuit/library/n_local/n_local.py +1 -1
  62. qiskit/circuit/library/n_local/qaoa_ansatz.py +1 -1
  63. qiskit/circuit/library/overlap.py +2 -2
  64. qiskit/circuit/library/pauli_evolution.py +39 -24
  65. qiskit/circuit/library/phase_oracle.py +130 -51
  66. qiskit/circuit/library/standard_gates/__init__.py +0 -1
  67. qiskit/circuit/library/standard_gates/dcx.py +3 -4
  68. qiskit/circuit/library/standard_gates/ecr.py +3 -4
  69. qiskit/circuit/library/standard_gates/global_phase.py +5 -6
  70. qiskit/circuit/library/standard_gates/h.py +4 -9
  71. qiskit/circuit/library/standard_gates/i.py +2 -2
  72. qiskit/circuit/library/standard_gates/iswap.py +3 -4
  73. qiskit/circuit/library/standard_gates/p.py +15 -34
  74. qiskit/circuit/library/standard_gates/r.py +2 -6
  75. qiskit/circuit/library/standard_gates/rx.py +5 -15
  76. qiskit/circuit/library/standard_gates/rxx.py +3 -6
  77. qiskit/circuit/library/standard_gates/ry.py +5 -17
  78. qiskit/circuit/library/standard_gates/ryy.py +3 -6
  79. qiskit/circuit/library/standard_gates/rz.py +5 -17
  80. qiskit/circuit/library/standard_gates/rzx.py +3 -6
  81. qiskit/circuit/library/standard_gates/rzz.py +3 -6
  82. qiskit/circuit/library/standard_gates/s.py +6 -15
  83. qiskit/circuit/library/standard_gates/swap.py +4 -11
  84. qiskit/circuit/library/standard_gates/sx.py +7 -12
  85. qiskit/circuit/library/standard_gates/t.py +6 -7
  86. qiskit/circuit/library/standard_gates/u.py +2 -10
  87. qiskit/circuit/library/standard_gates/u1.py +5 -16
  88. qiskit/circuit/library/standard_gates/u2.py +2 -6
  89. qiskit/circuit/library/standard_gates/u3.py +3 -11
  90. qiskit/circuit/library/standard_gates/x.py +13 -60
  91. qiskit/circuit/library/standard_gates/xx_minus_yy.py +2 -5
  92. qiskit/circuit/library/standard_gates/xx_plus_yy.py +2 -5
  93. qiskit/circuit/library/standard_gates/y.py +4 -9
  94. qiskit/circuit/library/standard_gates/z.py +5 -15
  95. qiskit/circuit/measure.py +11 -2
  96. qiskit/circuit/parameterexpression.py +4 -0
  97. qiskit/circuit/quantumcircuit.py +881 -555
  98. qiskit/circuit/random/utils.py +12 -6
  99. qiskit/circuit/reset.py +5 -2
  100. qiskit/circuit/singleton.py +5 -11
  101. qiskit/circuit/store.py +0 -8
  102. qiskit/compiler/__init__.py +1 -7
  103. qiskit/compiler/transpiler.py +38 -196
  104. qiskit/converters/circuit_to_dag.py +4 -2
  105. qiskit/converters/circuit_to_dagdependency.py +0 -2
  106. qiskit/converters/circuit_to_dagdependency_v2.py +0 -1
  107. qiskit/converters/circuit_to_gate.py +1 -1
  108. qiskit/converters/circuit_to_instruction.py +16 -29
  109. qiskit/converters/dag_to_circuit.py +5 -5
  110. qiskit/converters/dag_to_dagdependency.py +0 -1
  111. qiskit/converters/dag_to_dagdependency_v2.py +0 -1
  112. qiskit/converters/dagdependency_to_circuit.py +0 -6
  113. qiskit/converters/dagdependency_to_dag.py +0 -6
  114. qiskit/dagcircuit/collect_blocks.py +32 -20
  115. qiskit/dagcircuit/dagdependency.py +3 -37
  116. qiskit/dagcircuit/dagdependency_v2.py +2 -80
  117. qiskit/dagcircuit/dagnode.py +14 -2
  118. qiskit/passmanager/__init__.py +24 -6
  119. qiskit/passmanager/passmanager.py +26 -24
  120. qiskit/primitives/__init__.py +44 -35
  121. qiskit/primitives/backend_estimator_v2.py +102 -23
  122. qiskit/primitives/backend_sampler_v2.py +5 -20
  123. qiskit/primitives/base/__init__.py +4 -4
  124. qiskit/primitives/base/base_estimator.py +77 -82
  125. qiskit/primitives/base/base_primitive_job.py +2 -2
  126. qiskit/primitives/base/{base_primitive.py → base_primitive_v1.py} +1 -1
  127. qiskit/primitives/base/{base_result.py → base_result_v1.py} +1 -1
  128. qiskit/primitives/base/base_sampler.py +52 -60
  129. qiskit/primitives/base/{estimator_result.py → estimator_result_v1.py} +2 -2
  130. qiskit/primitives/base/{sampler_result.py → sampler_result_v1.py} +2 -2
  131. qiskit/primitives/base/{validation.py → validation_v1.py} +34 -15
  132. qiskit/primitives/containers/bindings_array.py +3 -1
  133. qiskit/primitives/containers/bit_array.py +23 -0
  134. qiskit/primitives/containers/data_bin.py +3 -1
  135. qiskit/primitives/containers/observables_array.py +19 -2
  136. qiskit/primitives/statevector_sampler.py +6 -8
  137. qiskit/primitives/utils.py +14 -189
  138. qiskit/providers/__init__.py +4 -130
  139. qiskit/providers/backend.py +11 -314
  140. qiskit/providers/basic_provider/__init__.py +3 -1
  141. qiskit/providers/basic_provider/basic_provider.py +29 -9
  142. qiskit/providers/basic_provider/basic_simulator.py +158 -298
  143. qiskit/providers/exceptions.py +0 -33
  144. qiskit/providers/fake_provider/__init__.py +0 -37
  145. qiskit/providers/fake_provider/generic_backend_v2.py +32 -693
  146. qiskit/qasm2/__init__.py +21 -6
  147. qiskit/qasm2/export.py +2 -10
  148. qiskit/qasm2/parse.py +11 -25
  149. qiskit/qasm3/__init__.py +5 -1
  150. qiskit/qasm3/ast.py +44 -0
  151. qiskit/qasm3/exporter.py +65 -27
  152. qiskit/qasm3/printer.py +35 -4
  153. qiskit/qpy/__init__.py +141 -19
  154. qiskit/qpy/binary_io/__init__.py +0 -1
  155. qiskit/qpy/binary_io/circuits.py +91 -116
  156. qiskit/qpy/binary_io/schedules.py +61 -388
  157. qiskit/qpy/binary_io/value.py +154 -28
  158. qiskit/qpy/common.py +10 -7
  159. qiskit/qpy/formats.py +41 -0
  160. qiskit/qpy/interface.py +29 -62
  161. qiskit/qpy/type_keys.py +58 -221
  162. qiskit/quantum_info/analysis/distance.py +3 -1
  163. qiskit/quantum_info/operators/dihedral/dihedral.py +3 -1
  164. qiskit/quantum_info/operators/operator.py +6 -2
  165. qiskit/quantum_info/operators/symplectic/clifford.py +3 -1
  166. qiskit/quantum_info/operators/symplectic/pauli.py +4 -2
  167. qiskit/quantum_info/operators/symplectic/pauli_list.py +17 -5
  168. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +40 -6
  169. qiskit/quantum_info/states/densitymatrix.py +16 -6
  170. qiskit/quantum_info/states/stabilizerstate.py +35 -4
  171. qiskit/quantum_info/states/statevector.py +16 -6
  172. qiskit/result/__init__.py +5 -17
  173. qiskit/result/models.py +18 -10
  174. qiskit/result/result.py +28 -126
  175. qiskit/result/sampled_expval.py +1 -2
  176. qiskit/result/utils.py +3 -4
  177. qiskit/synthesis/__init__.py +21 -1
  178. qiskit/synthesis/arithmetic/__init__.py +3 -1
  179. qiskit/synthesis/arithmetic/adders/cdkm_ripple_carry_adder.py +1 -1
  180. qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +1 -1
  181. qiskit/synthesis/arithmetic/adders/vbe_ripple_carry_adder.py +2 -2
  182. qiskit/{providers/fake_provider/backends_v1/fake_20q → synthesis/arithmetic/comparators}/__init__.py +4 -6
  183. qiskit/synthesis/arithmetic/comparators/compare_2s.py +112 -0
  184. qiskit/synthesis/arithmetic/comparators/compare_greedy.py +66 -0
  185. qiskit/synthesis/arithmetic/multipliers/hrs_cumulative_multiplier.py +1 -1
  186. qiskit/synthesis/arithmetic/multipliers/rg_qft_multiplier.py +1 -1
  187. qiskit/synthesis/arithmetic/weighted_sum.py +155 -0
  188. qiskit/{result/mitigation → synthesis/boolean}/__init__.py +2 -2
  189. qiskit/synthesis/boolean/boolean_expression.py +231 -0
  190. qiskit/synthesis/boolean/boolean_expression_synth.py +124 -0
  191. qiskit/synthesis/boolean/boolean_expression_visitor.py +96 -0
  192. qiskit/synthesis/discrete_basis/generate_basis_approximations.py +2 -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 +2 -40
  209. qiskit/transpiler/passes/basis/basis_translator.py +4 -3
  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 +4 -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 +1 -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 +30 -2
  245. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +20 -58
  246. qiskit/transpiler/passes/scheduling/padding/pad_delay.py +11 -3
  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 +127 -59
  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 +101 -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 +67 -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/dag_visualization.py +2 -1
  287. qiskit/visualization/gate_map.py +39 -154
  288. qiskit/visualization/pass_manager_visualization.py +6 -2
  289. qiskit/visualization/state_visualization.py +6 -0
  290. qiskit/visualization/timeline/core.py +18 -12
  291. qiskit/visualization/timeline/interface.py +19 -18
  292. {qiskit-1.4.1.dist-info → qiskit-2.0.0rc1.dist-info}/METADATA +2 -2
  293. {qiskit-1.4.1.dist-info → qiskit-2.0.0rc1.dist-info}/RECORD +297 -444
  294. {qiskit-1.4.1.dist-info → qiskit-2.0.0rc1.dist-info}/WHEEL +2 -1
  295. {qiskit-1.4.1.dist-info → qiskit-2.0.0rc1.dist-info}/entry_points.txt +8 -2
  296. qiskit/assembler/__init__.py +0 -42
  297. qiskit/assembler/assemble_circuits.py +0 -451
  298. qiskit/assembler/assemble_schedules.py +0 -367
  299. qiskit/assembler/disassemble.py +0 -310
  300. qiskit/assembler/run_config.py +0 -77
  301. qiskit/circuit/bit.py +0 -106
  302. qiskit/circuit/classicalfunction/__init__.py +0 -152
  303. qiskit/circuit/classicalfunction/boolean_expression.py +0 -138
  304. qiskit/circuit/classicalfunction/classical_element.py +0 -54
  305. qiskit/circuit/classicalfunction/classical_function_visitor.py +0 -155
  306. qiskit/circuit/classicalfunction/classicalfunction.py +0 -182
  307. qiskit/circuit/classicalfunction/exceptions.py +0 -41
  308. qiskit/circuit/classicalfunction/types.py +0 -18
  309. qiskit/circuit/classicalfunction/utils.py +0 -91
  310. qiskit/circuit/classicalregister.py +0 -57
  311. qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +0 -405
  312. qiskit/circuit/quantumregister.py +0 -75
  313. qiskit/circuit/register.py +0 -246
  314. qiskit/compiler/assembler.py +0 -689
  315. qiskit/compiler/scheduler.py +0 -109
  316. qiskit/compiler/sequencer.py +0 -71
  317. qiskit/primitives/backend_estimator.py +0 -486
  318. qiskit/primitives/backend_sampler.py +0 -222
  319. qiskit/primitives/estimator.py +0 -172
  320. qiskit/primitives/sampler.py +0 -162
  321. qiskit/providers/backend_compat.py +0 -507
  322. qiskit/providers/fake_provider/backends_v1/__init__.py +0 -22
  323. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/__init__.py +0 -18
  324. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/conf_washington.json +0 -1
  325. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/defs_washington.json +0 -1
  326. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/fake_127q_pulse_v1.py +0 -37
  327. qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/props_washington.json +0 -1
  328. qiskit/providers/fake_provider/backends_v1/fake_20q/conf_singapore.json +0 -1
  329. qiskit/providers/fake_provider/backends_v1/fake_20q/fake_20q.py +0 -43
  330. qiskit/providers/fake_provider/backends_v1/fake_20q/props_singapore.json +0 -1
  331. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/__init__.py +0 -18
  332. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/conf_hanoi.json +0 -1
  333. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/defs_hanoi.json +0 -1
  334. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/fake_27q_pulse_v1.py +0 -50
  335. qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/props_hanoi.json +0 -1
  336. qiskit/providers/fake_provider/backends_v1/fake_5q/__init__.py +0 -18
  337. qiskit/providers/fake_provider/backends_v1/fake_5q/conf_yorktown.json +0 -1
  338. qiskit/providers/fake_provider/backends_v1/fake_5q/fake_5q_v1.py +0 -41
  339. qiskit/providers/fake_provider/backends_v1/fake_5q/props_yorktown.json +0 -1
  340. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/__init__.py +0 -18
  341. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/conf_nairobi.json +0 -1
  342. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/defs_nairobi.json +0 -1
  343. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/fake_7q_pulse_v1.py +0 -44
  344. qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/props_nairobi.json +0 -1
  345. qiskit/providers/fake_provider/fake_1q.py +0 -91
  346. qiskit/providers/fake_provider/fake_backend.py +0 -165
  347. qiskit/providers/fake_provider/fake_openpulse_2q.py +0 -391
  348. qiskit/providers/fake_provider/fake_openpulse_3q.py +0 -340
  349. qiskit/providers/fake_provider/fake_pulse_backend.py +0 -49
  350. qiskit/providers/fake_provider/fake_qasm_backend.py +0 -77
  351. qiskit/providers/fake_provider/utils/backend_converter.py +0 -150
  352. qiskit/providers/fake_provider/utils/json_decoder.py +0 -109
  353. qiskit/providers/models/__init__.py +0 -89
  354. qiskit/providers/models/backendconfiguration.py +0 -1040
  355. qiskit/providers/models/backendproperties.py +0 -535
  356. qiskit/providers/models/backendstatus.py +0 -104
  357. qiskit/providers/models/jobstatus.py +0 -77
  358. qiskit/providers/models/pulsedefaults.py +0 -305
  359. qiskit/providers/provider.py +0 -95
  360. qiskit/pulse/__init__.py +0 -158
  361. qiskit/pulse/builder.py +0 -2262
  362. qiskit/pulse/calibration_entries.py +0 -381
  363. qiskit/pulse/channels.py +0 -227
  364. qiskit/pulse/configuration.py +0 -245
  365. qiskit/pulse/exceptions.py +0 -45
  366. qiskit/pulse/filters.py +0 -309
  367. qiskit/pulse/instruction_schedule_map.py +0 -424
  368. qiskit/pulse/instructions/__init__.py +0 -67
  369. qiskit/pulse/instructions/acquire.py +0 -150
  370. qiskit/pulse/instructions/delay.py +0 -71
  371. qiskit/pulse/instructions/directives.py +0 -154
  372. qiskit/pulse/instructions/frequency.py +0 -135
  373. qiskit/pulse/instructions/instruction.py +0 -270
  374. qiskit/pulse/instructions/phase.py +0 -152
  375. qiskit/pulse/instructions/play.py +0 -99
  376. qiskit/pulse/instructions/reference.py +0 -100
  377. qiskit/pulse/instructions/snapshot.py +0 -82
  378. qiskit/pulse/library/__init__.py +0 -97
  379. qiskit/pulse/library/continuous.py +0 -430
  380. qiskit/pulse/library/pulse.py +0 -148
  381. qiskit/pulse/library/samplers/__init__.py +0 -15
  382. qiskit/pulse/library/samplers/decorators.py +0 -295
  383. qiskit/pulse/library/samplers/strategies.py +0 -71
  384. qiskit/pulse/library/symbolic_pulses.py +0 -1989
  385. qiskit/pulse/library/waveform.py +0 -136
  386. qiskit/pulse/macros.py +0 -262
  387. qiskit/pulse/parameter_manager.py +0 -445
  388. qiskit/pulse/parser.py +0 -314
  389. qiskit/pulse/reference_manager.py +0 -58
  390. qiskit/pulse/schedule.py +0 -1854
  391. qiskit/pulse/transforms/__init__.py +0 -106
  392. qiskit/pulse/transforms/alignments.py +0 -406
  393. qiskit/pulse/transforms/base_transforms.py +0 -71
  394. qiskit/pulse/transforms/canonicalization.py +0 -498
  395. qiskit/pulse/transforms/dag.py +0 -122
  396. qiskit/pulse/utils.py +0 -149
  397. qiskit/qobj/__init__.py +0 -75
  398. qiskit/qobj/common.py +0 -81
  399. qiskit/qobj/converters/__init__.py +0 -18
  400. qiskit/qobj/converters/lo_config.py +0 -177
  401. qiskit/qobj/converters/pulse_instruction.py +0 -897
  402. qiskit/qobj/pulse_qobj.py +0 -709
  403. qiskit/qobj/qasm_qobj.py +0 -708
  404. qiskit/qobj/utils.py +0 -46
  405. qiskit/result/mitigation/base_readout_mitigator.py +0 -79
  406. qiskit/result/mitigation/correlated_readout_mitigator.py +0 -277
  407. qiskit/result/mitigation/local_readout_mitigator.py +0 -328
  408. qiskit/result/mitigation/utils.py +0 -217
  409. qiskit/scheduler/__init__.py +0 -40
  410. qiskit/scheduler/config.py +0 -37
  411. qiskit/scheduler/lowering.py +0 -187
  412. qiskit/scheduler/methods/__init__.py +0 -15
  413. qiskit/scheduler/methods/basic.py +0 -140
  414. qiskit/scheduler/schedule_circuit.py +0 -69
  415. qiskit/scheduler/sequence.py +0 -104
  416. qiskit/transpiler/passes/calibration/__init__.py +0 -17
  417. qiskit/transpiler/passes/calibration/base_builder.py +0 -79
  418. qiskit/transpiler/passes/calibration/builders.py +0 -20
  419. qiskit/transpiler/passes/calibration/exceptions.py +0 -22
  420. qiskit/transpiler/passes/calibration/pulse_gate.py +0 -100
  421. qiskit/transpiler/passes/calibration/rx_builder.py +0 -164
  422. qiskit/transpiler/passes/calibration/rzx_builder.py +0 -411
  423. qiskit/transpiler/passes/calibration/rzx_templates.py +0 -58
  424. qiskit/transpiler/passes/optimization/cx_cancellation.py +0 -65
  425. qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py +0 -162
  426. qiskit/transpiler/passes/optimization/normalize_rx_angle.py +0 -157
  427. qiskit/transpiler/passes/routing/stochastic_swap.py +0 -532
  428. qiskit/transpiler/passes/scheduling/alap.py +0 -153
  429. qiskit/transpiler/passes/scheduling/alignments/align_measures.py +0 -255
  430. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +0 -107
  431. qiskit/transpiler/passes/scheduling/asap.py +0 -175
  432. qiskit/transpiler/passes/scheduling/base_scheduler.py +0 -310
  433. qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +0 -313
  434. qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +0 -93
  435. qiskit/utils/deprecate_pulse.py +0 -119
  436. qiskit/utils/multiprocessing.py +0 -56
  437. qiskit/visualization/pulse_v2/__init__.py +0 -21
  438. qiskit/visualization/pulse_v2/core.py +0 -901
  439. qiskit/visualization/pulse_v2/device_info.py +0 -173
  440. qiskit/visualization/pulse_v2/drawings.py +0 -253
  441. qiskit/visualization/pulse_v2/events.py +0 -254
  442. qiskit/visualization/pulse_v2/generators/__init__.py +0 -40
  443. qiskit/visualization/pulse_v2/generators/barrier.py +0 -76
  444. qiskit/visualization/pulse_v2/generators/chart.py +0 -208
  445. qiskit/visualization/pulse_v2/generators/frame.py +0 -436
  446. qiskit/visualization/pulse_v2/generators/snapshot.py +0 -133
  447. qiskit/visualization/pulse_v2/generators/waveform.py +0 -645
  448. qiskit/visualization/pulse_v2/interface.py +0 -459
  449. qiskit/visualization/pulse_v2/layouts.py +0 -387
  450. qiskit/visualization/pulse_v2/plotters/__init__.py +0 -17
  451. qiskit/visualization/pulse_v2/plotters/base_plotter.py +0 -53
  452. qiskit/visualization/pulse_v2/plotters/matplotlib.py +0 -201
  453. qiskit/visualization/pulse_v2/stylesheet.py +0 -312
  454. qiskit/visualization/pulse_v2/types.py +0 -242
  455. {qiskit-1.4.1.dist-info → qiskit-2.0.0rc1.dist-info}/LICENSE.txt +0 -0
  456. {qiskit-1.4.1.dist-info → qiskit-2.0.0rc1.dist-info}/top_level.txt +0 -0
qiskit/pulse/builder.py DELETED
@@ -1,2262 +0,0 @@
1
- # This code is part of Qiskit.
2
- #
3
- # (C) Copyright IBM 2020.
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
- r"""
14
-
15
- .. _pulse_builder:
16
-
17
- =============
18
- Pulse Builder
19
- =============
20
-
21
- ..
22
- We actually want people to think of these functions as being defined within the ``qiskit.pulse``
23
- namespace, not the submodule ``qiskit.pulse.builder``.
24
-
25
- .. currentmodule: qiskit.pulse
26
-
27
- Use the pulse builder DSL to write pulse programs with an imperative syntax.
28
-
29
- .. warning::
30
- The pulse builder interface is still in active development. It may have
31
- breaking API changes without deprecation warnings in future releases until
32
- otherwise indicated.
33
-
34
-
35
- The pulse builder provides an imperative API for writing pulse programs
36
- with less difficulty than the :class:`~qiskit.pulse.Schedule` API.
37
- It contextually constructs a pulse schedule and then emits the schedule for
38
- execution. For example, to play a series of pulses on channels is as simple as:
39
-
40
-
41
- .. plot::
42
- :alt: Output from the previous code.
43
- :include-source:
44
-
45
- from qiskit import pulse
46
-
47
- dc = pulse.DriveChannel
48
- d0, d1, d2, d3, d4 = dc(0), dc(1), dc(2), dc(3), dc(4)
49
-
50
- with pulse.build(name='pulse_programming_in') as pulse_prog:
51
- pulse.play([1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1], d0)
52
- pulse.play([1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0], d1)
53
- pulse.play([1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0], d2)
54
- pulse.play([1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0], d3)
55
- pulse.play([1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0], d4)
56
-
57
- pulse_prog.draw()
58
-
59
- To begin pulse programming we must first initialize our program builder
60
- context with :func:`build`, after which we can begin adding program
61
- statements. For example, below we write a simple program that :func:`play`\s
62
- a pulse:
63
-
64
- .. plot::
65
- :alt: Output from the previous code.
66
- :include-source:
67
-
68
- from qiskit import pulse
69
-
70
- d0 = pulse.DriveChannel(0)
71
-
72
- with pulse.build() as pulse_prog:
73
- pulse.play(pulse.Constant(100, 1.0), d0)
74
-
75
- pulse_prog.draw()
76
-
77
- The builder initializes a :class:`.pulse.Schedule`, ``pulse_prog``
78
- and then begins to construct the program within the context. The output pulse
79
- schedule will survive after the context is exited and can be used like a
80
- normal Qiskit schedule.
81
-
82
- Pulse programming has a simple imperative style. This leaves the programmer
83
- to worry about the raw experimental physics of pulse programming and not
84
- constructing cumbersome data structures.
85
-
86
- We can optionally pass a :class:`~qiskit.providers.Backend` to
87
- :func:`build` to enable enhanced functionality. Below, we prepare a Bell state
88
- by automatically compiling the required pulses from their gate-level
89
- representations, while simultaneously applying a long decoupling pulse to a
90
- neighboring qubit. We terminate the experiment with a measurement to observe the
91
- state we prepared. This program which mixes circuits and pulses will be
92
- automatically lowered to be run as a pulse program:
93
-
94
- .. plot::
95
- :alt: Output from the previous code.
96
- :include-source:
97
-
98
- from math import pi
99
- from qiskit.compiler import schedule
100
- from qiskit.circuit import QuantumCircuit
101
-
102
- from qiskit import pulse
103
- from qiskit.providers.fake_provider import GenericBackendV2
104
-
105
- backend = GenericBackendV2(num_qubits=5, calibrate_instructions=True)
106
-
107
- d2 = pulse.DriveChannel(2)
108
-
109
- qc = QuantumCircuit(2)
110
- # Hadamard
111
- qc.rz(pi/2, 0)
112
- qc.sx(0)
113
- qc.rz(pi/2, 0)
114
-
115
- qc.cx(0, 1)
116
-
117
- bell_sched = schedule(qc, backend)
118
-
119
- with pulse.build(backend) as decoupled_bell_prep_and_measure:
120
- # We call our bell state preparation schedule constructed above.
121
- with pulse.align_right():
122
- pulse.call(bell_sched)
123
- pulse.play(pulse.Constant(bell_sched.duration, 0.02), d2)
124
- pulse.barrier(0, 1, 2)
125
- registers = pulse.measure_all()
126
-
127
- decoupled_bell_prep_and_measure.draw()
128
-
129
-
130
- With the pulse builder we are able to blend programming on qubits and channels.
131
- While the pulse schedule is based on instructions that operate on
132
- channels, the pulse builder automatically handles the mapping from qubits to
133
- channels for you.
134
-
135
- In the example below we demonstrate some more features of the pulse builder:
136
-
137
- .. code-block::
138
-
139
- import math
140
- from qiskit.compiler import schedule
141
-
142
- from qiskit import pulse, QuantumCircuit
143
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
144
-
145
- backend = FakeOpenPulse2Q()
146
-
147
- qc = QuantumCircuit(2, 2)
148
- qc.cx(0, 1)
149
-
150
- with pulse.build(backend) as pulse_prog:
151
- # Create a pulse.
152
- gaussian_pulse = pulse.Gaussian(10, 1.0, 2)
153
- # Get the qubit's corresponding drive channel from the backend.
154
- d0 = pulse.drive_channel(0)
155
- d1 = pulse.drive_channel(1)
156
- # Play a pulse at t=0.
157
- pulse.play(gaussian_pulse, d0)
158
- # Play another pulse directly after the previous pulse at t=10.
159
- pulse.play(gaussian_pulse, d0)
160
- # The default scheduling behavior is to schedule pulses in parallel
161
- # across channels. For example, the statement below
162
- # plays the same pulse on a different channel at t=0.
163
- pulse.play(gaussian_pulse, d1)
164
-
165
- # We also provide pulse scheduling alignment contexts.
166
- # The default alignment context is align_left.
167
-
168
- # The sequential context schedules pulse instructions sequentially in time.
169
- # This context starts at t=10 due to earlier pulses above.
170
- with pulse.align_sequential():
171
- pulse.play(gaussian_pulse, d0)
172
- # Play another pulse after at t=20.
173
- pulse.play(gaussian_pulse, d1)
174
-
175
- # We can also nest contexts as each instruction is
176
- # contained in its local scheduling context.
177
- # The output of a child context is a context-schedule
178
- # with the internal instructions timing fixed relative to
179
- # one another. This is schedule is then called in the parent context.
180
-
181
- # Context starts at t=30.
182
- with pulse.align_left():
183
- # Start at t=30.
184
- pulse.play(gaussian_pulse, d0)
185
- # Start at t=30.
186
- pulse.play(gaussian_pulse, d1)
187
- # Context ends at t=40.
188
-
189
- # Alignment context where all pulse instructions are
190
- # aligned to the right, ie., as late as possible.
191
- with pulse.align_right():
192
- # Shift the phase of a pulse channel.
193
- pulse.shift_phase(math.pi, d1)
194
- # Starts at t=40.
195
- pulse.delay(100, d0)
196
- # Ends at t=140.
197
-
198
- # Starts at t=130.
199
- pulse.play(gaussian_pulse, d1)
200
- # Ends at t=140.
201
-
202
- # Acquire data for a qubit and store in a memory slot.
203
- pulse.acquire(100, 0, pulse.MemorySlot(0))
204
-
205
- # We also support a variety of macros for common operations.
206
-
207
- # Measure all qubits.
208
- pulse.measure_all()
209
-
210
- # Delay on some qubits.
211
- # This requires knowledge of which channels belong to which qubits.
212
- # delay for 100 cycles on qubits 0 and 1.
213
- pulse.delay_qubits(100, 0, 1)
214
-
215
- # Call a schedule for a quantum circuit thereby inserting into
216
- # the pulse schedule.
217
- qc = QuantumCircuit(2, 2)
218
- qc.cx(0, 1)
219
- qc_sched = schedule(qc, backend)
220
- pulse.call(qc_sched)
221
-
222
-
223
- # It is also be possible to call a preexisting schedule
224
- tmp_sched = pulse.Schedule()
225
- tmp_sched += pulse.Play(gaussian_pulse, d0)
226
- pulse.call(tmp_sched)
227
-
228
- # We also support:
229
-
230
- # frequency instructions
231
- pulse.set_frequency(5.0e9, d0)
232
-
233
- # phase instructions
234
- pulse.shift_phase(0.1, d0)
235
-
236
- # offset contexts
237
- with pulse.phase_offset(math.pi, d0):
238
- pulse.play(gaussian_pulse, d0)
239
-
240
-
241
- The above is just a small taste of what is possible with the builder. See the rest of the module
242
- documentation for more information on its capabilities.
243
-
244
- .. autofunction:: build
245
-
246
-
247
- Channels
248
- ========
249
-
250
- Methods to return the correct channels for the respective qubit indices.
251
-
252
- .. code-block::
253
-
254
- from qiskit import pulse
255
- from qiskit.providers.fake_provider import GenericBackendV2
256
-
257
- backend = GenericBackendV2(num_qubits=2, calibrate_instructions=True)
258
-
259
- with pulse.build(backend) as drive_sched:
260
- d0 = pulse.drive_channel(0)
261
- print(d0)
262
-
263
- .. code-block:: text
264
-
265
- DriveChannel(0)
266
-
267
- .. autofunction:: acquire_channel
268
- .. autofunction:: control_channels
269
- .. autofunction:: drive_channel
270
- .. autofunction:: measure_channel
271
-
272
-
273
- Instructions
274
- ============
275
-
276
- Pulse instructions are available within the builder interface. Here's an example:
277
-
278
- .. plot::
279
- :alt: Output from the previous code.
280
- :include-source:
281
-
282
- from qiskit import pulse
283
- from qiskit.providers.fake_provider import GenericBackendV2
284
-
285
- backend = GenericBackendV2(num_qubits=2, calibrate_instructions=True)
286
-
287
- with pulse.build(backend) as drive_sched:
288
- d0 = pulse.drive_channel(0)
289
- a0 = pulse.acquire_channel(0)
290
-
291
- pulse.play(pulse.Constant(10, 1.0), d0)
292
- pulse.delay(20, d0)
293
- pulse.shift_phase(3.14/2, d0)
294
- pulse.set_phase(3.14, d0)
295
- pulse.shift_frequency(1e7, d0)
296
- pulse.set_frequency(5e9, d0)
297
-
298
- with pulse.build() as temp_sched:
299
- pulse.play(pulse.Gaussian(20, 1.0, 3.0), d0)
300
- pulse.play(pulse.Gaussian(20, -1.0, 3.0), d0)
301
-
302
- pulse.call(temp_sched)
303
- pulse.acquire(30, a0, pulse.MemorySlot(0))
304
-
305
- drive_sched.draw()
306
-
307
- .. autofunction:: acquire
308
- .. autofunction:: barrier
309
- .. autofunction:: call
310
- .. autofunction:: delay
311
- .. autofunction:: play
312
- .. autofunction:: reference
313
- .. autofunction:: set_frequency
314
- .. autofunction:: set_phase
315
- .. autofunction:: shift_frequency
316
- .. autofunction:: shift_phase
317
- .. autofunction:: snapshot
318
-
319
-
320
- Contexts
321
- ========
322
-
323
- Builder aware contexts that modify the construction of a pulse program. For
324
- example an alignment context like :func:`align_right` may
325
- be used to align all pulses as late as possible in a pulse program.
326
-
327
- .. plot::
328
- :alt: Output from the previous code.
329
- :include-source:
330
-
331
- from qiskit import pulse
332
-
333
- d0 = pulse.DriveChannel(0)
334
- d1 = pulse.DriveChannel(1)
335
-
336
- with pulse.build() as pulse_prog:
337
- with pulse.align_right():
338
- # this pulse will start at t=0
339
- pulse.play(pulse.Constant(100, 1.0), d0)
340
- # this pulse will start at t=80
341
- pulse.play(pulse.Constant(20, 1.0), d1)
342
-
343
- pulse_prog.draw()
344
-
345
- .. autofunction:: align_equispaced
346
- .. autofunction:: align_func
347
- .. autofunction:: align_left
348
- .. autofunction:: align_right
349
- .. autofunction:: align_sequential
350
- .. autofunction:: frequency_offset
351
- .. autofunction:: phase_offset
352
-
353
-
354
- Macros
355
- ======
356
-
357
- Macros help you add more complex functionality to your pulse program.
358
-
359
- .. code-block::
360
-
361
- from qiskit import pulse
362
- from qiskit.providers.fake_provider import GenericBackendV2
363
-
364
- backend = GenericBackendV2(num_qubits=2, calibrate_instructions=True)
365
-
366
- with pulse.build(backend) as measure_sched:
367
- mem_slot = pulse.measure(0)
368
- print(mem_slot)
369
-
370
- .. code-block:: text
371
-
372
- MemorySlot(0)
373
-
374
- .. autofunction:: measure
375
- .. autofunction:: measure_all
376
- .. autofunction:: delay_qubits
377
-
378
-
379
- Utilities
380
- =========
381
-
382
- The utility functions can be used to gather attributes about the backend and modify
383
- how the program is built.
384
-
385
- .. code-block::
386
-
387
- from qiskit import pulse
388
-
389
- from qiskit.providers.fake_provider import GenericBackendV2
390
-
391
- backend = GenericBackendV2(num_qubits=2, calibrate_instructions=True)
392
-
393
- with pulse.build(backend) as u3_sched:
394
- print('Number of qubits in backend: {}'.format(pulse.num_qubits()))
395
-
396
- samples = 160
397
- print('There are {} samples in {} seconds'.format(
398
- samples, pulse.samples_to_seconds(160)))
399
-
400
- seconds = 1e-6
401
- print('There are {} seconds in {} samples.'.format(
402
- seconds, pulse.seconds_to_samples(1e-6)))
403
-
404
- .. code-block:: text
405
-
406
- Number of qubits in backend: 1
407
- There are 160 samples in 3.5555555555555554e-08 seconds
408
- There are 1e-06 seconds in 4500 samples.
409
-
410
- .. autofunction:: active_backend
411
- .. autofunction:: num_qubits
412
- .. autofunction:: qubit_channels
413
- .. autofunction:: samples_to_seconds
414
- .. autofunction:: seconds_to_samples
415
- """
416
- from __future__ import annotations
417
- import contextvars
418
- import functools
419
- import itertools
420
- import sys
421
- import uuid
422
- import warnings
423
- from collections.abc import Generator, Callable, Iterable
424
- from contextlib import contextmanager
425
- from functools import singledispatchmethod
426
- from typing import TypeVar, ContextManager, TypedDict, Union, Optional, Dict
427
-
428
- import numpy as np
429
-
430
- from qiskit.circuit.parameterexpression import ParameterExpression, ParameterValueType
431
- from qiskit.pulse import (
432
- channels as chans,
433
- configuration,
434
- exceptions,
435
- instructions,
436
- macros,
437
- library,
438
- transforms,
439
- )
440
- from qiskit.providers.backend import BackendV2
441
- from qiskit.pulse.instructions import directives
442
- from qiskit.pulse.schedule import Schedule, ScheduleBlock
443
- from qiskit.pulse.transforms.alignments import AlignmentKind
444
- from qiskit.utils.deprecate_pulse import deprecate_pulse_func
445
-
446
-
447
- if sys.version_info >= (3, 12):
448
- from typing import Unpack
449
- else:
450
- from typing_extensions import Unpack
451
-
452
- #: contextvars.ContextVar[BuilderContext]: active builder
453
- BUILDER_CONTEXTVAR: contextvars.ContextVar["_PulseBuilder"] = contextvars.ContextVar("backend")
454
-
455
- T = TypeVar("T")
456
-
457
- StorageLocation = Union[chans.MemorySlot, chans.RegisterSlot]
458
-
459
-
460
- def _requires_backend(function: Callable[..., T]) -> Callable[..., T]:
461
- """Decorator a function to raise if it is called without a builder with a
462
- set backend.
463
- """
464
-
465
- @functools.wraps(function)
466
- def wrapper(self, *args, **kwargs):
467
- if self.backend is None:
468
- raise exceptions.BackendNotSet(
469
- 'This function requires the builder to have a "backend" set.'
470
- )
471
- return function(self, *args, **kwargs)
472
-
473
- return wrapper
474
-
475
-
476
- class _PulseBuilder:
477
- """Builder context class."""
478
-
479
- __alignment_kinds__ = {
480
- "left": transforms.AlignLeft(),
481
- "right": transforms.AlignRight(),
482
- "sequential": transforms.AlignSequential(),
483
- }
484
-
485
- def __init__(
486
- self,
487
- backend=None,
488
- block: ScheduleBlock | None = None,
489
- name: str | None = None,
490
- default_alignment: str | AlignmentKind = "left",
491
- ):
492
- """Initialize the builder context.
493
-
494
- .. note::
495
- At some point we may consider incorporating the builder into
496
- the :class:`~qiskit.pulse.Schedule` class. However, the risk of
497
- this is tying the user interface to the intermediate
498
- representation. For now we avoid this at the cost of some code
499
- duplication.
500
-
501
- Args:
502
- backend (Backend): Input backend to use in
503
- builder. If not set certain functionality will be unavailable.
504
- block: Initital ``ScheduleBlock`` to build on.
505
- name: Name of pulse program to be built.
506
- default_alignment: Default scheduling alignment for builder.
507
- One of ``left``, ``right``, ``sequential`` or an instance of
508
- :class:`~qiskit.pulse.transforms.alignments.AlignmentKind` subclass.
509
-
510
- Raises:
511
- PulseError: When invalid ``default_alignment`` or `block` is specified.
512
- """
513
- #: Backend: Backend instance for context builder.
514
- self._backend = backend
515
-
516
- # Token for this ``_PulseBuilder``'s ``ContextVar``.
517
- self._backend_ctx_token: contextvars.Token[_PulseBuilder] | None = None
518
-
519
- # Stack of context.
520
- self._context_stack: list[ScheduleBlock] = []
521
-
522
- #: str: Name of the output program
523
- self._name = name
524
-
525
- # Add root block if provided. Schedule will be built on top of this.
526
- if block is not None:
527
- if isinstance(block, ScheduleBlock):
528
- root_block = block
529
- elif isinstance(block, Schedule):
530
- root_block = self._naive_typecast_schedule(block)
531
- else:
532
- raise exceptions.PulseError(
533
- f"Input `block` type {block.__class__.__name__} is "
534
- "not a valid format. Specify a pulse program."
535
- )
536
- self._context_stack.append(root_block)
537
-
538
- # Set default alignment context
539
- if isinstance(default_alignment, AlignmentKind): # AlignmentKind instance
540
- alignment = default_alignment
541
- else: # str identifier
542
- alignment = _PulseBuilder.__alignment_kinds__.get(default_alignment, default_alignment)
543
- if not isinstance(alignment, AlignmentKind):
544
- raise exceptions.PulseError(
545
- f"Given `default_alignment` {repr(default_alignment)} is "
546
- "not a valid transformation. Set one of "
547
- f'{", ".join(_PulseBuilder.__alignment_kinds__.keys())}, '
548
- "or set an instance of `AlignmentKind` subclass."
549
- )
550
- self.push_context(alignment)
551
-
552
- def __enter__(self) -> ScheduleBlock:
553
- """Enter this builder context and yield either the supplied schedule
554
- or the schedule created for the user.
555
-
556
- Returns:
557
- The schedule that the builder will build on.
558
- """
559
- self._backend_ctx_token = BUILDER_CONTEXTVAR.set(self)
560
- output = self._context_stack[0]
561
- output._name = self._name or output.name
562
-
563
- return output
564
-
565
- def __exit__(self, exc_type, exc_val, exc_tb):
566
- """Exit the builder context and compile the built pulse program."""
567
- self.compile()
568
- BUILDER_CONTEXTVAR.reset(self._backend_ctx_token)
569
-
570
- @property
571
- def backend(self):
572
- """Returns the builder backend if set.
573
-
574
- Returns:
575
- Optional[Backend]: The builder's backend.
576
- """
577
- return self._backend
578
-
579
- def push_context(self, alignment: AlignmentKind):
580
- """Push new context to the stack."""
581
- self._context_stack.append(ScheduleBlock(alignment_context=alignment))
582
-
583
- def pop_context(self) -> ScheduleBlock:
584
- """Pop the last context from the stack."""
585
- if len(self._context_stack) == 1:
586
- raise exceptions.PulseError("The root context cannot be popped out.")
587
-
588
- return self._context_stack.pop()
589
-
590
- def get_context(self) -> ScheduleBlock:
591
- """Get current context.
592
-
593
- Notes:
594
- New instruction can be added by `.append_subroutine` or `.append_instruction` method.
595
- Use above methods rather than directly accessing to the current context.
596
- """
597
- return self._context_stack[-1]
598
-
599
- @property
600
- @_requires_backend
601
- def num_qubits(self):
602
- """Get the number of qubits in the backend."""
603
- # backendV2
604
- if isinstance(self.backend, BackendV2):
605
- return self.backend.num_qubits
606
- return self.backend.configuration().n_qubits
607
-
608
- def compile(self) -> ScheduleBlock:
609
- """Compile and output the built pulse program."""
610
- # Not much happens because we currently compile as we build.
611
- # This should be offloaded to a true compilation module
612
- # once we define a more sophisticated IR.
613
-
614
- while len(self._context_stack) > 1:
615
- current = self.pop_context()
616
- self.append_subroutine(current)
617
-
618
- return self._context_stack[0]
619
-
620
- def append_instruction(self, instruction: instructions.Instruction):
621
- """Add an instruction to the builder's context schedule.
622
-
623
- Args:
624
- instruction: Instruction to append.
625
- """
626
- self._context_stack[-1].append(instruction)
627
-
628
- def append_reference(self, name: str, *extra_keys: str):
629
- """Add external program as a :class:`~qiskit.pulse.instructions.Reference` instruction.
630
-
631
- Args:
632
- name: Name of subroutine.
633
- extra_keys: Assistance keys to uniquely specify the subroutine.
634
- """
635
- inst = instructions.Reference(name, *extra_keys)
636
- self.append_instruction(inst)
637
-
638
- def append_subroutine(self, subroutine: Schedule | ScheduleBlock):
639
- """Append a :class:`ScheduleBlock` to the builder's context schedule.
640
-
641
- This operation doesn't create a reference. Subroutine is directly
642
- appended to current context schedule.
643
-
644
- Args:
645
- subroutine: ScheduleBlock to append to the current context block.
646
-
647
- Raises:
648
- PulseError: When subroutine is not Schedule nor ScheduleBlock.
649
- """
650
- if not isinstance(subroutine, (ScheduleBlock, Schedule)):
651
- raise exceptions.PulseError(
652
- f"'{subroutine.__class__.__name__}' is not valid data format in the builder. "
653
- "'Schedule' and 'ScheduleBlock' can be appended to the builder context."
654
- )
655
-
656
- if len(subroutine) == 0:
657
- return
658
- if isinstance(subroutine, Schedule):
659
- subroutine = self._naive_typecast_schedule(subroutine)
660
- self._context_stack[-1].append(subroutine)
661
-
662
- @singledispatchmethod
663
- def call_subroutine(
664
- self,
665
- subroutine: Schedule | ScheduleBlock,
666
- name: str | None = None,
667
- value_dict: dict[ParameterExpression, ParameterValueType] | None = None,
668
- **kw_params: ParameterValueType,
669
- ):
670
- """Call a schedule or circuit defined outside of the current scope.
671
-
672
- The ``subroutine`` is appended to the context schedule as a call instruction.
673
- This logic just generates a convenient program representation in the compiler.
674
- Thus, this doesn't affect execution of inline subroutines.
675
- See :class:`~pulse.instructions.Call` for more details.
676
-
677
- Args:
678
- subroutine: Target schedule or circuit to append to the current context.
679
- name: Name of subroutine if defined.
680
- value_dict: Parameter object and assigned value mapping. This is more precise way to
681
- identify a parameter since mapping is managed with unique object id rather than
682
- name. Especially there is any name collision in a parameter table.
683
- kw_params: Parameter values to bind to the target subroutine
684
- with string parameter names. If there are parameter name overlapping,
685
- these parameters are updated with the same assigned value.
686
-
687
- Raises:
688
- PulseError:
689
- - When input subroutine is not valid data format.
690
- """
691
- raise exceptions.PulseError(
692
- f"Subroutine type {subroutine.__class__.__name__} is "
693
- "not valid data format. Call "
694
- "Schedule, or ScheduleBlock."
695
- )
696
-
697
- @call_subroutine.register
698
- def _(
699
- self,
700
- target_block: ScheduleBlock,
701
- name: Optional[str] = None,
702
- value_dict: Optional[Dict[ParameterExpression, ParameterValueType]] = None,
703
- **kw_params: ParameterValueType,
704
- ):
705
- if len(target_block) == 0:
706
- return
707
-
708
- # Create local parameter assignment
709
- local_assignment = {}
710
- for param_name, value in kw_params.items():
711
- params = target_block.get_parameters(param_name)
712
- if not params:
713
- raise exceptions.PulseError(
714
- f"Parameter {param_name} is not defined in the target subroutine. "
715
- f'{", ".join(map(str, target_block.parameters))} can be specified.'
716
- )
717
- for param in params:
718
- local_assignment[param] = value
719
-
720
- if value_dict:
721
- if local_assignment.keys() & value_dict.keys():
722
- warnings.warn(
723
- "Some parameters provided by 'value_dict' conflict with one through "
724
- "keyword arguments. Parameter values in the keyword arguments "
725
- "are overridden by the dictionary values.",
726
- UserWarning,
727
- )
728
- local_assignment.update(value_dict)
729
-
730
- if local_assignment:
731
- target_block = target_block.assign_parameters(local_assignment, inplace=False)
732
-
733
- if name is None:
734
- # Add unique string, not to accidentally override existing reference entry.
735
- keys: tuple[str, ...] = (target_block.name, uuid.uuid4().hex)
736
- else:
737
- keys = (name,)
738
-
739
- self.append_reference(*keys)
740
- self.get_context().assign_references({keys: target_block}, inplace=True)
741
-
742
- @call_subroutine.register
743
- def _(
744
- self,
745
- target_schedule: Schedule,
746
- name: Optional[str] = None,
747
- value_dict: Optional[Dict[ParameterExpression, ParameterValueType]] = None,
748
- **kw_params: ParameterValueType,
749
- ):
750
- if len(target_schedule) == 0:
751
- return
752
-
753
- self.call_subroutine(
754
- self._naive_typecast_schedule(target_schedule),
755
- name=name,
756
- value_dict=value_dict,
757
- **kw_params,
758
- )
759
-
760
- @staticmethod
761
- def _naive_typecast_schedule(schedule: Schedule):
762
- # Naively convert into ScheduleBlock
763
- from qiskit.pulse.transforms import inline_subroutines, flatten, pad
764
-
765
- preprocessed_schedule = inline_subroutines(flatten(schedule))
766
- pad(preprocessed_schedule, inplace=True, pad_with=instructions.TimeBlockade)
767
-
768
- # default to left alignment, namely ASAP scheduling
769
- target_block = ScheduleBlock(name=schedule.name)
770
- for _, inst in preprocessed_schedule.instructions:
771
- target_block.append(inst, inplace=True)
772
-
773
- return target_block
774
-
775
- def get_dt(self):
776
- """Retrieve dt differently based on the type of Backend"""
777
- if isinstance(self.backend, BackendV2):
778
- return self.backend.dt
779
- return self.backend.configuration().dt
780
-
781
-
782
- @deprecate_pulse_func
783
- def build(
784
- backend=None,
785
- schedule: ScheduleBlock | None = None,
786
- name: str | None = None,
787
- default_alignment: str | AlignmentKind | None = "left",
788
- ) -> ContextManager[ScheduleBlock]:
789
- """Create a context manager for launching the imperative pulse builder DSL.
790
-
791
- To enter a building context and starting building a pulse program:
792
-
793
- .. code-block::
794
-
795
- from qiskit import transpile, pulse
796
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
797
-
798
- backend = FakeOpenPulse2Q()
799
-
800
- d0 = pulse.DriveChannel(0)
801
-
802
- with pulse.build() as pulse_prog:
803
- pulse.play(pulse.Constant(100, 0.5), d0)
804
-
805
-
806
- While the output program ``pulse_prog`` cannot be executed as we are using
807
- a mock backend. If a real backend is being used, executing the program is
808
- done with:
809
-
810
- .. code-block:: python
811
-
812
- backend.run(transpile(pulse_prog, backend))
813
-
814
- Args:
815
- backend (Backend): A Qiskit backend. If not supplied certain
816
- builder functionality will be unavailable.
817
- schedule: A pulse ``ScheduleBlock`` in which your pulse program will be built.
818
- name: Name of pulse program to be built.
819
- default_alignment: Default scheduling alignment for builder.
820
- One of ``left``, ``right``, ``sequential`` or an alignment context.
821
-
822
- Returns:
823
- A new builder context which has the active builder initialized.
824
- """
825
- return _PulseBuilder(
826
- backend=backend,
827
- block=schedule,
828
- name=name,
829
- default_alignment=default_alignment,
830
- )
831
-
832
-
833
- # Builder Utilities
834
-
835
-
836
- def _active_builder() -> _PulseBuilder:
837
- """Get the active builder in the active context.
838
-
839
- Returns:
840
- The active active builder in this context.
841
-
842
- Raises:
843
- exceptions.NoActiveBuilder: If a pulse builder function is called
844
- outside of a builder context.
845
- """
846
- try:
847
- return BUILDER_CONTEXTVAR.get()
848
- except LookupError as ex:
849
- raise exceptions.NoActiveBuilder(
850
- "A Pulse builder function was called outside of "
851
- "a builder context. Try calling within a builder "
852
- 'context, eg., "with pulse.build() as schedule: ...".'
853
- ) from ex
854
-
855
-
856
- @deprecate_pulse_func
857
- def active_backend():
858
- """Get the backend of the currently active builder context.
859
-
860
- Returns:
861
- Backend: The active backend in the currently active
862
- builder context.
863
-
864
- Raises:
865
- exceptions.BackendNotSet: If the builder does not have a backend set.
866
- """
867
- builder = _active_builder().backend
868
- if builder is None:
869
- raise exceptions.BackendNotSet(
870
- 'This function requires the active builder to have a "backend" set.'
871
- )
872
- return builder
873
-
874
-
875
- def append_schedule(schedule: Schedule | ScheduleBlock):
876
- """Call a schedule by appending to the active builder's context block.
877
-
878
- Args:
879
- schedule: Schedule or ScheduleBlock to append.
880
- """
881
- _active_builder().append_subroutine(schedule)
882
-
883
-
884
- def append_instruction(instruction: instructions.Instruction):
885
- """Append an instruction to the active builder's context schedule.
886
-
887
- Examples:
888
-
889
- .. code-block::
890
-
891
- from qiskit import pulse
892
-
893
- d0 = pulse.DriveChannel(0)
894
-
895
- with pulse.build() as pulse_prog:
896
- pulse.builder.append_instruction(pulse.Delay(10, d0))
897
-
898
- print(pulse_prog.instructions)
899
-
900
- .. code-block:: text
901
-
902
- ((0, Delay(10, DriveChannel(0))),)
903
- """
904
- _active_builder().append_instruction(instruction)
905
-
906
-
907
- @deprecate_pulse_func
908
- def num_qubits() -> int:
909
- """Return number of qubits in the currently active backend.
910
-
911
- Examples:
912
-
913
- .. code-block::
914
-
915
- from qiskit import pulse
916
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
917
-
918
- backend = FakeOpenPulse2Q()
919
-
920
- with pulse.build(backend):
921
- print(pulse.num_qubits())
922
-
923
- .. code-block:: text
924
-
925
- 2
926
-
927
- .. note:: Requires the active builder context to have a backend set.
928
- """
929
- if isinstance(active_backend(), BackendV2):
930
- return active_backend().num_qubits
931
- return active_backend().configuration().n_qubits
932
-
933
-
934
- @deprecate_pulse_func
935
- def seconds_to_samples(seconds: float | np.ndarray) -> int | np.ndarray:
936
- """Obtain the number of samples that will elapse in ``seconds`` on the
937
- active backend.
938
-
939
- Rounds down.
940
-
941
- Args:
942
- seconds: Time in seconds to convert to samples.
943
-
944
- Returns:
945
- The number of samples for the time to elapse
946
- """
947
- dt = _active_builder().get_dt()
948
- if isinstance(seconds, np.ndarray):
949
- return (seconds / dt).astype(int)
950
- return int(seconds / dt)
951
-
952
-
953
- @deprecate_pulse_func
954
- def samples_to_seconds(samples: int | np.ndarray) -> float | np.ndarray:
955
- """Obtain the time in seconds that will elapse for the input number of
956
- samples on the active backend.
957
-
958
- Args:
959
- samples: Number of samples to convert to time in seconds.
960
-
961
- Returns:
962
- The time that elapses in ``samples``.
963
- """
964
- return samples * _active_builder().get_dt()
965
-
966
-
967
- @deprecate_pulse_func
968
- def qubit_channels(qubit: int) -> set[chans.Channel]:
969
- """Returns the set of channels associated with a qubit.
970
-
971
- Examples:
972
-
973
- .. code-block::
974
-
975
- from qiskit import pulse
976
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
977
-
978
- backend = FakeOpenPulse2Q()
979
-
980
- with pulse.build(backend):
981
- print(pulse.qubit_channels(0))
982
-
983
- .. code-block:: text
984
-
985
- {MeasureChannel(0), ControlChannel(0), DriveChannel(0), AcquireChannel(0), ControlChannel(1)}
986
-
987
- .. note:: Requires the active builder context to have a backend set.
988
-
989
- .. note:: A channel may still be associated with another qubit in this list
990
- such as in the case where significant crosstalk exists.
991
-
992
- """
993
-
994
- # implement as the inner function to avoid API change for a patch release in 0.24.2.
995
- def get_qubit_channels_v2(backend: BackendV2, qubit: int):
996
- r"""Return a list of channels which operate on the given ``qubit``.
997
- Returns:
998
- List of ``Channel``\s operated on my the given ``qubit``.
999
- """
1000
- channels = []
1001
-
1002
- # add multi-qubit channels
1003
- for node_qubits in backend.coupling_map:
1004
- if qubit in node_qubits:
1005
- control_channel = backend.control_channel(node_qubits)
1006
- if control_channel:
1007
- channels.extend(control_channel)
1008
-
1009
- # add single qubit channels
1010
- channels.append(backend.drive_channel(qubit))
1011
- channels.append(backend.measure_channel(qubit))
1012
- channels.append(backend.acquire_channel(qubit))
1013
- return channels
1014
-
1015
- # backendV2
1016
- if isinstance(active_backend(), BackendV2):
1017
- return set(get_qubit_channels_v2(active_backend(), qubit))
1018
- return set(active_backend().configuration().get_qubit_channels(qubit))
1019
-
1020
-
1021
- def _qubits_to_channels(*channels_or_qubits: int | chans.Channel) -> set[chans.Channel]:
1022
- """Returns the unique channels of the input qubits."""
1023
- channels = set()
1024
- for channel_or_qubit in channels_or_qubits:
1025
- if isinstance(channel_or_qubit, int):
1026
- channels |= qubit_channels(channel_or_qubit)
1027
- elif isinstance(channel_or_qubit, chans.Channel):
1028
- channels.add(channel_or_qubit)
1029
- else:
1030
- raise exceptions.PulseError(
1031
- f'{channel_or_qubit} is not a "Channel" or qubit (integer).'
1032
- )
1033
- return channels
1034
-
1035
-
1036
- # Contexts
1037
-
1038
-
1039
- @contextmanager
1040
- @deprecate_pulse_func
1041
- def align_left() -> Generator[None, None, None]:
1042
- """Left alignment pulse scheduling context.
1043
-
1044
- Pulse instructions within this context are scheduled as early as possible
1045
- by shifting them left to the earliest available time.
1046
-
1047
- Examples:
1048
-
1049
- .. code-block::
1050
-
1051
- from qiskit import pulse
1052
-
1053
- d0 = pulse.DriveChannel(0)
1054
- d1 = pulse.DriveChannel(1)
1055
-
1056
- with pulse.build() as pulse_prog:
1057
- with pulse.align_left():
1058
- # this pulse will start at t=0
1059
- pulse.play(pulse.Constant(100, 1.0), d0)
1060
- # this pulse will start at t=0
1061
- pulse.play(pulse.Constant(20, 1.0), d1)
1062
- pulse_prog = pulse.transforms.block_to_schedule(pulse_prog)
1063
-
1064
- assert pulse_prog.ch_start_time(d0) == pulse_prog.ch_start_time(d1)
1065
-
1066
- Yields:
1067
- None
1068
- """
1069
- builder = _active_builder()
1070
- builder.push_context(transforms.AlignLeft())
1071
- try:
1072
- yield
1073
- finally:
1074
- current = builder.pop_context()
1075
- builder.append_subroutine(current)
1076
-
1077
-
1078
- @contextmanager
1079
- @deprecate_pulse_func
1080
- def align_right() -> Generator[None, None, None]:
1081
- """Right alignment pulse scheduling context.
1082
-
1083
- Pulse instructions within this context are scheduled as late as possible
1084
- by shifting them right to the latest available time.
1085
-
1086
- Examples:
1087
-
1088
- .. code-block::
1089
-
1090
- from qiskit import pulse
1091
-
1092
- d0 = pulse.DriveChannel(0)
1093
- d1 = pulse.DriveChannel(1)
1094
-
1095
- with pulse.build() as pulse_prog:
1096
- with pulse.align_right():
1097
- # this pulse will start at t=0
1098
- pulse.play(pulse.Constant(100, 1.0), d0)
1099
- # this pulse will start at t=80
1100
- pulse.play(pulse.Constant(20, 1.0), d1)
1101
- pulse_prog = pulse.transforms.block_to_schedule(pulse_prog)
1102
-
1103
- assert pulse_prog.ch_stop_time(d0) == pulse_prog.ch_stop_time(d1)
1104
-
1105
- Yields:
1106
- None
1107
- """
1108
- builder = _active_builder()
1109
- builder.push_context(transforms.AlignRight())
1110
- try:
1111
- yield
1112
- finally:
1113
- current = builder.pop_context()
1114
- builder.append_subroutine(current)
1115
-
1116
-
1117
- @contextmanager
1118
- @deprecate_pulse_func
1119
- def align_sequential() -> Generator[None, None, None]:
1120
- """Sequential alignment pulse scheduling context.
1121
-
1122
- Pulse instructions within this context are scheduled sequentially in time
1123
- such that no two instructions will be played at the same time.
1124
-
1125
- Examples:
1126
-
1127
- .. code-block::
1128
-
1129
- from qiskit import pulse
1130
-
1131
- d0 = pulse.DriveChannel(0)
1132
- d1 = pulse.DriveChannel(1)
1133
-
1134
- with pulse.build() as pulse_prog:
1135
- with pulse.align_sequential():
1136
- # this pulse will start at t=0
1137
- pulse.play(pulse.Constant(100, 1.0), d0)
1138
- # this pulse will also start at t=100
1139
- pulse.play(pulse.Constant(20, 1.0), d1)
1140
- pulse_prog = pulse.transforms.block_to_schedule(pulse_prog)
1141
-
1142
- assert pulse_prog.ch_stop_time(d0) == pulse_prog.ch_start_time(d1)
1143
-
1144
- Yields:
1145
- None
1146
- """
1147
- builder = _active_builder()
1148
- builder.push_context(transforms.AlignSequential())
1149
- try:
1150
- yield
1151
- finally:
1152
- current = builder.pop_context()
1153
- builder.append_subroutine(current)
1154
-
1155
-
1156
- @contextmanager
1157
- @deprecate_pulse_func
1158
- def align_equispaced(duration: int | ParameterExpression) -> Generator[None, None, None]:
1159
- """Equispaced alignment pulse scheduling context.
1160
-
1161
- Pulse instructions within this context are scheduled with the same interval spacing such that
1162
- the total length of the context block is ``duration``.
1163
- If the total free ``duration`` cannot be evenly divided by the number of instructions
1164
- within the context, the modulo is split and then prepended and appended to
1165
- the returned schedule. Delay instructions are automatically inserted in between pulses.
1166
-
1167
- This context is convenient to write a schedule for periodical dynamic decoupling or
1168
- the Hahn echo sequence.
1169
-
1170
- Examples:
1171
-
1172
- .. plot::
1173
- :alt: Output from the previous code.
1174
- :include-source:
1175
-
1176
- from qiskit import pulse
1177
-
1178
- d0 = pulse.DriveChannel(0)
1179
- x90 = pulse.Gaussian(10, 0.1, 3)
1180
- x180 = pulse.Gaussian(10, 0.2, 3)
1181
-
1182
- with pulse.build() as hahn_echo:
1183
- with pulse.align_equispaced(duration=100):
1184
- pulse.play(x90, d0)
1185
- pulse.play(x180, d0)
1186
- pulse.play(x90, d0)
1187
-
1188
- hahn_echo.draw()
1189
-
1190
- Args:
1191
- duration: Duration of this context. This should be larger than the schedule duration.
1192
-
1193
- Yields:
1194
- None
1195
-
1196
- Notes:
1197
- The scheduling is performed for sub-schedules within the context rather than
1198
- channel-wise. If you want to apply the equispaced context for each channel,
1199
- you should use the context independently for channels.
1200
- """
1201
- builder = _active_builder()
1202
- builder.push_context(transforms.AlignEquispaced(duration=duration))
1203
- try:
1204
- yield
1205
- finally:
1206
- current = builder.pop_context()
1207
- builder.append_subroutine(current)
1208
-
1209
-
1210
- @contextmanager
1211
- @deprecate_pulse_func
1212
- def align_func(
1213
- duration: int | ParameterExpression, func: Callable[[int], float]
1214
- ) -> Generator[None, None, None]:
1215
- """Callback defined alignment pulse scheduling context.
1216
-
1217
- Pulse instructions within this context are scheduled at the location specified by
1218
- arbitrary callback function `position` that takes integer index and returns
1219
- the associated fractional location within [0, 1].
1220
- Delay instruction is automatically inserted in between pulses.
1221
-
1222
- This context may be convenient to write a schedule of arbitrary dynamical decoupling
1223
- sequences such as Uhrig dynamical decoupling.
1224
-
1225
- Examples:
1226
-
1227
- .. plot::
1228
- :alt: Output from the previous code.
1229
- :include-source:
1230
-
1231
- import numpy as np
1232
- from qiskit import pulse
1233
-
1234
- d0 = pulse.DriveChannel(0)
1235
- x90 = pulse.Gaussian(10, 0.1, 3)
1236
- x180 = pulse.Gaussian(10, 0.2, 3)
1237
-
1238
- def udd10_pos(j):
1239
- return np.sin(np.pi*j/(2*10 + 2))**2
1240
-
1241
- with pulse.build() as udd_sched:
1242
- pulse.play(x90, d0)
1243
- with pulse.align_func(duration=300, func=udd10_pos):
1244
- for _ in range(10):
1245
- pulse.play(x180, d0)
1246
- pulse.play(x90, d0)
1247
-
1248
- udd_sched.draw()
1249
-
1250
- Args:
1251
- duration: Duration of context. This should be larger than the schedule duration.
1252
- func: A function that takes an index of sub-schedule and returns the
1253
- fractional coordinate of of that sub-schedule.
1254
- The returned value should be defined within [0, 1].
1255
- The pulse index starts from 1.
1256
-
1257
- Yields:
1258
- None
1259
-
1260
- Notes:
1261
- The scheduling is performed for sub-schedules within the context rather than
1262
- channel-wise. If you want to apply the numerical context for each channel,
1263
- you need to apply the context independently to channels.
1264
- """
1265
- builder = _active_builder()
1266
- builder.push_context(transforms.AlignFunc(duration=duration, func=func))
1267
- try:
1268
- yield
1269
- finally:
1270
- current = builder.pop_context()
1271
- builder.append_subroutine(current)
1272
-
1273
-
1274
- @contextmanager
1275
- def general_transforms(alignment_context: AlignmentKind) -> Generator[None, None, None]:
1276
- """Arbitrary alignment transformation defined by a subclass instance of
1277
- :class:`~qiskit.pulse.transforms.alignments.AlignmentKind`.
1278
-
1279
- Args:
1280
- alignment_context: Alignment context instance that defines schedule transformation.
1281
-
1282
- Yields:
1283
- None
1284
-
1285
- Raises:
1286
- PulseError: When input ``alignment_context`` is not ``AlignmentKind`` subclasses.
1287
- """
1288
- if not isinstance(alignment_context, AlignmentKind):
1289
- raise exceptions.PulseError("Input alignment context is not `AlignmentKind` subclass.")
1290
-
1291
- builder = _active_builder()
1292
- builder.push_context(alignment_context)
1293
- try:
1294
- yield
1295
- finally:
1296
- current = builder.pop_context()
1297
- builder.append_subroutine(current)
1298
-
1299
-
1300
- @contextmanager
1301
- @deprecate_pulse_func
1302
- def phase_offset(phase: float, *channels: chans.PulseChannel) -> Generator[None, None, None]:
1303
- """Shift the phase of input channels on entry into context and undo on exit.
1304
-
1305
- Examples:
1306
-
1307
- .. code-block::
1308
-
1309
- import math
1310
-
1311
- from qiskit import pulse
1312
-
1313
- d0 = pulse.DriveChannel(0)
1314
-
1315
- with pulse.build() as pulse_prog:
1316
- with pulse.phase_offset(math.pi, d0):
1317
- pulse.play(pulse.Constant(10, 1.0), d0)
1318
-
1319
- assert len(pulse_prog.instructions) == 3
1320
-
1321
- Args:
1322
- phase: Amount of phase offset in radians.
1323
- channels: Channels to offset phase of.
1324
-
1325
- Yields:
1326
- None
1327
- """
1328
- for channel in channels:
1329
- shift_phase(phase, channel)
1330
- try:
1331
- yield
1332
- finally:
1333
- for channel in channels:
1334
- shift_phase(-phase, channel)
1335
-
1336
-
1337
- @contextmanager
1338
- @deprecate_pulse_func
1339
- def frequency_offset(
1340
- frequency: float, *channels: chans.PulseChannel, compensate_phase: bool = False
1341
- ) -> Generator[None, None, None]:
1342
- """Shift the frequency of inputs channels on entry into context and undo on exit.
1343
-
1344
- Examples:
1345
-
1346
- .. code-block:: python
1347
- :emphasize-lines: 7, 16
1348
-
1349
- from qiskit import pulse
1350
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
1351
-
1352
- backend = FakeOpenPulse2Q()
1353
- d0 = pulse.DriveChannel(0)
1354
-
1355
- with pulse.build(backend) as pulse_prog:
1356
- # shift frequency by 1GHz
1357
- with pulse.frequency_offset(1e9, d0):
1358
- pulse.play(pulse.Constant(10, 1.0), d0)
1359
-
1360
- assert len(pulse_prog.instructions) == 3
1361
-
1362
- with pulse.build(backend) as pulse_prog:
1363
- # Shift frequency by 1GHz.
1364
- # Undo accumulated phase in the shifted frequency frame
1365
- # when exiting the context.
1366
- with pulse.frequency_offset(1e9, d0, compensate_phase=True):
1367
- pulse.play(pulse.Constant(10, 1.0), d0)
1368
-
1369
- assert len(pulse_prog.instructions) == 4
1370
-
1371
- Args:
1372
- frequency: Amount of frequency offset in Hz.
1373
- channels: Channels to offset frequency of.
1374
- compensate_phase: Compensate for accumulated phase accumulated with
1375
- respect to the channels' frame at its initial frequency.
1376
-
1377
- Yields:
1378
- None
1379
- """
1380
- builder = _active_builder()
1381
- # TODO: Need proper implementation of compensation. t0 may depend on the parent context.
1382
- # For example, the instruction position within the equispaced context depends on
1383
- # the current total number of instructions, thus adding more instruction after
1384
- # offset context may change the t0 when the parent context is transformed.
1385
- t0 = builder.get_context().duration
1386
-
1387
- for channel in channels:
1388
- shift_frequency(frequency, channel)
1389
- try:
1390
- yield
1391
- finally:
1392
- if compensate_phase:
1393
- duration = builder.get_context().duration - t0
1394
-
1395
- accumulated_phase = 2 * np.pi * ((duration * builder.get_dt() * frequency) % 1)
1396
- for channel in channels:
1397
- shift_phase(-accumulated_phase, channel)
1398
-
1399
- for channel in channels:
1400
- shift_frequency(-frequency, channel)
1401
-
1402
-
1403
- # Channels
1404
- @deprecate_pulse_func
1405
- def drive_channel(qubit: int) -> chans.DriveChannel:
1406
- """Return ``DriveChannel`` for ``qubit`` on the active builder backend.
1407
-
1408
- Examples:
1409
-
1410
- .. code-block::
1411
-
1412
- from qiskit import pulse
1413
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
1414
-
1415
- backend = FakeOpenPulse2Q()
1416
-
1417
- with pulse.build(backend):
1418
- assert pulse.drive_channel(0) == pulse.DriveChannel(0)
1419
-
1420
- .. note:: Requires the active builder context to have a backend set.
1421
- """
1422
- # backendV2
1423
- if isinstance(active_backend(), BackendV2):
1424
- return active_backend().drive_channel(qubit)
1425
- return active_backend().configuration().drive(qubit)
1426
-
1427
-
1428
- @deprecate_pulse_func
1429
- def measure_channel(qubit: int) -> chans.MeasureChannel:
1430
- """Return ``MeasureChannel`` for ``qubit`` on the active builder backend.
1431
-
1432
- Examples:
1433
-
1434
- .. code-block::
1435
-
1436
- from qiskit import pulse
1437
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
1438
-
1439
- backend = FakeOpenPulse2Q()
1440
-
1441
- with pulse.build(backend):
1442
- assert pulse.measure_channel(0) == pulse.MeasureChannel(0)
1443
-
1444
- .. note:: Requires the active builder context to have a backend set.
1445
- """
1446
- # backendV2
1447
- if isinstance(active_backend(), BackendV2):
1448
- return active_backend().measure_channel(qubit)
1449
- return active_backend().configuration().measure(qubit)
1450
-
1451
-
1452
- @deprecate_pulse_func
1453
- def acquire_channel(qubit: int) -> chans.AcquireChannel:
1454
- """Return ``AcquireChannel`` for ``qubit`` on the active builder backend.
1455
-
1456
- Examples:
1457
-
1458
- .. code-block::
1459
-
1460
- from qiskit import pulse
1461
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
1462
-
1463
- backend = FakeOpenPulse2Q()
1464
-
1465
- with pulse.build(backend):
1466
- assert pulse.acquire_channel(0) == pulse.AcquireChannel(0)
1467
-
1468
- .. note:: Requires the active builder context to have a backend set.
1469
- """
1470
- # backendV2
1471
- if isinstance(active_backend(), BackendV2):
1472
- return active_backend().acquire_channel(qubit)
1473
- return active_backend().configuration().acquire(qubit)
1474
-
1475
-
1476
- @deprecate_pulse_func
1477
- def control_channels(*qubits: Iterable[int]) -> list[chans.ControlChannel]:
1478
- """Return ``ControlChannel`` for ``qubit`` on the active builder backend.
1479
-
1480
- Return the secondary drive channel for the given qubit -- typically
1481
- utilized for controlling multi-qubit interactions.
1482
-
1483
- Examples:
1484
-
1485
- .. code-block::
1486
-
1487
- from qiskit import pulse
1488
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
1489
-
1490
- backend = FakeOpenPulse2Q()
1491
- with pulse.build(backend):
1492
- assert pulse.control_channels(0, 1) == [pulse.ControlChannel(0)]
1493
-
1494
- .. note:: Requires the active builder context to have a backend set.
1495
-
1496
- Args:
1497
- qubits: Tuple or list of ordered qubits of the form
1498
- `(control_qubit, target_qubit)`.
1499
-
1500
- Returns:
1501
- List of control channels associated with the supplied ordered list
1502
- of qubits.
1503
- """
1504
- # backendV2
1505
- if isinstance(active_backend(), BackendV2):
1506
- return active_backend().control_channel(qubits)
1507
- return active_backend().configuration().control(qubits=qubits)
1508
-
1509
-
1510
- # Base Instructions
1511
- @deprecate_pulse_func
1512
- def delay(duration: int, channel: chans.Channel, name: str | None = None):
1513
- """Delay on a ``channel`` for a ``duration``.
1514
-
1515
- Examples:
1516
-
1517
- .. code-block::
1518
-
1519
- from qiskit import pulse
1520
-
1521
- d0 = pulse.DriveChannel(0)
1522
-
1523
- with pulse.build() as pulse_prog:
1524
- pulse.delay(10, d0)
1525
-
1526
- Args:
1527
- duration: Number of cycles to delay for on ``channel``.
1528
- channel: Channel to delay on.
1529
- name: Name of the instruction.
1530
- """
1531
- append_instruction(instructions.Delay(duration, channel, name=name))
1532
-
1533
-
1534
- @deprecate_pulse_func
1535
- def play(pulse: library.Pulse | np.ndarray, channel: chans.PulseChannel, name: str | None = None):
1536
- """Play a ``pulse`` on a ``channel``.
1537
-
1538
- Examples:
1539
-
1540
- .. code-block::
1541
-
1542
- from qiskit import pulse
1543
-
1544
- d0 = pulse.DriveChannel(0)
1545
-
1546
- with pulse.build() as pulse_prog:
1547
- pulse.play(pulse.Constant(10, 1.0), d0)
1548
-
1549
- Args:
1550
- pulse: Pulse to play.
1551
- channel: Channel to play pulse on.
1552
- name: Name of the pulse.
1553
- """
1554
- if not isinstance(pulse, library.Pulse):
1555
- pulse = library.Waveform(pulse)
1556
-
1557
- append_instruction(instructions.Play(pulse, channel, name=name))
1558
-
1559
-
1560
- class _MetaDataType(TypedDict, total=False):
1561
- kernel: configuration.Kernel
1562
- discriminator: configuration.Discriminator
1563
- mem_slot: chans.MemorySlot
1564
- reg_slot: chans.RegisterSlot
1565
- name: str
1566
-
1567
-
1568
- @deprecate_pulse_func
1569
- def acquire(
1570
- duration: int,
1571
- qubit_or_channel: int | chans.AcquireChannel,
1572
- register: StorageLocation,
1573
- **metadata: Unpack[_MetaDataType],
1574
- ):
1575
- """Acquire for a ``duration`` on a ``channel`` and store the result
1576
- in a ``register``.
1577
-
1578
- Examples:
1579
-
1580
- .. code-block::
1581
-
1582
- from qiskit import pulse
1583
-
1584
- acq0 = pulse.AcquireChannel(0)
1585
- mem0 = pulse.MemorySlot(0)
1586
-
1587
- with pulse.build() as pulse_prog:
1588
- pulse.acquire(100, acq0, mem0)
1589
-
1590
- # measurement metadata
1591
- kernel = pulse.configuration.Kernel('linear_discriminator')
1592
- pulse.acquire(100, acq0, mem0, kernel=kernel)
1593
-
1594
- .. note:: The type of data acquire will depend on the execution ``meas_level``.
1595
-
1596
- Args:
1597
- duration: Duration to acquire data for
1598
- qubit_or_channel: Either the qubit to acquire data for or the specific
1599
- :class:`~qiskit.pulse.channels.AcquireChannel` to acquire on.
1600
- register: Location to store measured result.
1601
- metadata: Additional metadata for measurement. See
1602
- :class:`~qiskit.pulse.instructions.Acquire` for more information.
1603
-
1604
- Raises:
1605
- exceptions.PulseError: If the register type is not supported.
1606
- """
1607
- if isinstance(qubit_or_channel, int):
1608
- qubit_or_channel = chans.AcquireChannel(qubit_or_channel)
1609
-
1610
- if isinstance(register, chans.MemorySlot):
1611
- append_instruction(
1612
- instructions.Acquire(duration, qubit_or_channel, mem_slot=register, **metadata)
1613
- )
1614
- elif isinstance(register, chans.RegisterSlot):
1615
- append_instruction(
1616
- instructions.Acquire(duration, qubit_or_channel, reg_slot=register, **metadata)
1617
- )
1618
- else:
1619
- raise exceptions.PulseError(f'Register of type: "{type(register)}" is not supported')
1620
-
1621
-
1622
- @deprecate_pulse_func
1623
- def set_frequency(frequency: float, channel: chans.PulseChannel, name: str | None = None):
1624
- """Set the ``frequency`` of a pulse ``channel``.
1625
-
1626
- Examples:
1627
-
1628
- .. code-block::
1629
-
1630
- from qiskit import pulse
1631
-
1632
- d0 = pulse.DriveChannel(0)
1633
-
1634
- with pulse.build() as pulse_prog:
1635
- pulse.set_frequency(1e9, d0)
1636
-
1637
- Args:
1638
- frequency: Frequency in Hz to set channel to.
1639
- channel: Channel to set frequency of.
1640
- name: Name of the instruction.
1641
- """
1642
- append_instruction(instructions.SetFrequency(frequency, channel, name=name))
1643
-
1644
-
1645
- @deprecate_pulse_func
1646
- def shift_frequency(frequency: float, channel: chans.PulseChannel, name: str | None = None):
1647
- """Shift the ``frequency`` of a pulse ``channel``.
1648
-
1649
- Examples:
1650
-
1651
- .. code-block:: python
1652
- :emphasize-lines: 6
1653
-
1654
- from qiskit import pulse
1655
-
1656
- d0 = pulse.DriveChannel(0)
1657
-
1658
- with pulse.build() as pulse_prog:
1659
- pulse.shift_frequency(1e9, d0)
1660
-
1661
- Args:
1662
- frequency: Frequency in Hz to shift channel frequency by.
1663
- channel: Channel to shift frequency of.
1664
- name: Name of the instruction.
1665
- """
1666
- append_instruction(instructions.ShiftFrequency(frequency, channel, name=name))
1667
-
1668
-
1669
- @deprecate_pulse_func
1670
- def set_phase(phase: float, channel: chans.PulseChannel, name: str | None = None):
1671
- """Set the ``phase`` of a pulse ``channel``.
1672
-
1673
- Examples:
1674
-
1675
- .. code-block:: python
1676
- :emphasize-lines: 8
1677
-
1678
- import math
1679
-
1680
- from qiskit import pulse
1681
-
1682
- d0 = pulse.DriveChannel(0)
1683
-
1684
- with pulse.build() as pulse_prog:
1685
- pulse.set_phase(math.pi, d0)
1686
-
1687
- Args:
1688
- phase: Phase in radians to set channel carrier signal to.
1689
- channel: Channel to set phase of.
1690
- name: Name of the instruction.
1691
- """
1692
- append_instruction(instructions.SetPhase(phase, channel, name=name))
1693
-
1694
-
1695
- @deprecate_pulse_func
1696
- def shift_phase(phase: float, channel: chans.PulseChannel, name: str | None = None):
1697
- """Shift the ``phase`` of a pulse ``channel``.
1698
-
1699
- Examples:
1700
-
1701
- .. code-block::
1702
-
1703
- import math
1704
-
1705
- from qiskit import pulse
1706
-
1707
- d0 = pulse.DriveChannel(0)
1708
-
1709
- with pulse.build() as pulse_prog:
1710
- pulse.shift_phase(math.pi, d0)
1711
-
1712
- Args:
1713
- phase: Phase in radians to shift channel carrier signal by.
1714
- channel: Channel to shift phase of.
1715
- name: Name of the instruction.
1716
- """
1717
- append_instruction(instructions.ShiftPhase(phase, channel, name))
1718
-
1719
-
1720
- @deprecate_pulse_func
1721
- def snapshot(label: str, snapshot_type: str = "statevector"):
1722
- """Simulator snapshot.
1723
-
1724
- Examples:
1725
-
1726
- .. code-block::
1727
-
1728
- from qiskit import pulse
1729
-
1730
- with pulse.build() as pulse_prog:
1731
- pulse.snapshot('first', 'statevector')
1732
-
1733
- Args:
1734
- label: Label for snapshot.
1735
- snapshot_type: Type of snapshot.
1736
- """
1737
- append_instruction(instructions.Snapshot(label, snapshot_type=snapshot_type))
1738
-
1739
-
1740
- @deprecate_pulse_func
1741
- def call(
1742
- target: Schedule | ScheduleBlock | None,
1743
- name: str | None = None,
1744
- value_dict: dict[ParameterValueType, ParameterValueType] | None = None,
1745
- **kw_params: ParameterValueType,
1746
- ):
1747
- """Call the subroutine within the currently active builder context with arbitrary
1748
- parameters which will be assigned to the target program.
1749
-
1750
- .. note::
1751
-
1752
- If the ``target`` program is a :class:`.ScheduleBlock`, then a :class:`.Reference`
1753
- instruction will be created and appended to the current context.
1754
- The ``target`` program will be immediately assigned to the current scope as a subroutine.
1755
- If the ``target`` program is :class:`.Schedule`, it will be wrapped by the
1756
- :class:`.Call` instruction and appended to the current context to avoid
1757
- a mixed representation of :class:`.ScheduleBlock` and :class:`.Schedule`.
1758
- If the ``target`` program is a :class:`.QuantumCircuit` it will be scheduled
1759
- and the new :class:`.Schedule` will be added as a :class:`.Call` instruction.
1760
-
1761
- Examples:
1762
-
1763
- 1. Calling a schedule block (recommended)
1764
-
1765
- .. code-block::
1766
-
1767
- from qiskit import circuit, pulse
1768
- from qiskit.providers.fake_provider import GenericBackendV2
1769
-
1770
- backend = GenericBackendV2(num_qubits=5, calibrate_instructions=True)
1771
-
1772
- with pulse.build() as x_sched:
1773
- pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0))
1774
-
1775
- with pulse.build() as pulse_prog:
1776
- pulse.call(x_sched)
1777
-
1778
- print(pulse_prog)
1779
-
1780
- .. code-block:: text
1781
-
1782
- ScheduleBlock(
1783
- ScheduleBlock(
1784
- Play(
1785
- Gaussian(duration=160, amp=(0.1+0j), sigma=40),
1786
- DriveChannel(0)
1787
- ),
1788
- name="block0",
1789
- transform=AlignLeft()
1790
- ),
1791
- name="block1",
1792
- transform=AlignLeft()
1793
- )
1794
-
1795
- The actual program is stored in the reference table attached to the schedule.
1796
-
1797
- .. code-block::
1798
-
1799
- print(pulse_prog.references)
1800
-
1801
- .. code-block:: text
1802
-
1803
- ReferenceManager:
1804
- - ('block0', '634b3b50bd684e26a673af1fbd2d6c81'): ScheduleBlock(Play(Gaussian(...
1805
-
1806
- In addition, you can call a parameterized target program with parameter assignment.
1807
-
1808
- .. code-block::
1809
-
1810
- amp = circuit.Parameter("amp")
1811
-
1812
- with pulse.build() as subroutine:
1813
- pulse.play(pulse.Gaussian(160, amp, 40), pulse.DriveChannel(0))
1814
-
1815
- with pulse.build() as pulse_prog:
1816
- pulse.call(subroutine, amp=0.1)
1817
- pulse.call(subroutine, amp=0.3)
1818
-
1819
- print(pulse_prog)
1820
-
1821
- .. code-block:: text
1822
-
1823
- ScheduleBlock(
1824
- ScheduleBlock(
1825
- Play(
1826
- Gaussian(duration=160, amp=(0.1+0j), sigma=40),
1827
- DriveChannel(0)
1828
- ),
1829
- name="block2",
1830
- transform=AlignLeft()
1831
- ),
1832
- ScheduleBlock(
1833
- Play(
1834
- Gaussian(duration=160, amp=(0.3+0j), sigma=40),
1835
- DriveChannel(0)
1836
- ),
1837
- name="block2",
1838
- transform=AlignLeft()
1839
- ),
1840
- name="block3",
1841
- transform=AlignLeft()
1842
- )
1843
-
1844
- If there is a name collision between parameters, you can distinguish them by specifying
1845
- each parameter object in a python dictionary. For example,
1846
-
1847
- .. code-block::
1848
-
1849
- amp1 = circuit.Parameter('amp')
1850
- amp2 = circuit.Parameter('amp')
1851
-
1852
- with pulse.build() as subroutine:
1853
- pulse.play(pulse.Gaussian(160, amp1, 40), pulse.DriveChannel(0))
1854
- pulse.play(pulse.Gaussian(160, amp2, 40), pulse.DriveChannel(1))
1855
-
1856
- with pulse.build() as pulse_prog:
1857
- pulse.call(subroutine, value_dict={amp1: 0.1, amp2: 0.3})
1858
-
1859
- print(pulse_prog)
1860
-
1861
- .. code-block:: text
1862
-
1863
- ScheduleBlock(
1864
- ScheduleBlock(
1865
- Play(Gaussian(duration=160, amp=(0.1+0j), sigma=40), DriveChannel(0)),
1866
- Play(Gaussian(duration=160, amp=(0.3+0j), sigma=40), DriveChannel(1)),
1867
- name="block4",
1868
- transform=AlignLeft()
1869
- ),
1870
- name="block5",
1871
- transform=AlignLeft()
1872
- )
1873
-
1874
- 2. Calling a schedule
1875
-
1876
- .. code-block::
1877
-
1878
- x_sched = backend.instruction_schedule_map.get("x", (0,))
1879
-
1880
- with pulse.build(backend) as pulse_prog:
1881
- pulse.call(x_sched)
1882
-
1883
- print(pulse_prog)
1884
-
1885
- .. code-block:: text
1886
-
1887
- ScheduleBlock(
1888
- Call(
1889
- Schedule(
1890
- (
1891
- 0,
1892
- Play(
1893
- Drag(
1894
- duration=160,
1895
- amp=(0.18989731546729305+0j),
1896
- sigma=40,
1897
- beta=-1.201258305015517,
1898
- name='drag_86a8'
1899
- ),
1900
- DriveChannel(0),
1901
- name='drag_86a8'
1902
- )
1903
- ),
1904
- name="x"
1905
- ),
1906
- name='x'
1907
- ),
1908
- name="block6",
1909
- transform=AlignLeft()
1910
- )
1911
-
1912
- Currently, the backend calibrated gates are provided in the form of :class:`~.Schedule`.
1913
- The parameter assignment mechanism is available also for schedules.
1914
- However, the called schedule is not treated as a reference.
1915
-
1916
-
1917
- Args:
1918
- target: Target circuit or pulse schedule to call.
1919
- name: Optional. A unique name of subroutine if defined. When the name is explicitly
1920
- provided, one cannot call different schedule blocks with the same name.
1921
- value_dict: Optional. Parameters assigned to the ``target`` program.
1922
- If this dictionary is provided, the ``target`` program is copied and
1923
- then stored in the main built schedule and its parameters are assigned to the given values.
1924
- This dictionary is keyed on :class:`~.Parameter` objects,
1925
- allowing parameter name collision to be avoided.
1926
- kw_params: Alternative way to provide parameters.
1927
- Since this is keyed on the string parameter name,
1928
- the parameters having the same name are all updated together.
1929
- If you want to avoid name collision, use ``value_dict`` with :class:`~.Parameter`
1930
- objects instead.
1931
- """
1932
- _active_builder().call_subroutine(target, name, value_dict, **kw_params)
1933
-
1934
-
1935
- @deprecate_pulse_func
1936
- def reference(name: str, *extra_keys: str):
1937
- """Refer to undefined subroutine by string keys.
1938
-
1939
- A :class:`~qiskit.pulse.instructions.Reference` instruction is implicitly created
1940
- and a schedule can be separately registered to the reference at a later stage.
1941
-
1942
- .. code-block:: python
1943
-
1944
- from qiskit import pulse
1945
-
1946
- with pulse.build() as main_prog:
1947
- pulse.reference("x_gate", "q0")
1948
-
1949
- with pulse.build() as subroutine:
1950
- pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0))
1951
-
1952
- main_prog.assign_references(subroutine_dict={("x_gate", "q0"): subroutine})
1953
-
1954
- Args:
1955
- name: Name of subroutine.
1956
- extra_keys: Helper keys to uniquely specify the subroutine.
1957
- """
1958
- _active_builder().append_reference(name, *extra_keys)
1959
-
1960
-
1961
- # Directives
1962
- @deprecate_pulse_func
1963
- def barrier(*channels_or_qubits: chans.Channel | int, name: str | None = None):
1964
- """Barrier directive for a set of channels and qubits.
1965
-
1966
- This directive prevents the compiler from moving instructions across
1967
- the barrier. Consider the case where we want to enforce that one pulse
1968
- happens after another on separate channels, this can be done with:
1969
-
1970
- .. code-block::
1971
-
1972
- from qiskit import pulse
1973
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
1974
-
1975
- backend = FakeOpenPulse2Q()
1976
-
1977
- d0 = pulse.DriveChannel(0)
1978
- d1 = pulse.DriveChannel(1)
1979
-
1980
- with pulse.build(backend) as barrier_pulse_prog:
1981
- pulse.play(pulse.Constant(10, 1.0), d0)
1982
- pulse.barrier(d0, d1)
1983
- pulse.play(pulse.Constant(10, 1.0), d1)
1984
-
1985
- Of course this could have been accomplished with:
1986
-
1987
- .. code-block::
1988
-
1989
- from qiskit.pulse import transforms
1990
-
1991
- with pulse.build(backend) as aligned_pulse_prog:
1992
- with pulse.align_sequential():
1993
- pulse.play(pulse.Constant(10, 1.0), d0)
1994
- pulse.play(pulse.Constant(10, 1.0), d1)
1995
-
1996
- barrier_pulse_prog = transforms.target_qobj_transform(barrier_pulse_prog)
1997
- aligned_pulse_prog = transforms.target_qobj_transform(aligned_pulse_prog)
1998
-
1999
- assert barrier_pulse_prog == aligned_pulse_prog
2000
-
2001
- The barrier allows the pulse compiler to take care of more advanced
2002
- scheduling alignment operations across channels. For example
2003
- in the case where we are calling an outside circuit or schedule and
2004
- want to align a pulse at the end of one call:
2005
-
2006
- .. code-block::
2007
-
2008
- import math
2009
- from qiskit import pulse
2010
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
2011
-
2012
- backend = FakeOpenPulse2Q()
2013
-
2014
- d0 = pulse.DriveChannel(0)
2015
-
2016
- with pulse.build(backend) as pulse_prog:
2017
- with pulse.align_right():
2018
- pulse.call(backend.defaults().instruction_schedule_map.get('u1', (1,)))
2019
- # Barrier qubit 1 and d0.
2020
- pulse.barrier(1, d0)
2021
- # Due to barrier this will play before the gate on qubit 1.
2022
- pulse.play(pulse.Constant(10, 1.0), d0)
2023
- # This will end at the same time as the pulse above due to
2024
- # the barrier.
2025
- pulse.call(backend.defaults().instruction_schedule_map.get('u1', (1,)))
2026
-
2027
- .. note:: Requires the active builder context to have a backend set if
2028
- qubits are barriered on.
2029
-
2030
- Args:
2031
- channels_or_qubits: Channels or qubits to barrier.
2032
- name: Name for the barrier
2033
- """
2034
- channels = _qubits_to_channels(*channels_or_qubits)
2035
- if len(channels) > 1:
2036
- append_instruction(directives.RelativeBarrier(*channels, name=name))
2037
-
2038
-
2039
- # Macros
2040
- def macro(func: Callable):
2041
- """Wrap a Python function and activate the parent builder context at calling time.
2042
-
2043
- This enables embedding Python functions as builder macros. This generates a new
2044
- :class:`pulse.Schedule` that is embedded in the parent builder context with
2045
- every call of the decorated macro function. The decorated macro function will
2046
- behave as if the function code was embedded inline in the parent builder context
2047
- after parameter substitution.
2048
-
2049
-
2050
- Examples:
2051
-
2052
- .. plot::
2053
- :alt: Output from the previous code.
2054
- :include-source:
2055
-
2056
- from qiskit import pulse
2057
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
2058
-
2059
- @pulse.macro
2060
- def measure(qubit: int):
2061
- pulse.play(pulse.GaussianSquare(16384, 256, 15872), pulse.measure_channel(qubit))
2062
- mem_slot = pulse.MemorySlot(qubit)
2063
- pulse.acquire(16384, pulse.acquire_channel(qubit), mem_slot)
2064
-
2065
- return mem_slot
2066
-
2067
-
2068
- backend = FakeOpenPulse2Q()
2069
-
2070
- with pulse.build(backend=backend) as sched:
2071
- mem_slot = measure(0)
2072
- print(f"Qubit measured into {mem_slot}")
2073
-
2074
- sched.draw()
2075
-
2076
-
2077
- Args:
2078
- func: The Python function to enable as a builder macro. There are no
2079
- requirements on the signature of the function, any calls to pulse
2080
- builder methods will be added to builder context the wrapped function
2081
- is called from.
2082
-
2083
- Returns:
2084
- Callable: The wrapped ``func``.
2085
- """
2086
- func_name = getattr(func, "__name__", repr(func))
2087
-
2088
- @functools.wraps(func)
2089
- def wrapper(*args, **kwargs):
2090
- _builder = _active_builder()
2091
- # activate the pulse builder before calling the function
2092
- with build(backend=_builder.backend, name=func_name) as built:
2093
- output = func(*args, **kwargs)
2094
-
2095
- _builder.call_subroutine(built)
2096
- return output
2097
-
2098
- return wrapper
2099
-
2100
-
2101
- @deprecate_pulse_func
2102
- def measure(
2103
- qubits: list[int] | int,
2104
- registers: list[StorageLocation] | StorageLocation = None,
2105
- ) -> list[StorageLocation] | StorageLocation:
2106
- """Measure a qubit within the currently active builder context.
2107
-
2108
- At the pulse level a measurement is composed of both a stimulus pulse and
2109
- an acquisition instruction which tells the systems measurement unit to
2110
- acquire data and process it. We provide this measurement macro to automate
2111
- the process for you, but if desired full control is still available with
2112
- :func:`acquire` and :func:`play`.
2113
-
2114
- To use the measurement it is as simple as specifying the qubit you wish to
2115
- measure:
2116
-
2117
- .. code-block::
2118
-
2119
- from qiskit import pulse
2120
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
2121
-
2122
- backend = FakeOpenPulse2Q()
2123
-
2124
- qubit = 0
2125
-
2126
- with pulse.build(backend) as pulse_prog:
2127
- # Do something to the qubit.
2128
- qubit_drive_chan = pulse.drive_channel(0)
2129
- pulse.play(pulse.Constant(100, 1.0), qubit_drive_chan)
2130
- # Measure the qubit.
2131
- reg = pulse.measure(qubit)
2132
-
2133
- For now it is not possible to do much with the handle to ``reg`` but in the
2134
- future we will support using this handle to a result register to build
2135
- up ones program. It is also possible to supply this register:
2136
-
2137
- .. code-block::
2138
-
2139
- with pulse.build(backend) as pulse_prog:
2140
- pulse.play(pulse.Constant(100, 1.0), qubit_drive_chan)
2141
- # Measure the qubit.
2142
- mem0 = pulse.MemorySlot(0)
2143
- reg = pulse.measure(qubit, mem0)
2144
-
2145
- assert reg == mem0
2146
-
2147
- .. note:: Requires the active builder context to have a backend set.
2148
-
2149
- Args:
2150
- qubits: Physical qubit to measure.
2151
- registers: Register to store result in. If not selected the current
2152
- behavior is to return the :class:`MemorySlot` with the same
2153
- index as ``qubit``. This register will be returned.
2154
- Returns:
2155
- The ``register`` the qubit measurement result will be stored in.
2156
- """
2157
- backend = active_backend()
2158
-
2159
- try:
2160
- qubits = list(qubits)
2161
- except TypeError:
2162
- qubits = [qubits]
2163
-
2164
- if registers is None:
2165
- registers = [chans.MemorySlot(qubit) for qubit in qubits]
2166
- else:
2167
- try:
2168
- registers = list(registers)
2169
- except TypeError:
2170
- registers = [registers]
2171
- measure_sched = macros.measure(
2172
- qubits=qubits,
2173
- backend=backend,
2174
- qubit_mem_slots={qubit: register.index for qubit, register in zip(qubits, registers)},
2175
- )
2176
-
2177
- # note this is not a subroutine.
2178
- # just a macro to automate combination of stimulus and acquisition.
2179
- # prepare unique reference name based on qubit and memory slot index.
2180
- qubits_repr = "&".join(map(str, qubits))
2181
- mslots_repr = "&".join((str(r.index) for r in registers))
2182
- _active_builder().call_subroutine(measure_sched, name=f"measure_{qubits_repr}..{mslots_repr}")
2183
-
2184
- if len(qubits) == 1:
2185
- return registers[0]
2186
- else:
2187
- return registers
2188
-
2189
-
2190
- @deprecate_pulse_func
2191
- def measure_all() -> list[chans.MemorySlot]:
2192
- r"""Measure all qubits within the currently active builder context.
2193
-
2194
- A simple macro function to measure all of the qubits in the device at the
2195
- same time. This is useful for handling device ``meas_map`` and single
2196
- measurement constraints.
2197
-
2198
- Examples:
2199
-
2200
- .. code-block::
2201
-
2202
- from qiskit import pulse
2203
- from qiskit.providers.fake_provider import FakeOpenPulse2Q
2204
-
2205
- backend = FakeOpenPulse2Q()
2206
-
2207
- with pulse.build(backend) as pulse_prog:
2208
- # Measure all qubits and return associated registers.
2209
- regs = pulse.measure_all()
2210
-
2211
- .. note::
2212
- Requires the active builder context to have a backend set.
2213
-
2214
- Returns:
2215
- The ``register``\s the qubit measurement results will be stored in.
2216
- """
2217
- backend = active_backend()
2218
- qubits = range(num_qubits())
2219
- registers = [chans.MemorySlot(qubit) for qubit in qubits]
2220
-
2221
- measure_sched = macros.measure(
2222
- qubits=qubits,
2223
- backend=backend,
2224
- qubit_mem_slots={qubit: qubit for qubit in qubits},
2225
- )
2226
-
2227
- # note this is not a subroutine.
2228
- # just a macro to automate combination of stimulus and acquisition.
2229
- _active_builder().call_subroutine(measure_sched, name="measure_all")
2230
-
2231
- return registers
2232
-
2233
-
2234
- @deprecate_pulse_func
2235
- def delay_qubits(duration: int, *qubits: int):
2236
- r"""Insert delays on all the :class:`channels.Channel`\s that correspond
2237
- to the input ``qubits`` at the same time.
2238
-
2239
- Examples:
2240
-
2241
- .. code-block::
2242
-
2243
- from qiskit import pulse
2244
- from qiskit.providers.fake_provider import FakeOpenPulse3Q
2245
-
2246
- backend = FakeOpenPulse3Q()
2247
-
2248
- with pulse.build(backend) as pulse_prog:
2249
- # Delay for 100 cycles on qubits 0, 1 and 2.
2250
- regs = pulse.delay_qubits(100, 0, 1, 2)
2251
-
2252
- .. note:: Requires the active builder context to have a backend set.
2253
-
2254
- Args:
2255
- duration: Duration to delay for.
2256
- qubits: Physical qubits to delay on. Delays will be inserted based on
2257
- the channels returned by :func:`pulse.qubit_channels`.
2258
- """
2259
- qubit_chans = set(itertools.chain.from_iterable(qubit_channels(qubit) for qubit in qubits))
2260
- with align_left():
2261
- for chan in qubit_chans:
2262
- delay(duration, chan)