qiskit 2.0.3__cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.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 (690) hide show
  1. qiskit/VERSION.txt +1 -0
  2. qiskit/__init__.py +141 -0
  3. qiskit/_accelerate.abi3.so +0 -0
  4. qiskit/_numpy_compat.py +73 -0
  5. qiskit/circuit/__init__.py +1343 -0
  6. qiskit/circuit/_add_control.py +312 -0
  7. qiskit/circuit/_classical_resource_map.py +150 -0
  8. qiskit/circuit/_standard_gates_commutations.py +3849 -0
  9. qiskit/circuit/_utils.py +167 -0
  10. qiskit/circuit/annotated_operation.py +279 -0
  11. qiskit/circuit/barrier.py +46 -0
  12. qiskit/circuit/classical/__init__.py +41 -0
  13. qiskit/circuit/classical/expr/__init__.py +266 -0
  14. qiskit/circuit/classical/expr/constructors.py +764 -0
  15. qiskit/circuit/classical/expr/expr.py +498 -0
  16. qiskit/circuit/classical/expr/visitors.py +375 -0
  17. qiskit/circuit/classical/types/__init__.py +113 -0
  18. qiskit/circuit/classical/types/ordering.py +229 -0
  19. qiskit/circuit/classical/types/types.py +153 -0
  20. qiskit/circuit/commutation_checker.py +133 -0
  21. qiskit/circuit/commutation_library.py +20 -0
  22. qiskit/circuit/controlflow/__init__.py +59 -0
  23. qiskit/circuit/controlflow/_builder_utils.py +211 -0
  24. qiskit/circuit/controlflow/box.py +163 -0
  25. qiskit/circuit/controlflow/break_loop.py +56 -0
  26. qiskit/circuit/controlflow/builder.py +791 -0
  27. qiskit/circuit/controlflow/continue_loop.py +56 -0
  28. qiskit/circuit/controlflow/control_flow.py +94 -0
  29. qiskit/circuit/controlflow/for_loop.py +218 -0
  30. qiskit/circuit/controlflow/if_else.py +498 -0
  31. qiskit/circuit/controlflow/switch_case.py +411 -0
  32. qiskit/circuit/controlflow/while_loop.py +166 -0
  33. qiskit/circuit/controlledgate.py +274 -0
  34. qiskit/circuit/delay.py +157 -0
  35. qiskit/circuit/duration.py +80 -0
  36. qiskit/circuit/equivalence.py +94 -0
  37. qiskit/circuit/equivalence_library.py +18 -0
  38. qiskit/circuit/exceptions.py +19 -0
  39. qiskit/circuit/gate.py +261 -0
  40. qiskit/circuit/instruction.py +564 -0
  41. qiskit/circuit/instructionset.py +132 -0
  42. qiskit/circuit/library/__init__.py +984 -0
  43. qiskit/circuit/library/arithmetic/__init__.py +40 -0
  44. qiskit/circuit/library/arithmetic/adders/__init__.py +18 -0
  45. qiskit/circuit/library/arithmetic/adders/adder.py +235 -0
  46. qiskit/circuit/library/arithmetic/adders/cdkm_ripple_carry_adder.py +123 -0
  47. qiskit/circuit/library/arithmetic/adders/draper_qft_adder.py +129 -0
  48. qiskit/circuit/library/arithmetic/adders/vbe_ripple_carry_adder.py +95 -0
  49. qiskit/circuit/library/arithmetic/exact_reciprocal.py +131 -0
  50. qiskit/circuit/library/arithmetic/functional_pauli_rotations.py +114 -0
  51. qiskit/circuit/library/arithmetic/integer_comparator.py +200 -0
  52. qiskit/circuit/library/arithmetic/linear_amplitude_function.py +363 -0
  53. qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +243 -0
  54. qiskit/circuit/library/arithmetic/multipliers/__init__.py +17 -0
  55. qiskit/circuit/library/arithmetic/multipliers/hrs_cumulative_multiplier.py +145 -0
  56. qiskit/circuit/library/arithmetic/multipliers/multiplier.py +201 -0
  57. qiskit/circuit/library/arithmetic/multipliers/rg_qft_multiplier.py +108 -0
  58. qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +502 -0
  59. qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +387 -0
  60. qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +493 -0
  61. qiskit/circuit/library/arithmetic/polynomial_pauli_rotations.py +389 -0
  62. qiskit/circuit/library/arithmetic/quadratic_form.py +364 -0
  63. qiskit/circuit/library/arithmetic/weighted_adder.py +409 -0
  64. qiskit/circuit/library/basis_change/__init__.py +15 -0
  65. qiskit/circuit/library/basis_change/qft.py +316 -0
  66. qiskit/circuit/library/bit_flip_oracle.py +130 -0
  67. qiskit/circuit/library/blueprintcircuit.py +316 -0
  68. qiskit/circuit/library/boolean_logic/__init__.py +18 -0
  69. qiskit/circuit/library/boolean_logic/inner_product.py +157 -0
  70. qiskit/circuit/library/boolean_logic/quantum_and.py +204 -0
  71. qiskit/circuit/library/boolean_logic/quantum_or.py +206 -0
  72. qiskit/circuit/library/boolean_logic/quantum_xor.py +167 -0
  73. qiskit/circuit/library/data_preparation/__init__.py +57 -0
  74. qiskit/circuit/library/data_preparation/_z_feature_map.py +115 -0
  75. qiskit/circuit/library/data_preparation/_zz_feature_map.py +150 -0
  76. qiskit/circuit/library/data_preparation/initializer.py +107 -0
  77. qiskit/circuit/library/data_preparation/pauli_feature_map.py +656 -0
  78. qiskit/circuit/library/data_preparation/state_preparation.py +336 -0
  79. qiskit/circuit/library/fourier_checking.py +160 -0
  80. qiskit/circuit/library/generalized_gates/__init__.py +30 -0
  81. qiskit/circuit/library/generalized_gates/diagonal.py +159 -0
  82. qiskit/circuit/library/generalized_gates/gms.py +175 -0
  83. qiskit/circuit/library/generalized_gates/gr.py +219 -0
  84. qiskit/circuit/library/generalized_gates/isometry.py +370 -0
  85. qiskit/circuit/library/generalized_gates/linear_function.py +318 -0
  86. qiskit/circuit/library/generalized_gates/mcg_up_to_diagonal.py +143 -0
  87. qiskit/circuit/library/generalized_gates/mcmt.py +316 -0
  88. qiskit/circuit/library/generalized_gates/pauli.py +84 -0
  89. qiskit/circuit/library/generalized_gates/permutation.py +198 -0
  90. qiskit/circuit/library/generalized_gates/rv.py +96 -0
  91. qiskit/circuit/library/generalized_gates/uc.py +303 -0
  92. qiskit/circuit/library/generalized_gates/uc_pauli_rot.py +164 -0
  93. qiskit/circuit/library/generalized_gates/ucrx.py +32 -0
  94. qiskit/circuit/library/generalized_gates/ucry.py +32 -0
  95. qiskit/circuit/library/generalized_gates/ucrz.py +32 -0
  96. qiskit/circuit/library/generalized_gates/unitary.py +217 -0
  97. qiskit/circuit/library/graph_state.py +172 -0
  98. qiskit/circuit/library/grover_operator.py +583 -0
  99. qiskit/circuit/library/hamiltonian_gate.py +142 -0
  100. qiskit/circuit/library/hidden_linear_function.py +163 -0
  101. qiskit/circuit/library/iqp.py +180 -0
  102. qiskit/circuit/library/n_local/__init__.py +45 -0
  103. qiskit/circuit/library/n_local/efficient_su2.py +282 -0
  104. qiskit/circuit/library/n_local/evolved_operator_ansatz.py +520 -0
  105. qiskit/circuit/library/n_local/excitation_preserving.py +303 -0
  106. qiskit/circuit/library/n_local/n_local.py +1477 -0
  107. qiskit/circuit/library/n_local/pauli_two_design.py +246 -0
  108. qiskit/circuit/library/n_local/qaoa_ansatz.py +367 -0
  109. qiskit/circuit/library/n_local/real_amplitudes.py +312 -0
  110. qiskit/circuit/library/n_local/two_local.py +289 -0
  111. qiskit/circuit/library/overlap.py +183 -0
  112. qiskit/circuit/library/pauli_evolution.py +201 -0
  113. qiskit/circuit/library/phase_estimation.py +177 -0
  114. qiskit/circuit/library/phase_oracle.py +239 -0
  115. qiskit/circuit/library/quantum_volume.py +180 -0
  116. qiskit/circuit/library/standard_gates/__init__.py +141 -0
  117. qiskit/circuit/library/standard_gates/dcx.py +77 -0
  118. qiskit/circuit/library/standard_gates/ecr.py +129 -0
  119. qiskit/circuit/library/standard_gates/equivalence_library.py +1800 -0
  120. qiskit/circuit/library/standard_gates/global_phase.py +84 -0
  121. qiskit/circuit/library/standard_gates/h.py +253 -0
  122. qiskit/circuit/library/standard_gates/i.py +76 -0
  123. qiskit/circuit/library/standard_gates/iswap.py +133 -0
  124. qiskit/circuit/library/standard_gates/p.py +422 -0
  125. qiskit/circuit/library/standard_gates/r.py +114 -0
  126. qiskit/circuit/library/standard_gates/rx.py +293 -0
  127. qiskit/circuit/library/standard_gates/rxx.py +180 -0
  128. qiskit/circuit/library/standard_gates/ry.py +286 -0
  129. qiskit/circuit/library/standard_gates/ryy.py +180 -0
  130. qiskit/circuit/library/standard_gates/rz.py +307 -0
  131. qiskit/circuit/library/standard_gates/rzx.py +226 -0
  132. qiskit/circuit/library/standard_gates/rzz.py +193 -0
  133. qiskit/circuit/library/standard_gates/s.py +419 -0
  134. qiskit/circuit/library/standard_gates/swap.py +281 -0
  135. qiskit/circuit/library/standard_gates/sx.py +310 -0
  136. qiskit/circuit/library/standard_gates/t.py +178 -0
  137. qiskit/circuit/library/standard_gates/u.py +395 -0
  138. qiskit/circuit/library/standard_gates/u1.py +490 -0
  139. qiskit/circuit/library/standard_gates/u2.py +145 -0
  140. qiskit/circuit/library/standard_gates/u3.py +428 -0
  141. qiskit/circuit/library/standard_gates/x.py +1481 -0
  142. qiskit/circuit/library/standard_gates/xx_minus_yy.py +202 -0
  143. qiskit/circuit/library/standard_gates/xx_plus_yy.py +236 -0
  144. qiskit/circuit/library/standard_gates/y.py +257 -0
  145. qiskit/circuit/library/standard_gates/z.py +338 -0
  146. qiskit/circuit/library/templates/__init__.py +92 -0
  147. qiskit/circuit/library/templates/clifford/__init__.py +33 -0
  148. qiskit/circuit/library/templates/clifford/clifford_2_1.py +34 -0
  149. qiskit/circuit/library/templates/clifford/clifford_2_2.py +35 -0
  150. qiskit/circuit/library/templates/clifford/clifford_2_3.py +34 -0
  151. qiskit/circuit/library/templates/clifford/clifford_2_4.py +34 -0
  152. qiskit/circuit/library/templates/clifford/clifford_3_1.py +35 -0
  153. qiskit/circuit/library/templates/clifford/clifford_4_1.py +38 -0
  154. qiskit/circuit/library/templates/clifford/clifford_4_2.py +37 -0
  155. qiskit/circuit/library/templates/clifford/clifford_4_3.py +38 -0
  156. qiskit/circuit/library/templates/clifford/clifford_4_4.py +37 -0
  157. qiskit/circuit/library/templates/clifford/clifford_5_1.py +40 -0
  158. qiskit/circuit/library/templates/clifford/clifford_6_1.py +40 -0
  159. qiskit/circuit/library/templates/clifford/clifford_6_2.py +40 -0
  160. qiskit/circuit/library/templates/clifford/clifford_6_3.py +40 -0
  161. qiskit/circuit/library/templates/clifford/clifford_6_4.py +38 -0
  162. qiskit/circuit/library/templates/clifford/clifford_6_5.py +40 -0
  163. qiskit/circuit/library/templates/clifford/clifford_8_1.py +42 -0
  164. qiskit/circuit/library/templates/clifford/clifford_8_2.py +42 -0
  165. qiskit/circuit/library/templates/clifford/clifford_8_3.py +41 -0
  166. qiskit/circuit/library/templates/nct/__init__.py +67 -0
  167. qiskit/circuit/library/templates/nct/template_nct_2a_1.py +34 -0
  168. qiskit/circuit/library/templates/nct/template_nct_2a_2.py +35 -0
  169. qiskit/circuit/library/templates/nct/template_nct_2a_3.py +37 -0
  170. qiskit/circuit/library/templates/nct/template_nct_4a_1.py +43 -0
  171. qiskit/circuit/library/templates/nct/template_nct_4a_2.py +41 -0
  172. qiskit/circuit/library/templates/nct/template_nct_4a_3.py +39 -0
  173. qiskit/circuit/library/templates/nct/template_nct_4b_1.py +41 -0
  174. qiskit/circuit/library/templates/nct/template_nct_4b_2.py +39 -0
  175. qiskit/circuit/library/templates/nct/template_nct_5a_1.py +40 -0
  176. qiskit/circuit/library/templates/nct/template_nct_5a_2.py +40 -0
  177. qiskit/circuit/library/templates/nct/template_nct_5a_3.py +40 -0
  178. qiskit/circuit/library/templates/nct/template_nct_5a_4.py +39 -0
  179. qiskit/circuit/library/templates/nct/template_nct_6a_1.py +40 -0
  180. qiskit/circuit/library/templates/nct/template_nct_6a_2.py +41 -0
  181. qiskit/circuit/library/templates/nct/template_nct_6a_3.py +41 -0
  182. qiskit/circuit/library/templates/nct/template_nct_6a_4.py +41 -0
  183. qiskit/circuit/library/templates/nct/template_nct_6b_1.py +41 -0
  184. qiskit/circuit/library/templates/nct/template_nct_6b_2.py +41 -0
  185. qiskit/circuit/library/templates/nct/template_nct_6c_1.py +41 -0
  186. qiskit/circuit/library/templates/nct/template_nct_7a_1.py +43 -0
  187. qiskit/circuit/library/templates/nct/template_nct_7b_1.py +43 -0
  188. qiskit/circuit/library/templates/nct/template_nct_7c_1.py +43 -0
  189. qiskit/circuit/library/templates/nct/template_nct_7d_1.py +43 -0
  190. qiskit/circuit/library/templates/nct/template_nct_7e_1.py +43 -0
  191. qiskit/circuit/library/templates/nct/template_nct_9a_1.py +45 -0
  192. qiskit/circuit/library/templates/nct/template_nct_9c_1.py +43 -0
  193. qiskit/circuit/library/templates/nct/template_nct_9c_10.py +44 -0
  194. qiskit/circuit/library/templates/nct/template_nct_9c_11.py +44 -0
  195. qiskit/circuit/library/templates/nct/template_nct_9c_12.py +44 -0
  196. qiskit/circuit/library/templates/nct/template_nct_9c_2.py +44 -0
  197. qiskit/circuit/library/templates/nct/template_nct_9c_3.py +44 -0
  198. qiskit/circuit/library/templates/nct/template_nct_9c_4.py +44 -0
  199. qiskit/circuit/library/templates/nct/template_nct_9c_5.py +44 -0
  200. qiskit/circuit/library/templates/nct/template_nct_9c_6.py +44 -0
  201. qiskit/circuit/library/templates/nct/template_nct_9c_7.py +44 -0
  202. qiskit/circuit/library/templates/nct/template_nct_9c_8.py +44 -0
  203. qiskit/circuit/library/templates/nct/template_nct_9c_9.py +44 -0
  204. qiskit/circuit/library/templates/nct/template_nct_9d_1.py +43 -0
  205. qiskit/circuit/library/templates/nct/template_nct_9d_10.py +44 -0
  206. qiskit/circuit/library/templates/nct/template_nct_9d_2.py +44 -0
  207. qiskit/circuit/library/templates/nct/template_nct_9d_3.py +44 -0
  208. qiskit/circuit/library/templates/nct/template_nct_9d_4.py +44 -0
  209. qiskit/circuit/library/templates/nct/template_nct_9d_5.py +44 -0
  210. qiskit/circuit/library/templates/nct/template_nct_9d_6.py +44 -0
  211. qiskit/circuit/library/templates/nct/template_nct_9d_7.py +44 -0
  212. qiskit/circuit/library/templates/nct/template_nct_9d_8.py +44 -0
  213. qiskit/circuit/library/templates/nct/template_nct_9d_9.py +44 -0
  214. qiskit/circuit/library/templates/rzx/__init__.py +25 -0
  215. qiskit/circuit/library/templates/rzx/rzx_cy.py +47 -0
  216. qiskit/circuit/library/templates/rzx/rzx_xz.py +54 -0
  217. qiskit/circuit/library/templates/rzx/rzx_yz.py +45 -0
  218. qiskit/circuit/library/templates/rzx/rzx_zz1.py +69 -0
  219. qiskit/circuit/library/templates/rzx/rzx_zz2.py +59 -0
  220. qiskit/circuit/library/templates/rzx/rzx_zz3.py +59 -0
  221. qiskit/circuit/measure.py +53 -0
  222. qiskit/circuit/operation.py +68 -0
  223. qiskit/circuit/parameter.py +179 -0
  224. qiskit/circuit/parameterexpression.py +703 -0
  225. qiskit/circuit/parametertable.py +119 -0
  226. qiskit/circuit/parametervector.py +140 -0
  227. qiskit/circuit/quantumcircuit.py +7540 -0
  228. qiskit/circuit/quantumcircuitdata.py +136 -0
  229. qiskit/circuit/random/__init__.py +15 -0
  230. qiskit/circuit/random/utils.py +366 -0
  231. qiskit/circuit/reset.py +37 -0
  232. qiskit/circuit/singleton.py +600 -0
  233. qiskit/circuit/store.py +89 -0
  234. qiskit/circuit/tools/__init__.py +16 -0
  235. qiskit/circuit/tools/pi_check.py +193 -0
  236. qiskit/circuit/twirling.py +145 -0
  237. qiskit/compiler/__init__.py +27 -0
  238. qiskit/compiler/transpiler.py +375 -0
  239. qiskit/converters/__init__.py +74 -0
  240. qiskit/converters/circuit_to_dag.py +80 -0
  241. qiskit/converters/circuit_to_dagdependency.py +49 -0
  242. qiskit/converters/circuit_to_dagdependency_v2.py +46 -0
  243. qiskit/converters/circuit_to_gate.py +107 -0
  244. qiskit/converters/circuit_to_instruction.py +142 -0
  245. qiskit/converters/dag_to_circuit.py +79 -0
  246. qiskit/converters/dag_to_dagdependency.py +54 -0
  247. qiskit/converters/dag_to_dagdependency_v2.py +43 -0
  248. qiskit/converters/dagdependency_to_circuit.py +40 -0
  249. qiskit/converters/dagdependency_to_dag.py +48 -0
  250. qiskit/dagcircuit/__init__.py +55 -0
  251. qiskit/dagcircuit/collect_blocks.py +407 -0
  252. qiskit/dagcircuit/dagcircuit.py +24 -0
  253. qiskit/dagcircuit/dagdependency.py +612 -0
  254. qiskit/dagcircuit/dagdependency_v2.py +566 -0
  255. qiskit/dagcircuit/dagdepnode.py +160 -0
  256. qiskit/dagcircuit/dagnode.py +188 -0
  257. qiskit/dagcircuit/exceptions.py +42 -0
  258. qiskit/exceptions.py +153 -0
  259. qiskit/passmanager/__init__.py +258 -0
  260. qiskit/passmanager/base_tasks.py +230 -0
  261. qiskit/passmanager/compilation_status.py +74 -0
  262. qiskit/passmanager/exceptions.py +19 -0
  263. qiskit/passmanager/flow_controllers.py +116 -0
  264. qiskit/passmanager/passmanager.py +353 -0
  265. qiskit/primitives/__init__.py +490 -0
  266. qiskit/primitives/backend_estimator_v2.py +530 -0
  267. qiskit/primitives/backend_sampler_v2.py +339 -0
  268. qiskit/primitives/base/__init__.py +20 -0
  269. qiskit/primitives/base/base_estimator.py +247 -0
  270. qiskit/primitives/base/base_primitive_job.py +78 -0
  271. qiskit/primitives/base/base_primitive_v1.py +45 -0
  272. qiskit/primitives/base/base_result_v1.py +65 -0
  273. qiskit/primitives/base/base_sampler.py +196 -0
  274. qiskit/primitives/base/estimator_result_v1.py +46 -0
  275. qiskit/primitives/base/sampler_result_v1.py +45 -0
  276. qiskit/primitives/base/validation_v1.py +250 -0
  277. qiskit/primitives/containers/__init__.py +26 -0
  278. qiskit/primitives/containers/bindings_array.py +391 -0
  279. qiskit/primitives/containers/bit_array.py +764 -0
  280. qiskit/primitives/containers/data_bin.py +175 -0
  281. qiskit/primitives/containers/estimator_pub.py +222 -0
  282. qiskit/primitives/containers/object_array.py +94 -0
  283. qiskit/primitives/containers/observables_array.py +296 -0
  284. qiskit/primitives/containers/primitive_result.py +53 -0
  285. qiskit/primitives/containers/pub_result.py +51 -0
  286. qiskit/primitives/containers/sampler_pub.py +193 -0
  287. qiskit/primitives/containers/sampler_pub_result.py +74 -0
  288. qiskit/primitives/containers/shape.py +129 -0
  289. qiskit/primitives/primitive_job.py +81 -0
  290. qiskit/primitives/statevector_estimator.py +175 -0
  291. qiskit/primitives/statevector_sampler.py +290 -0
  292. qiskit/primitives/utils.py +72 -0
  293. qiskit/providers/__init__.py +677 -0
  294. qiskit/providers/backend.py +364 -0
  295. qiskit/providers/basic_provider/__init__.py +47 -0
  296. qiskit/providers/basic_provider/basic_provider.py +121 -0
  297. qiskit/providers/basic_provider/basic_provider_job.py +65 -0
  298. qiskit/providers/basic_provider/basic_provider_tools.py +218 -0
  299. qiskit/providers/basic_provider/basic_simulator.py +693 -0
  300. qiskit/providers/basic_provider/exceptions.py +30 -0
  301. qiskit/providers/exceptions.py +33 -0
  302. qiskit/providers/fake_provider/__init__.py +69 -0
  303. qiskit/providers/fake_provider/generic_backend_v2.py +374 -0
  304. qiskit/providers/fake_provider/utils/__init__.py +15 -0
  305. qiskit/providers/job.py +147 -0
  306. qiskit/providers/jobstatus.py +30 -0
  307. qiskit/providers/options.py +273 -0
  308. qiskit/providers/providerutils.py +110 -0
  309. qiskit/qasm/libs/dummy/stdgates.inc +75 -0
  310. qiskit/qasm/libs/qelib1.inc +266 -0
  311. qiskit/qasm/libs/stdgates.inc +82 -0
  312. qiskit/qasm2/__init__.py +669 -0
  313. qiskit/qasm2/exceptions.py +27 -0
  314. qiskit/qasm2/export.py +364 -0
  315. qiskit/qasm2/parse.py +438 -0
  316. qiskit/qasm3/__init__.py +372 -0
  317. qiskit/qasm3/ast.py +782 -0
  318. qiskit/qasm3/exceptions.py +27 -0
  319. qiskit/qasm3/experimental.py +70 -0
  320. qiskit/qasm3/exporter.py +1340 -0
  321. qiskit/qasm3/printer.py +608 -0
  322. qiskit/qpy/__init__.py +1965 -0
  323. qiskit/qpy/binary_io/__init__.py +35 -0
  324. qiskit/qpy/binary_io/circuits.py +1455 -0
  325. qiskit/qpy/binary_io/parse_sympy_repr.py +121 -0
  326. qiskit/qpy/binary_io/schedules.py +308 -0
  327. qiskit/qpy/binary_io/value.py +1165 -0
  328. qiskit/qpy/common.py +353 -0
  329. qiskit/qpy/exceptions.py +53 -0
  330. qiskit/qpy/formats.py +442 -0
  331. qiskit/qpy/interface.py +344 -0
  332. qiskit/qpy/type_keys.py +409 -0
  333. qiskit/quantum_info/__init__.py +162 -0
  334. qiskit/quantum_info/analysis/__init__.py +17 -0
  335. qiskit/quantum_info/analysis/average.py +47 -0
  336. qiskit/quantum_info/analysis/distance.py +104 -0
  337. qiskit/quantum_info/analysis/make_observable.py +44 -0
  338. qiskit/quantum_info/analysis/z2_symmetries.py +484 -0
  339. qiskit/quantum_info/operators/__init__.py +28 -0
  340. qiskit/quantum_info/operators/base_operator.py +145 -0
  341. qiskit/quantum_info/operators/channel/__init__.py +29 -0
  342. qiskit/quantum_info/operators/channel/chi.py +191 -0
  343. qiskit/quantum_info/operators/channel/choi.py +218 -0
  344. qiskit/quantum_info/operators/channel/kraus.py +337 -0
  345. qiskit/quantum_info/operators/channel/ptm.py +204 -0
  346. qiskit/quantum_info/operators/channel/quantum_channel.py +348 -0
  347. qiskit/quantum_info/operators/channel/stinespring.py +296 -0
  348. qiskit/quantum_info/operators/channel/superop.py +373 -0
  349. qiskit/quantum_info/operators/channel/transformations.py +490 -0
  350. qiskit/quantum_info/operators/custom_iterator.py +48 -0
  351. qiskit/quantum_info/operators/dihedral/__init__.py +18 -0
  352. qiskit/quantum_info/operators/dihedral/dihedral.py +511 -0
  353. qiskit/quantum_info/operators/dihedral/dihedral_circuits.py +216 -0
  354. qiskit/quantum_info/operators/dihedral/polynomial.py +313 -0
  355. qiskit/quantum_info/operators/dihedral/random.py +64 -0
  356. qiskit/quantum_info/operators/linear_op.py +25 -0
  357. qiskit/quantum_info/operators/measures.py +418 -0
  358. qiskit/quantum_info/operators/mixins/__init__.py +52 -0
  359. qiskit/quantum_info/operators/mixins/adjoint.py +52 -0
  360. qiskit/quantum_info/operators/mixins/group.py +171 -0
  361. qiskit/quantum_info/operators/mixins/linear.py +84 -0
  362. qiskit/quantum_info/operators/mixins/multiply.py +62 -0
  363. qiskit/quantum_info/operators/mixins/tolerances.py +72 -0
  364. qiskit/quantum_info/operators/op_shape.py +525 -0
  365. qiskit/quantum_info/operators/operator.py +869 -0
  366. qiskit/quantum_info/operators/operator_utils.py +76 -0
  367. qiskit/quantum_info/operators/predicates.py +183 -0
  368. qiskit/quantum_info/operators/random.py +154 -0
  369. qiskit/quantum_info/operators/scalar_op.py +254 -0
  370. qiskit/quantum_info/operators/symplectic/__init__.py +23 -0
  371. qiskit/quantum_info/operators/symplectic/base_pauli.py +719 -0
  372. qiskit/quantum_info/operators/symplectic/clifford.py +1032 -0
  373. qiskit/quantum_info/operators/symplectic/clifford_circuits.py +558 -0
  374. qiskit/quantum_info/operators/symplectic/pauli.py +755 -0
  375. qiskit/quantum_info/operators/symplectic/pauli_list.py +1242 -0
  376. qiskit/quantum_info/operators/symplectic/pauli_utils.py +40 -0
  377. qiskit/quantum_info/operators/symplectic/random.py +117 -0
  378. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +1239 -0
  379. qiskit/quantum_info/operators/utils/__init__.py +20 -0
  380. qiskit/quantum_info/operators/utils/anti_commutator.py +36 -0
  381. qiskit/quantum_info/operators/utils/commutator.py +36 -0
  382. qiskit/quantum_info/operators/utils/double_commutator.py +76 -0
  383. qiskit/quantum_info/quaternion.py +156 -0
  384. qiskit/quantum_info/random.py +26 -0
  385. qiskit/quantum_info/states/__init__.py +28 -0
  386. qiskit/quantum_info/states/densitymatrix.py +857 -0
  387. qiskit/quantum_info/states/measures.py +288 -0
  388. qiskit/quantum_info/states/quantum_state.py +503 -0
  389. qiskit/quantum_info/states/random.py +157 -0
  390. qiskit/quantum_info/states/stabilizerstate.py +805 -0
  391. qiskit/quantum_info/states/statevector.py +977 -0
  392. qiskit/quantum_info/states/utils.py +247 -0
  393. qiskit/result/__init__.py +61 -0
  394. qiskit/result/counts.py +189 -0
  395. qiskit/result/distributions/__init__.py +17 -0
  396. qiskit/result/distributions/probability.py +100 -0
  397. qiskit/result/distributions/quasi.py +154 -0
  398. qiskit/result/exceptions.py +40 -0
  399. qiskit/result/models.py +241 -0
  400. qiskit/result/postprocess.py +239 -0
  401. qiskit/result/result.py +385 -0
  402. qiskit/result/sampled_expval.py +74 -0
  403. qiskit/result/utils.py +294 -0
  404. qiskit/synthesis/__init__.py +240 -0
  405. qiskit/synthesis/arithmetic/__init__.py +18 -0
  406. qiskit/synthesis/arithmetic/adders/__init__.py +17 -0
  407. qiskit/synthesis/arithmetic/adders/cdkm_ripple_carry_adder.py +154 -0
  408. qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +103 -0
  409. qiskit/synthesis/arithmetic/adders/vbe_ripple_carry_adder.py +161 -0
  410. qiskit/synthesis/arithmetic/comparators/__init__.py +16 -0
  411. qiskit/synthesis/arithmetic/comparators/compare_2s.py +112 -0
  412. qiskit/synthesis/arithmetic/comparators/compare_greedy.py +66 -0
  413. qiskit/synthesis/arithmetic/multipliers/__init__.py +16 -0
  414. qiskit/synthesis/arithmetic/multipliers/hrs_cumulative_multiplier.py +103 -0
  415. qiskit/synthesis/arithmetic/multipliers/rg_qft_multiplier.py +100 -0
  416. qiskit/synthesis/arithmetic/weighted_sum.py +155 -0
  417. qiskit/synthesis/boolean/__init__.py +13 -0
  418. qiskit/synthesis/boolean/boolean_expression.py +231 -0
  419. qiskit/synthesis/boolean/boolean_expression_synth.py +124 -0
  420. qiskit/synthesis/boolean/boolean_expression_visitor.py +96 -0
  421. qiskit/synthesis/clifford/__init__.py +19 -0
  422. qiskit/synthesis/clifford/clifford_decompose_ag.py +178 -0
  423. qiskit/synthesis/clifford/clifford_decompose_bm.py +46 -0
  424. qiskit/synthesis/clifford/clifford_decompose_full.py +64 -0
  425. qiskit/synthesis/clifford/clifford_decompose_greedy.py +58 -0
  426. qiskit/synthesis/clifford/clifford_decompose_layers.py +447 -0
  427. qiskit/synthesis/cnotdihedral/__init__.py +17 -0
  428. qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_full.py +52 -0
  429. qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_general.py +141 -0
  430. qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_two_qubits.py +266 -0
  431. qiskit/synthesis/discrete_basis/__init__.py +16 -0
  432. qiskit/synthesis/discrete_basis/commutator_decompose.py +265 -0
  433. qiskit/synthesis/discrete_basis/gate_sequence.py +421 -0
  434. qiskit/synthesis/discrete_basis/generate_basis_approximations.py +165 -0
  435. qiskit/synthesis/discrete_basis/solovay_kitaev.py +240 -0
  436. qiskit/synthesis/evolution/__init__.py +21 -0
  437. qiskit/synthesis/evolution/evolution_synthesis.py +48 -0
  438. qiskit/synthesis/evolution/lie_trotter.py +120 -0
  439. qiskit/synthesis/evolution/matrix_synthesis.py +47 -0
  440. qiskit/synthesis/evolution/pauli_network.py +80 -0
  441. qiskit/synthesis/evolution/product_formula.py +313 -0
  442. qiskit/synthesis/evolution/qdrift.py +130 -0
  443. qiskit/synthesis/evolution/suzuki_trotter.py +224 -0
  444. qiskit/synthesis/linear/__init__.py +26 -0
  445. qiskit/synthesis/linear/cnot_synth.py +69 -0
  446. qiskit/synthesis/linear/linear_circuits_utils.py +128 -0
  447. qiskit/synthesis/linear/linear_depth_lnn.py +61 -0
  448. qiskit/synthesis/linear/linear_matrix_utils.py +27 -0
  449. qiskit/synthesis/linear_phase/__init__.py +17 -0
  450. qiskit/synthesis/linear_phase/cnot_phase_synth.py +206 -0
  451. qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py +61 -0
  452. qiskit/synthesis/linear_phase/cz_depth_lnn.py +58 -0
  453. qiskit/synthesis/multi_controlled/__init__.py +25 -0
  454. qiskit/synthesis/multi_controlled/mcmt_vchain.py +52 -0
  455. qiskit/synthesis/multi_controlled/mcx_synthesis.py +359 -0
  456. qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +206 -0
  457. qiskit/synthesis/one_qubit/__init__.py +15 -0
  458. qiskit/synthesis/one_qubit/one_qubit_decompose.py +288 -0
  459. qiskit/synthesis/permutation/__init__.py +18 -0
  460. qiskit/synthesis/permutation/permutation_full.py +78 -0
  461. qiskit/synthesis/permutation/permutation_lnn.py +54 -0
  462. qiskit/synthesis/permutation/permutation_reverse_lnn.py +93 -0
  463. qiskit/synthesis/permutation/permutation_utils.py +16 -0
  464. qiskit/synthesis/qft/__init__.py +16 -0
  465. qiskit/synthesis/qft/qft_decompose_full.py +97 -0
  466. qiskit/synthesis/qft/qft_decompose_lnn.py +79 -0
  467. qiskit/synthesis/stabilizer/__init__.py +16 -0
  468. qiskit/synthesis/stabilizer/stabilizer_circuit.py +149 -0
  469. qiskit/synthesis/stabilizer/stabilizer_decompose.py +194 -0
  470. qiskit/synthesis/two_qubit/__init__.py +20 -0
  471. qiskit/synthesis/two_qubit/local_invariance.py +63 -0
  472. qiskit/synthesis/two_qubit/two_qubit_decompose.py +583 -0
  473. qiskit/synthesis/two_qubit/xx_decompose/__init__.py +19 -0
  474. qiskit/synthesis/two_qubit/xx_decompose/circuits.py +300 -0
  475. qiskit/synthesis/two_qubit/xx_decompose/decomposer.py +324 -0
  476. qiskit/synthesis/two_qubit/xx_decompose/embodiments.py +163 -0
  477. qiskit/synthesis/two_qubit/xx_decompose/paths.py +412 -0
  478. qiskit/synthesis/two_qubit/xx_decompose/polytopes.py +262 -0
  479. qiskit/synthesis/two_qubit/xx_decompose/utilities.py +40 -0
  480. qiskit/synthesis/two_qubit/xx_decompose/weyl.py +133 -0
  481. qiskit/synthesis/unitary/__init__.py +13 -0
  482. qiskit/synthesis/unitary/aqc/__init__.py +177 -0
  483. qiskit/synthesis/unitary/aqc/approximate.py +116 -0
  484. qiskit/synthesis/unitary/aqc/aqc.py +175 -0
  485. qiskit/synthesis/unitary/aqc/cnot_structures.py +300 -0
  486. qiskit/synthesis/unitary/aqc/cnot_unit_circuit.py +103 -0
  487. qiskit/synthesis/unitary/aqc/cnot_unit_objective.py +299 -0
  488. qiskit/synthesis/unitary/aqc/elementary_operations.py +108 -0
  489. qiskit/synthesis/unitary/aqc/fast_gradient/__init__.py +164 -0
  490. qiskit/synthesis/unitary/aqc/fast_gradient/fast_grad_utils.py +237 -0
  491. qiskit/synthesis/unitary/aqc/fast_gradient/fast_gradient.py +226 -0
  492. qiskit/synthesis/unitary/aqc/fast_gradient/layer.py +370 -0
  493. qiskit/synthesis/unitary/aqc/fast_gradient/pmatrix.py +312 -0
  494. qiskit/synthesis/unitary/qsd.py +288 -0
  495. qiskit/transpiler/__init__.py +1345 -0
  496. qiskit/transpiler/basepasses.py +190 -0
  497. qiskit/transpiler/coupling.py +500 -0
  498. qiskit/transpiler/exceptions.py +59 -0
  499. qiskit/transpiler/instruction_durations.py +281 -0
  500. qiskit/transpiler/layout.py +740 -0
  501. qiskit/transpiler/passes/__init__.py +276 -0
  502. qiskit/transpiler/passes/analysis/__init__.py +23 -0
  503. qiskit/transpiler/passes/analysis/count_ops.py +30 -0
  504. qiskit/transpiler/passes/analysis/count_ops_longest_path.py +26 -0
  505. qiskit/transpiler/passes/analysis/dag_longest_path.py +24 -0
  506. qiskit/transpiler/passes/analysis/depth.py +33 -0
  507. qiskit/transpiler/passes/analysis/num_qubits.py +26 -0
  508. qiskit/transpiler/passes/analysis/num_tensor_factors.py +26 -0
  509. qiskit/transpiler/passes/analysis/resource_estimation.py +41 -0
  510. qiskit/transpiler/passes/analysis/size.py +36 -0
  511. qiskit/transpiler/passes/analysis/width.py +27 -0
  512. qiskit/transpiler/passes/basis/__init__.py +19 -0
  513. qiskit/transpiler/passes/basis/basis_translator.py +138 -0
  514. qiskit/transpiler/passes/basis/decompose.py +137 -0
  515. qiskit/transpiler/passes/basis/translate_parameterized.py +175 -0
  516. qiskit/transpiler/passes/basis/unroll_3q_or_more.py +84 -0
  517. qiskit/transpiler/passes/basis/unroll_custom_definitions.py +110 -0
  518. qiskit/transpiler/passes/layout/__init__.py +26 -0
  519. qiskit/transpiler/passes/layout/_csp_custom_solver.py +65 -0
  520. qiskit/transpiler/passes/layout/apply_layout.py +128 -0
  521. qiskit/transpiler/passes/layout/csp_layout.py +132 -0
  522. qiskit/transpiler/passes/layout/dense_layout.py +177 -0
  523. qiskit/transpiler/passes/layout/disjoint_utils.py +219 -0
  524. qiskit/transpiler/passes/layout/enlarge_with_ancilla.py +49 -0
  525. qiskit/transpiler/passes/layout/full_ancilla_allocation.py +116 -0
  526. qiskit/transpiler/passes/layout/layout_2q_distance.py +77 -0
  527. qiskit/transpiler/passes/layout/sabre_layout.py +506 -0
  528. qiskit/transpiler/passes/layout/sabre_pre_layout.py +225 -0
  529. qiskit/transpiler/passes/layout/set_layout.py +69 -0
  530. qiskit/transpiler/passes/layout/trivial_layout.py +66 -0
  531. qiskit/transpiler/passes/layout/vf2_layout.py +256 -0
  532. qiskit/transpiler/passes/layout/vf2_post_layout.py +376 -0
  533. qiskit/transpiler/passes/layout/vf2_utils.py +235 -0
  534. qiskit/transpiler/passes/optimization/__init__.py +42 -0
  535. qiskit/transpiler/passes/optimization/_gate_extension.py +80 -0
  536. qiskit/transpiler/passes/optimization/collect_1q_runs.py +31 -0
  537. qiskit/transpiler/passes/optimization/collect_2q_blocks.py +35 -0
  538. qiskit/transpiler/passes/optimization/collect_and_collapse.py +117 -0
  539. qiskit/transpiler/passes/optimization/collect_cliffords.py +109 -0
  540. qiskit/transpiler/passes/optimization/collect_linear_functions.py +85 -0
  541. qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +242 -0
  542. qiskit/transpiler/passes/optimization/commutation_analysis.py +44 -0
  543. qiskit/transpiler/passes/optimization/commutative_cancellation.py +82 -0
  544. qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py +140 -0
  545. qiskit/transpiler/passes/optimization/consolidate_blocks.py +176 -0
  546. qiskit/transpiler/passes/optimization/contract_idle_wires_in_control_flow.py +104 -0
  547. qiskit/transpiler/passes/optimization/elide_permutations.py +91 -0
  548. qiskit/transpiler/passes/optimization/hoare_opt.py +420 -0
  549. qiskit/transpiler/passes/optimization/inverse_cancellation.py +95 -0
  550. qiskit/transpiler/passes/optimization/light_cone.py +135 -0
  551. qiskit/transpiler/passes/optimization/optimize_1q_commutation.py +267 -0
  552. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +250 -0
  553. qiskit/transpiler/passes/optimization/optimize_1q_gates.py +384 -0
  554. qiskit/transpiler/passes/optimization/optimize_annotated.py +449 -0
  555. qiskit/transpiler/passes/optimization/optimize_cliffords.py +89 -0
  556. qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py +71 -0
  557. qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py +41 -0
  558. qiskit/transpiler/passes/optimization/remove_final_reset.py +37 -0
  559. qiskit/transpiler/passes/optimization/remove_identity_equiv.py +70 -0
  560. qiskit/transpiler/passes/optimization/remove_reset_in_zero_state.py +37 -0
  561. qiskit/transpiler/passes/optimization/reset_after_measure_simplification.py +50 -0
  562. qiskit/transpiler/passes/optimization/split_2q_unitaries.py +63 -0
  563. qiskit/transpiler/passes/optimization/template_matching/__init__.py +19 -0
  564. qiskit/transpiler/passes/optimization/template_matching/backward_match.py +749 -0
  565. qiskit/transpiler/passes/optimization/template_matching/forward_match.py +452 -0
  566. qiskit/transpiler/passes/optimization/template_matching/maximal_matches.py +77 -0
  567. qiskit/transpiler/passes/optimization/template_matching/template_matching.py +370 -0
  568. qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +639 -0
  569. qiskit/transpiler/passes/optimization/template_optimization.py +158 -0
  570. qiskit/transpiler/passes/routing/__init__.py +21 -0
  571. qiskit/transpiler/passes/routing/algorithms/__init__.py +33 -0
  572. qiskit/transpiler/passes/routing/algorithms/token_swapper.py +105 -0
  573. qiskit/transpiler/passes/routing/algorithms/types.py +46 -0
  574. qiskit/transpiler/passes/routing/algorithms/util.py +103 -0
  575. qiskit/transpiler/passes/routing/basic_swap.py +166 -0
  576. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/__init__.py +25 -0
  577. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_block.py +60 -0
  578. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +397 -0
  579. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/pauli_2q_evolution_commutation.py +145 -0
  580. qiskit/transpiler/passes/routing/commuting_2q_gate_routing/swap_strategy.py +306 -0
  581. qiskit/transpiler/passes/routing/layout_transformation.py +119 -0
  582. qiskit/transpiler/passes/routing/lookahead_swap.py +390 -0
  583. qiskit/transpiler/passes/routing/sabre_swap.py +463 -0
  584. qiskit/transpiler/passes/routing/star_prerouting.py +408 -0
  585. qiskit/transpiler/passes/routing/utils.py +35 -0
  586. qiskit/transpiler/passes/scheduling/__init__.py +21 -0
  587. qiskit/transpiler/passes/scheduling/alignments/__init__.py +79 -0
  588. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +70 -0
  589. qiskit/transpiler/passes/scheduling/alignments/reschedule.py +251 -0
  590. qiskit/transpiler/passes/scheduling/padding/__init__.py +16 -0
  591. qiskit/transpiler/passes/scheduling/padding/base_padding.py +284 -0
  592. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +415 -0
  593. qiskit/transpiler/passes/scheduling/padding/pad_delay.py +90 -0
  594. qiskit/transpiler/passes/scheduling/scheduling/__init__.py +17 -0
  595. qiskit/transpiler/passes/scheduling/scheduling/alap.py +93 -0
  596. qiskit/transpiler/passes/scheduling/scheduling/asap.py +100 -0
  597. qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +88 -0
  598. qiskit/transpiler/passes/scheduling/scheduling/set_io_latency.py +64 -0
  599. qiskit/transpiler/passes/scheduling/time_unit_conversion.py +237 -0
  600. qiskit/transpiler/passes/synthesis/__init__.py +20 -0
  601. qiskit/transpiler/passes/synthesis/aqc_plugin.py +153 -0
  602. qiskit/transpiler/passes/synthesis/default_unitary_synth_plugin.py +653 -0
  603. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +429 -0
  604. qiskit/transpiler/passes/synthesis/hls_plugins.py +1963 -0
  605. qiskit/transpiler/passes/synthesis/linear_functions_synthesis.py +41 -0
  606. qiskit/transpiler/passes/synthesis/plugin.py +738 -0
  607. qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +313 -0
  608. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +425 -0
  609. qiskit/transpiler/passes/utils/__init__.py +32 -0
  610. qiskit/transpiler/passes/utils/barrier_before_final_measurements.py +41 -0
  611. qiskit/transpiler/passes/utils/check_gate_direction.py +60 -0
  612. qiskit/transpiler/passes/utils/check_map.py +78 -0
  613. qiskit/transpiler/passes/utils/contains_instruction.py +45 -0
  614. qiskit/transpiler/passes/utils/control_flow.py +61 -0
  615. qiskit/transpiler/passes/utils/dag_fixed_point.py +36 -0
  616. qiskit/transpiler/passes/utils/error.py +69 -0
  617. qiskit/transpiler/passes/utils/filter_op_nodes.py +66 -0
  618. qiskit/transpiler/passes/utils/fixed_point.py +48 -0
  619. qiskit/transpiler/passes/utils/gate_direction.py +93 -0
  620. qiskit/transpiler/passes/utils/gates_basis.py +51 -0
  621. qiskit/transpiler/passes/utils/merge_adjacent_barriers.py +163 -0
  622. qiskit/transpiler/passes/utils/minimum_point.py +118 -0
  623. qiskit/transpiler/passes/utils/remove_barriers.py +50 -0
  624. qiskit/transpiler/passes/utils/remove_final_measurements.py +121 -0
  625. qiskit/transpiler/passes/utils/unroll_forloops.py +81 -0
  626. qiskit/transpiler/passmanager.py +503 -0
  627. qiskit/transpiler/passmanager_config.py +151 -0
  628. qiskit/transpiler/preset_passmanagers/__init__.py +93 -0
  629. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +993 -0
  630. qiskit/transpiler/preset_passmanagers/common.py +672 -0
  631. qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +437 -0
  632. qiskit/transpiler/preset_passmanagers/level0.py +104 -0
  633. qiskit/transpiler/preset_passmanagers/level1.py +108 -0
  634. qiskit/transpiler/preset_passmanagers/level2.py +109 -0
  635. qiskit/transpiler/preset_passmanagers/level3.py +110 -0
  636. qiskit/transpiler/preset_passmanagers/plugin.py +346 -0
  637. qiskit/transpiler/target.py +905 -0
  638. qiskit/transpiler/timing_constraints.py +59 -0
  639. qiskit/user_config.py +266 -0
  640. qiskit/utils/__init__.py +90 -0
  641. qiskit/utils/classtools.py +146 -0
  642. qiskit/utils/deprecation.py +382 -0
  643. qiskit/utils/lazy_tester.py +363 -0
  644. qiskit/utils/optionals.py +354 -0
  645. qiskit/utils/parallel.py +318 -0
  646. qiskit/utils/units.py +146 -0
  647. qiskit/version.py +84 -0
  648. qiskit/visualization/__init__.py +290 -0
  649. qiskit/visualization/array.py +207 -0
  650. qiskit/visualization/bloch.py +778 -0
  651. qiskit/visualization/circuit/__init__.py +15 -0
  652. qiskit/visualization/circuit/_utils.py +675 -0
  653. qiskit/visualization/circuit/circuit_visualization.py +735 -0
  654. qiskit/visualization/circuit/latex.py +661 -0
  655. qiskit/visualization/circuit/matplotlib.py +2019 -0
  656. qiskit/visualization/circuit/qcstyle.py +278 -0
  657. qiskit/visualization/circuit/styles/__init__.py +13 -0
  658. qiskit/visualization/circuit/styles/bw.json +202 -0
  659. qiskit/visualization/circuit/styles/clifford.json +202 -0
  660. qiskit/visualization/circuit/styles/iqp-dark.json +214 -0
  661. qiskit/visualization/circuit/styles/iqp.json +214 -0
  662. qiskit/visualization/circuit/styles/textbook.json +202 -0
  663. qiskit/visualization/circuit/text.py +1849 -0
  664. qiskit/visualization/circuit_visualization.py +19 -0
  665. qiskit/visualization/counts_visualization.py +487 -0
  666. qiskit/visualization/dag_visualization.py +318 -0
  667. qiskit/visualization/exceptions.py +21 -0
  668. qiskit/visualization/gate_map.py +1424 -0
  669. qiskit/visualization/library.py +40 -0
  670. qiskit/visualization/pass_manager_visualization.py +312 -0
  671. qiskit/visualization/state_visualization.py +1546 -0
  672. qiskit/visualization/timeline/__init__.py +21 -0
  673. qiskit/visualization/timeline/core.py +495 -0
  674. qiskit/visualization/timeline/drawings.py +260 -0
  675. qiskit/visualization/timeline/generators.py +506 -0
  676. qiskit/visualization/timeline/interface.py +444 -0
  677. qiskit/visualization/timeline/layouts.py +115 -0
  678. qiskit/visualization/timeline/plotters/__init__.py +16 -0
  679. qiskit/visualization/timeline/plotters/base_plotter.py +58 -0
  680. qiskit/visualization/timeline/plotters/matplotlib.py +195 -0
  681. qiskit/visualization/timeline/stylesheet.py +301 -0
  682. qiskit/visualization/timeline/types.py +148 -0
  683. qiskit/visualization/transition_visualization.py +369 -0
  684. qiskit/visualization/utils.py +49 -0
  685. qiskit-2.0.3.dist-info/METADATA +220 -0
  686. qiskit-2.0.3.dist-info/RECORD +690 -0
  687. qiskit-2.0.3.dist-info/WHEEL +6 -0
  688. qiskit-2.0.3.dist-info/entry_points.txt +82 -0
  689. qiskit-2.0.3.dist-info/licenses/LICENSE.txt +203 -0
  690. qiskit-2.0.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2019 @@
1
+ # This code is part of Qiskit.
2
+ #
3
+ # (C) Copyright IBM 2017, 2018.
4
+ #
5
+ # This code is licensed under the Apache License, Version 2.0. You may
6
+ # obtain a copy of this license in the LICENSE.txt file in the root directory
7
+ # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8
+ #
9
+ # Any modifications or derivative works of this code must retain this
10
+ # copyright notice, and modified files need to carry a notice indicating
11
+ # that they have been altered from the originals.
12
+
13
+ # pylint: disable=invalid-name,inconsistent-return-statements
14
+
15
+ """mpl circuit visualization backend."""
16
+
17
+ import collections
18
+ import itertools
19
+ import re
20
+ from io import StringIO
21
+
22
+ import numpy as np
23
+
24
+ from qiskit.circuit import (
25
+ QuantumCircuit,
26
+ Qubit,
27
+ Clbit,
28
+ ClassicalRegister,
29
+ ControlledGate,
30
+ Measure,
31
+ ControlFlowOp,
32
+ BoxOp,
33
+ WhileLoopOp,
34
+ IfElseOp,
35
+ ForLoopOp,
36
+ SwitchCaseOp,
37
+ CircuitError,
38
+ )
39
+ from qiskit.circuit.controlflow import condition_resources
40
+ from qiskit.circuit.classical import expr
41
+ from qiskit.circuit.annotated_operation import _canonicalize_modifiers, ControlModifier
42
+ from qiskit.circuit.library import Initialize
43
+ from qiskit.circuit.library.standard_gates import (
44
+ SwapGate,
45
+ RZZGate,
46
+ U1Gate,
47
+ PhaseGate,
48
+ XGate,
49
+ ZGate,
50
+ )
51
+ from qiskit.qasm3 import ast
52
+ from qiskit.qasm3.exporter import _ExprBuilder
53
+ from qiskit.qasm3.printer import BasicPrinter
54
+
55
+ from qiskit.circuit.tools.pi_check import pi_check
56
+ from qiskit.utils import optionals as _optionals
57
+
58
+ from .qcstyle import load_style
59
+ from ._utils import (
60
+ get_gate_ctrl_text,
61
+ get_param_str,
62
+ get_wire_map,
63
+ get_bit_register,
64
+ get_bit_reg_index,
65
+ get_wire_label,
66
+ get_condition_label_val,
67
+ _get_layered_instructions,
68
+ )
69
+ from ..utils import matplotlib_close_if_inline
70
+
71
+ # Default gate width and height
72
+ WID = 0.65
73
+ HIG = 0.65
74
+
75
+ # Z dimension order for different drawing types
76
+ PORDER_REGLINE = 1
77
+ PORDER_FLOW = 3
78
+ PORDER_MASK = 4
79
+ PORDER_LINE = 6
80
+ PORDER_LINE_PLUS = 7
81
+ PORDER_BARRIER = 8
82
+ PORDER_GATE = 10
83
+ PORDER_GATE_PLUS = 11
84
+ PORDER_TEXT = 13
85
+
86
+ INFINITE_FOLD = 10000000
87
+
88
+
89
+ @_optionals.HAS_MATPLOTLIB.require_in_instance
90
+ @_optionals.HAS_PYLATEX.require_in_instance
91
+ class MatplotlibDrawer:
92
+ """Matplotlib drawer class called from circuit_drawer"""
93
+
94
+ _mathmode_regex = re.compile(r"(?<!\\)\$(.*)(?<!\\)\$")
95
+
96
+ def __init__(
97
+ self,
98
+ qubits,
99
+ clbits,
100
+ nodes,
101
+ circuit,
102
+ scale=None,
103
+ style=None,
104
+ reverse_bits=False,
105
+ plot_barriers=True,
106
+ fold=25,
107
+ ax=None,
108
+ initial_state=False,
109
+ cregbundle=None,
110
+ with_layout=False,
111
+ expr_len=30,
112
+ ):
113
+ self._circuit = circuit
114
+ self._qubits = qubits
115
+ self._clbits = clbits
116
+ self._nodes = nodes
117
+ self._scale = 1.0 if scale is None else scale
118
+
119
+ self._style = style
120
+
121
+ self._plot_barriers = plot_barriers
122
+ self._reverse_bits = reverse_bits
123
+ if with_layout:
124
+ if self._circuit._layout:
125
+ self._layout = self._circuit._layout.initial_layout
126
+ else:
127
+ self._layout = None
128
+ else:
129
+ self._layout = None
130
+
131
+ self._fold = fold
132
+ if self._fold < 2:
133
+ self._fold = -1
134
+
135
+ self._ax = ax
136
+
137
+ self._initial_state = initial_state
138
+ self._global_phase = self._circuit.global_phase
139
+ self._expr_len = expr_len
140
+ self._cregbundle = cregbundle
141
+
142
+ self._lwidth1 = 1.0
143
+ self._lwidth15 = 1.5
144
+ self._lwidth2 = 2.0
145
+ self._lwidth3 = 3.0
146
+ self._lwidth4 = 4.0
147
+
148
+ # Class instances of MatplotlibDrawer for each flow gate - If/Else, For, While, Switch
149
+ self._flow_drawers = {}
150
+
151
+ # Set if gate is inside a flow gate
152
+ self._flow_parent = None
153
+ self._flow_wire_map = {}
154
+
155
+ # _char_list for finding text_width of names, labels, and params
156
+ self._char_list = {
157
+ " ": (0.0958, 0.0583),
158
+ "!": (0.1208, 0.0729),
159
+ '"': (0.1396, 0.0875),
160
+ "#": (0.2521, 0.1562),
161
+ "$": (0.1917, 0.1167),
162
+ "%": (0.2854, 0.1771),
163
+ "&": (0.2333, 0.1458),
164
+ "'": (0.0833, 0.0521),
165
+ "(": (0.1167, 0.0729),
166
+ ")": (0.1167, 0.0729),
167
+ "*": (0.15, 0.0938),
168
+ "+": (0.25, 0.1562),
169
+ ",": (0.0958, 0.0583),
170
+ "-": (0.1083, 0.0667),
171
+ ".": (0.0958, 0.0604),
172
+ "/": (0.1021, 0.0625),
173
+ "0": (0.1875, 0.1167),
174
+ "1": (0.1896, 0.1167),
175
+ "2": (0.1917, 0.1188),
176
+ "3": (0.1917, 0.1167),
177
+ "4": (0.1917, 0.1188),
178
+ "5": (0.1917, 0.1167),
179
+ "6": (0.1896, 0.1167),
180
+ "7": (0.1917, 0.1188),
181
+ "8": (0.1896, 0.1188),
182
+ "9": (0.1917, 0.1188),
183
+ ":": (0.1021, 0.0604),
184
+ ";": (0.1021, 0.0604),
185
+ "<": (0.25, 0.1542),
186
+ "=": (0.25, 0.1562),
187
+ ">": (0.25, 0.1542),
188
+ "?": (0.1583, 0.0979),
189
+ "@": (0.2979, 0.1854),
190
+ "A": (0.2062, 0.1271),
191
+ "B": (0.2042, 0.1271),
192
+ "C": (0.2083, 0.1292),
193
+ "D": (0.2312, 0.1417),
194
+ "E": (0.1875, 0.1167),
195
+ "F": (0.1708, 0.1062),
196
+ "G": (0.2312, 0.1438),
197
+ "H": (0.225, 0.1396),
198
+ "I": (0.0875, 0.0542),
199
+ "J": (0.0875, 0.0542),
200
+ "K": (0.1958, 0.1208),
201
+ "L": (0.1667, 0.1042),
202
+ "M": (0.2583, 0.1604),
203
+ "N": (0.225, 0.1396),
204
+ "O": (0.2354, 0.1458),
205
+ "P": (0.1812, 0.1125),
206
+ "Q": (0.2354, 0.1458),
207
+ "R": (0.2083, 0.1292),
208
+ "S": (0.1896, 0.1188),
209
+ "T": (0.1854, 0.1125),
210
+ "U": (0.2208, 0.1354),
211
+ "V": (0.2062, 0.1271),
212
+ "W": (0.2958, 0.1833),
213
+ "X": (0.2062, 0.1271),
214
+ "Y": (0.1833, 0.1125),
215
+ "Z": (0.2042, 0.1271),
216
+ "[": (0.1167, 0.075),
217
+ "\\": (0.1021, 0.0625),
218
+ "]": (0.1167, 0.0729),
219
+ "^": (0.2521, 0.1562),
220
+ "_": (0.1521, 0.0938),
221
+ "`": (0.15, 0.0938),
222
+ "a": (0.1854, 0.1146),
223
+ "b": (0.1917, 0.1167),
224
+ "c": (0.1646, 0.1021),
225
+ "d": (0.1896, 0.1188),
226
+ "e": (0.1854, 0.1146),
227
+ "f": (0.1042, 0.0667),
228
+ "g": (0.1896, 0.1188),
229
+ "h": (0.1896, 0.1188),
230
+ "i": (0.0854, 0.0521),
231
+ "j": (0.0854, 0.0521),
232
+ "k": (0.1729, 0.1083),
233
+ "l": (0.0854, 0.0521),
234
+ "m": (0.2917, 0.1812),
235
+ "n": (0.1896, 0.1188),
236
+ "o": (0.1833, 0.1125),
237
+ "p": (0.1917, 0.1167),
238
+ "q": (0.1896, 0.1188),
239
+ "r": (0.125, 0.0771),
240
+ "s": (0.1562, 0.0958),
241
+ "t": (0.1167, 0.0729),
242
+ "u": (0.1896, 0.1188),
243
+ "v": (0.1771, 0.1104),
244
+ "w": (0.2458, 0.1521),
245
+ "x": (0.1771, 0.1104),
246
+ "y": (0.1771, 0.1104),
247
+ "z": (0.1562, 0.0979),
248
+ "{": (0.1917, 0.1188),
249
+ "|": (0.1, 0.0604),
250
+ "}": (0.1896, 0.1188),
251
+ }
252
+
253
+ def draw(self, filename=None, verbose=False):
254
+ """Main entry point to 'matplotlib' ('mpl') drawer. Called from
255
+ ``visualization.circuit_drawer`` and from ``QuantumCircuit.draw`` through circuit_drawer.
256
+ """
257
+
258
+ # Import matplotlib and load all the figure, window, and style info
259
+ from matplotlib import patches
260
+ from matplotlib import pyplot as plt
261
+
262
+ # glob_data contains global values used throughout, "n_lines", "x_offset", "next_x_index",
263
+ # "patches_mod", "subfont_factor"
264
+ glob_data = {}
265
+
266
+ glob_data["patches_mod"] = patches
267
+ plt_mod = plt
268
+
269
+ self._style, def_font_ratio = load_style(self._style)
270
+
271
+ # If font/subfont ratio changes from default, have to scale width calculations for
272
+ # subfont. Font change is auto scaled in the mpl_figure.set_size_inches call in draw()
273
+ glob_data["subfont_factor"] = self._style["sfs"] * def_font_ratio / self._style["fs"]
274
+
275
+ # if no user ax, setup default figure. Else use the user figure.
276
+ if self._ax is None:
277
+ is_user_ax = False
278
+ mpl_figure = plt.figure()
279
+ mpl_figure.patch.set_facecolor(color=self._style["bg"])
280
+ self._ax = mpl_figure.add_subplot(111)
281
+ else:
282
+ is_user_ax = True
283
+ mpl_figure = self._ax.get_figure()
284
+ self._ax.axis("off")
285
+ self._ax.set_aspect("equal")
286
+ self._ax.tick_params(labelbottom=False, labeltop=False, labelleft=False, labelright=False)
287
+
288
+ # All information for the drawing is first loaded into node_data for the gates and into
289
+ # qubits_dict, clbits_dict, and wire_map for the qubits, clbits, and wires,
290
+ # followed by the coordinates for each gate.
291
+
292
+ # load the wire map
293
+ wire_map = get_wire_map(self._circuit, self._qubits + self._clbits, self._cregbundle)
294
+
295
+ # node_data per node filled with class NodeData attributes
296
+ node_data = {}
297
+
298
+ # dicts for the names and locations of register/bit labels
299
+ qubits_dict = {}
300
+ clbits_dict = {}
301
+
302
+ # load the _qubit_dict and _clbit_dict with register info
303
+ self._set_bit_reg_info(wire_map, qubits_dict, clbits_dict, glob_data)
304
+
305
+ # get layer widths - flow gates are initialized here
306
+ layer_widths = self._get_layer_widths(node_data, wire_map, self._circuit, glob_data)
307
+
308
+ # load the coordinates for each top level gate and compute number of folds.
309
+ # coordinates for flow gates are loaded before draw_ops
310
+ max_x_index = self._get_coords(
311
+ node_data, wire_map, self._circuit, layer_widths, qubits_dict, clbits_dict, glob_data
312
+ )
313
+ num_folds = max(0, max_x_index - 1) // self._fold if self._fold > 0 else 0
314
+
315
+ # The window size limits are computed, followed by one of the four possible ways
316
+ # of scaling the drawing.
317
+
318
+ # compute the window size
319
+ if max_x_index > self._fold > 0:
320
+ xmax = self._fold + glob_data["x_offset"] + 0.1
321
+ ymax = (num_folds + 1) * (glob_data["n_lines"] + 1) - 1
322
+ else:
323
+ x_incr = 0.4 if not self._nodes else 0.9
324
+ xmax = max_x_index + 1 + glob_data["x_offset"] - x_incr
325
+ ymax = glob_data["n_lines"]
326
+
327
+ xl = -self._style["margin"][0]
328
+ xr = xmax + self._style["margin"][1]
329
+ yb = -ymax - self._style["margin"][2] + 0.5
330
+ yt = self._style["margin"][3] + 0.5
331
+ self._ax.set_xlim(xl, xr)
332
+ self._ax.set_ylim(yb, yt)
333
+
334
+ # update figure size and, for backward compatibility,
335
+ # need to scale by a default value equal to (self._style["fs"] * 3.01 / 72 / 0.65)
336
+ base_fig_w = (xr - xl) * 0.8361111
337
+ base_fig_h = (yt - yb) * 0.8361111
338
+ scale = self._scale
339
+
340
+ # if user passes in an ax, this size takes priority over any other settings
341
+ if is_user_ax:
342
+ # from stackoverflow #19306510, get the bbox size for the ax and then reset scale
343
+ bbox = self._ax.get_window_extent().transformed(mpl_figure.dpi_scale_trans.inverted())
344
+ scale = bbox.width / base_fig_w / 0.8361111
345
+
346
+ # if scale not 1.0, use this scale factor
347
+ elif self._scale != 1.0:
348
+ mpl_figure.set_size_inches(base_fig_w * self._scale, base_fig_h * self._scale)
349
+
350
+ # if "figwidth" style param set, use this to scale
351
+ elif self._style["figwidth"] > 0.0:
352
+ # in order to get actual inches, need to scale by factor
353
+ adj_fig_w = self._style["figwidth"] * 1.282736
354
+ mpl_figure.set_size_inches(adj_fig_w, adj_fig_w * base_fig_h / base_fig_w)
355
+ scale = adj_fig_w / base_fig_w
356
+
357
+ # otherwise, display default size
358
+ else:
359
+ mpl_figure.set_size_inches(base_fig_w, base_fig_h)
360
+
361
+ # drawing will scale with 'set_size_inches', but fonts and linewidths do not
362
+ if scale != 1.0:
363
+ self._style["fs"] *= scale
364
+ self._style["sfs"] *= scale
365
+ self._lwidth1 = 1.0 * scale
366
+ self._lwidth15 = 1.5 * scale
367
+ self._lwidth2 = 2.0 * scale
368
+ self._lwidth3 = 3.0 * scale
369
+ self._lwidth4 = 4.0 * scale
370
+
371
+ # Once the scaling factor has been determined, the global phase, register names
372
+ # and numbers, wires, and gates are drawn
373
+ if self._global_phase:
374
+ plt_mod.text(xl, yt, f"Global Phase: {pi_check(self._global_phase, output='mpl')}")
375
+ self._draw_regs_wires(num_folds, xmax, max_x_index, qubits_dict, clbits_dict, glob_data)
376
+ self._draw_ops(
377
+ self._nodes,
378
+ node_data,
379
+ wire_map,
380
+ self._circuit,
381
+ layer_widths,
382
+ qubits_dict,
383
+ clbits_dict,
384
+ glob_data,
385
+ verbose,
386
+ )
387
+ if filename:
388
+ mpl_figure.savefig(
389
+ filename,
390
+ dpi=self._style["dpi"],
391
+ bbox_inches="tight",
392
+ facecolor=mpl_figure.get_facecolor(),
393
+ )
394
+ if not is_user_ax:
395
+ matplotlib_close_if_inline(mpl_figure)
396
+ return mpl_figure
397
+
398
+ def _get_layer_widths(self, node_data, wire_map, outer_circuit, glob_data):
399
+ """Compute the layer_widths for the layers"""
400
+
401
+ layer_widths = {}
402
+ for layer_num, layer in enumerate(self._nodes):
403
+ widest_box = WID
404
+ for i, node in enumerate(layer):
405
+ # Put the layer_num in the first node in the layer and put -1 in the rest
406
+ # so that layer widths are not counted more than once
407
+ if i != 0:
408
+ layer_num = -1
409
+ layer_widths[node] = [1, layer_num, self._flow_parent]
410
+
411
+ op = node.op
412
+ node_data[node] = NodeData()
413
+ node_data[node].width = WID
414
+ num_ctrl_qubits = getattr(op, "num_ctrl_qubits", 0)
415
+ if (
416
+ getattr(op, "_directive", False) and (not op.label or not self._plot_barriers)
417
+ ) or isinstance(op, Measure):
418
+ node_data[node].raw_gate_text = op.name
419
+ continue
420
+
421
+ base_type = getattr(op, "base_gate", None)
422
+ gate_text, ctrl_text, raw_gate_text = get_gate_ctrl_text(
423
+ op, "mpl", style=self._style
424
+ )
425
+ node_data[node].gate_text = gate_text
426
+ node_data[node].ctrl_text = ctrl_text
427
+ node_data[node].raw_gate_text = raw_gate_text
428
+ node_data[node].param_text = ""
429
+
430
+ # if single qubit, no params, and no labels, layer_width is 1
431
+ if (
432
+ (len(node.qargs) - num_ctrl_qubits) == 1
433
+ and len(gate_text) < 3
434
+ and len(getattr(op, "params", [])) == 0
435
+ and ctrl_text is None
436
+ ):
437
+ continue
438
+
439
+ if isinstance(op, SwapGate) or isinstance(base_type, SwapGate):
440
+ continue
441
+
442
+ # small increments at end of the 3 _get_text_width calls are for small
443
+ # spacing adjustments between gates
444
+ ctrl_width = (
445
+ self._get_text_width(ctrl_text, glob_data, fontsize=self._style["sfs"]) - 0.05
446
+ )
447
+ # get param_width, but 0 for gates with array params or circuits in params
448
+ if (
449
+ len(getattr(op, "params", [])) > 0
450
+ and not any(isinstance(param, np.ndarray) for param in op.params)
451
+ and not any(isinstance(param, QuantumCircuit) for param in op.params)
452
+ ):
453
+ param_text = get_param_str(op, "mpl", ndigits=3)
454
+ if isinstance(op, Initialize):
455
+ param_text = f"$[{param_text.replace('$', '')}]$"
456
+ node_data[node].param_text = param_text
457
+ raw_param_width = self._get_text_width(
458
+ param_text, glob_data, fontsize=self._style["sfs"], param=True
459
+ )
460
+ param_width = raw_param_width + 0.08
461
+ else:
462
+ param_width = raw_param_width = 0.0
463
+
464
+ # get gate_width for sidetext symmetric gates
465
+ if isinstance(op, RZZGate) or isinstance(base_type, (U1Gate, PhaseGate, RZZGate)):
466
+ if isinstance(base_type, PhaseGate):
467
+ gate_text = "P"
468
+ raw_gate_width = (
469
+ self._get_text_width(
470
+ gate_text + " ()", glob_data, fontsize=self._style["sfs"]
471
+ )
472
+ + raw_param_width
473
+ )
474
+ gate_width = (raw_gate_width + 0.08) * 1.58
475
+
476
+ # Check if a ControlFlowOp - node_data load for these gates is done here
477
+ elif isinstance(node.op, ControlFlowOp):
478
+ self._flow_drawers[node] = []
479
+ node_data[node].width = []
480
+ node_data[node].nest_depth = 0
481
+ gate_width = 0.0
482
+ expr_width = 0.0
483
+
484
+ if (isinstance(op, SwitchCaseOp) and isinstance(op.target, expr.Expr)) or (
485
+ getattr(op, "condition", None) and isinstance(op.condition, expr.Expr)
486
+ ):
487
+
488
+ def lookup_var(var):
489
+ """Look up a classical-expression variable or register/bit in our
490
+ internal symbol table, and return an OQ3-like identifier."""
491
+ # We don't attempt to disambiguate anything like register/var naming
492
+ # collisions; we already don't really show classical variables.
493
+ if isinstance(var, expr.Var):
494
+ return ast.Identifier(var.name)
495
+ if isinstance(var, ClassicalRegister):
496
+ return ast.Identifier(var.name)
497
+ # Single clbit. This is not actually the correct way to lookup a bit on
498
+ # the circuit (it doesn't handle bit bindings fully), but the mpl
499
+ # drawer doesn't completely track inner-outer _bit_ bindings, only
500
+ # inner-indices, so we can't fully recover the information losslessly.
501
+ # Since most control-flow uses the control-flow builders, we should
502
+ # decay to something usable most of the time.
503
+ try:
504
+ register, bit_index, reg_index = get_bit_reg_index(
505
+ outer_circuit, var
506
+ )
507
+ except CircuitError:
508
+ # We failed to find the bit due to binding problems - fall back to
509
+ # something that's probably wrong, but at least disambiguating.
510
+ return ast.Identifier(f"bit{wire_map[var]}")
511
+ if register is None:
512
+ return ast.Identifier(f"bit{bit_index}")
513
+ return ast.SubscriptedIdentifier(
514
+ register.name, ast.IntegerLiteral(reg_index)
515
+ )
516
+
517
+ condition = op.target if isinstance(op, SwitchCaseOp) else op.condition
518
+ stream = StringIO()
519
+ BasicPrinter(stream, indent=" ").visit(
520
+ condition.accept(_ExprBuilder(lookup_var))
521
+ )
522
+ expr_text = stream.getvalue()
523
+ # Truncate expr_text so that first gate is no more than about 3 x_index's over
524
+ if len(expr_text) > self._expr_len:
525
+ expr_text = expr_text[: self._expr_len] + "..."
526
+ node_data[node].expr_text = expr_text
527
+
528
+ expr_width = self._get_text_width(
529
+ node_data[node].expr_text, glob_data, fontsize=self._style["sfs"]
530
+ )
531
+ node_data[node].expr_width = int(expr_width)
532
+
533
+ # Get the list of circuits to iterate over from the blocks
534
+ circuit_list = list(node.op.blocks)
535
+
536
+ # params is [indexset, loop_param, circuit] for for_loop,
537
+ # op.cases_specifier() returns jump tuple and circuit for switch/case
538
+ if isinstance(op, ForLoopOp):
539
+ node_data[node].indexset = op.params[0]
540
+ elif isinstance(op, SwitchCaseOp):
541
+ node_data[node].jump_values = []
542
+ cases = list(op.cases_specifier())
543
+
544
+ # Create an empty circuit at the head of the circuit_list if a Switch box
545
+ circuit_list.insert(0, cases[0][1].copy_empty_like())
546
+ for jump_values, _ in cases:
547
+ node_data[node].jump_values.append(jump_values)
548
+
549
+ # Now process the circuits inside the ControlFlowOps
550
+ for circ_num, circuit in enumerate(circuit_list):
551
+ # Only add expr_width for if, while, and switch
552
+ raw_gate_width = expr_width if circ_num == 0 else 0.0
553
+
554
+ # Depth of nested ControlFlowOp used for color of box
555
+ if self._flow_parent is not None:
556
+ node_data[node].nest_depth = node_data[self._flow_parent].nest_depth + 1
557
+
558
+ # Build the wire_map to be used by this flow op
559
+ flow_wire_map = wire_map.copy()
560
+ flow_wire_map.update(
561
+ {
562
+ inner: wire_map[outer]
563
+ for outer, inner in zip(node.qargs, circuit.qubits)
564
+ }
565
+ )
566
+ for outer, inner in zip(node.cargs, circuit.clbits):
567
+ if self._cregbundle and (
568
+ (in_reg := get_bit_register(outer_circuit, inner)) is not None
569
+ ):
570
+ out_reg = get_bit_register(outer_circuit, outer)
571
+ flow_wire_map.update({in_reg: wire_map[out_reg]})
572
+ else:
573
+ flow_wire_map.update({inner: wire_map[outer]})
574
+
575
+ # Get the layered node lists and instantiate a new drawer class for
576
+ # the circuit inside the ControlFlowOp.
577
+ qubits, clbits, flow_nodes = _get_layered_instructions(
578
+ circuit, wire_map=flow_wire_map
579
+ )
580
+ flow_drawer = MatplotlibDrawer(
581
+ qubits,
582
+ clbits,
583
+ flow_nodes,
584
+ circuit,
585
+ style=self._style,
586
+ plot_barriers=self._plot_barriers,
587
+ fold=self._fold,
588
+ cregbundle=self._cregbundle,
589
+ )
590
+
591
+ # flow_parent is the parent of the new class instance
592
+ flow_drawer._flow_parent = node
593
+ flow_drawer._flow_wire_map = flow_wire_map
594
+ self._flow_drawers[node].append(flow_drawer)
595
+
596
+ # Recursively call _get_layer_widths for the circuit inside the ControlFlowOp
597
+ flow_widths = flow_drawer._get_layer_widths(
598
+ node_data, flow_wire_map, outer_circuit, glob_data
599
+ )
600
+ layer_widths.update(flow_widths)
601
+
602
+ for flow_layer in flow_nodes:
603
+ for flow_node in flow_layer:
604
+ node_data[flow_node].circ_num = circ_num
605
+
606
+ # Add up the width values of the same flow_parent that are not -1
607
+ # to get the raw_gate_width
608
+ for width, layer_num, flow_parent in flow_widths.values():
609
+ if layer_num != -1 and flow_parent == flow_drawer._flow_parent:
610
+ raw_gate_width += width
611
+
612
+ # Need extra incr of 1.0 for else and case boxes
613
+ gate_width += raw_gate_width + (1.0 if circ_num > 0 else 0.0)
614
+
615
+ # Minor adjustment so else and case section gates align with indexes
616
+ if circ_num > 0:
617
+ raw_gate_width += 0.045
618
+
619
+ # If expr_width has a value, remove the decimal portion from raw_gate_widthl
620
+ if not isinstance(op, ForLoopOp) and circ_num == 0:
621
+ node_data[node].width.append(raw_gate_width - (expr_width % 1))
622
+ else:
623
+ node_data[node].width.append(raw_gate_width)
624
+
625
+ # Otherwise, standard gate or multiqubit gate
626
+ else:
627
+ raw_gate_width = self._get_text_width(
628
+ gate_text, glob_data, fontsize=self._style["fs"]
629
+ )
630
+ gate_width = raw_gate_width + 0.10
631
+ # add .21 for the qubit numbers on the left of the multibit gates
632
+ if len(node.qargs) - num_ctrl_qubits > 1:
633
+ gate_width += 0.21
634
+
635
+ box_width = max(gate_width, ctrl_width, param_width, WID)
636
+ if box_width > widest_box:
637
+ widest_box = box_width
638
+ if not isinstance(node.op, ControlFlowOp):
639
+ node_data[node].width = max(raw_gate_width, raw_param_width)
640
+ for node in layer:
641
+ layer_widths[node][0] = int(widest_box) + 1
642
+
643
+ return layer_widths
644
+
645
+ def _set_bit_reg_info(self, wire_map, qubits_dict, clbits_dict, glob_data):
646
+ """Get all the info for drawing bit/reg names and numbers"""
647
+
648
+ longest_wire_label_width = 0
649
+ glob_data["n_lines"] = 0
650
+ initial_qbit = r" $|0\rangle$" if self._initial_state else ""
651
+ initial_cbit = " 0" if self._initial_state else ""
652
+
653
+ idx = 0
654
+ pos = y_off = -len(self._qubits) + 1
655
+ for ii, wire in enumerate(wire_map):
656
+ # if it's a creg, register is the key and just load the index
657
+ if isinstance(wire, ClassicalRegister):
658
+ # If wire came from ControlFlowOp and not in clbits, don't draw it
659
+ if wire[0] not in self._clbits:
660
+ continue
661
+ register = wire
662
+ index = wire_map[wire]
663
+
664
+ # otherwise, get the register from find_bit and use bit_index if
665
+ # it's a bit, or the index of the bit in the register if it's a reg
666
+ else:
667
+ # If wire came from ControlFlowOp and not in qubits or clbits, don't draw it
668
+ if wire not in self._qubits + self._clbits:
669
+ continue
670
+ register, bit_index, reg_index = get_bit_reg_index(self._circuit, wire)
671
+ index = bit_index if register is None else reg_index
672
+
673
+ wire_label = get_wire_label(
674
+ "mpl", register, index, layout=self._layout, cregbundle=self._cregbundle
675
+ )
676
+ initial_bit = initial_qbit if isinstance(wire, Qubit) else initial_cbit
677
+
678
+ # for cregs with cregbundle on, don't use math formatting, which means
679
+ # no italics
680
+ if isinstance(wire, Qubit) or register is None or not self._cregbundle:
681
+ wire_label = "$" + wire_label + "$"
682
+ wire_label += initial_bit
683
+
684
+ reg_size = (
685
+ 0 if register is None or isinstance(wire, ClassicalRegister) else register.size
686
+ )
687
+ reg_remove_under = 0 if reg_size < 2 else 1
688
+ text_width = (
689
+ self._get_text_width(
690
+ wire_label, glob_data, self._style["fs"], reg_remove_under=reg_remove_under
691
+ )
692
+ * 1.15
693
+ )
694
+ if text_width > longest_wire_label_width:
695
+ longest_wire_label_width = text_width
696
+
697
+ if isinstance(wire, Qubit):
698
+ pos = -ii
699
+ qubits_dict[ii] = {
700
+ "y": pos,
701
+ "wire_label": wire_label,
702
+ }
703
+ glob_data["n_lines"] += 1
704
+ else:
705
+ if (
706
+ not self._cregbundle
707
+ or register is None
708
+ or (self._cregbundle and isinstance(wire, ClassicalRegister))
709
+ ):
710
+ glob_data["n_lines"] += 1
711
+ idx += 1
712
+
713
+ pos = y_off - idx
714
+ clbits_dict[ii] = {
715
+ "y": pos,
716
+ "wire_label": wire_label,
717
+ "register": register,
718
+ }
719
+ glob_data["x_offset"] = -1.2 + longest_wire_label_width
720
+
721
+ def _get_coords(
722
+ self,
723
+ node_data,
724
+ wire_map,
725
+ outer_circuit,
726
+ layer_widths,
727
+ qubits_dict,
728
+ clbits_dict,
729
+ glob_data,
730
+ flow_parent=None,
731
+ ):
732
+ """Load all the coordinate info needed to place the gates on the drawing."""
733
+
734
+ prev_x_index = -1
735
+ for layer in self._nodes:
736
+ curr_x_index = prev_x_index + 1
737
+ l_width = []
738
+ for node in layer:
739
+ # For gates inside a flow op set the x_index and if it's an else or case,
740
+ # increment by if/switch width. If more cases increment by width of previous cases.
741
+ if flow_parent is not None:
742
+ node_data[node].inside_flow = True
743
+ node_data[node].x_index = node_data[flow_parent].x_index + curr_x_index + 1
744
+ # If an else or case
745
+ if node_data[node].circ_num > 0:
746
+ for width in node_data[flow_parent].width[: node_data[node].circ_num]:
747
+ node_data[node].x_index += int(width) + 1
748
+ x_index = node_data[node].x_index
749
+ # Add expr_width to if, while, or switch if expr used
750
+ else:
751
+ x_index = node_data[node].x_index + node_data[flow_parent].expr_width
752
+ else:
753
+ node_data[node].inside_flow = False
754
+ x_index = curr_x_index
755
+
756
+ # get qubit indexes
757
+ q_indxs = []
758
+ for qarg in node.qargs:
759
+ if qarg in self._qubits:
760
+ q_indxs.append(wire_map[qarg])
761
+
762
+ # get clbit indexes
763
+ c_indxs = []
764
+ for carg in node.cargs:
765
+ if carg in self._clbits:
766
+ if self._cregbundle:
767
+ register = get_bit_register(outer_circuit, carg)
768
+ if register is not None:
769
+ c_indxs.append(wire_map[register])
770
+ else:
771
+ c_indxs.append(wire_map[carg])
772
+ else:
773
+ c_indxs.append(wire_map[carg])
774
+
775
+ flow_op = isinstance(node.op, ControlFlowOp)
776
+
777
+ # qubit coordinates
778
+ node_data[node].q_xy = [
779
+ self._plot_coord(
780
+ x_index,
781
+ qubits_dict[ii]["y"],
782
+ layer_widths[node][0],
783
+ glob_data,
784
+ flow_op,
785
+ )
786
+ for ii in q_indxs
787
+ ]
788
+ # clbit coordinates
789
+ node_data[node].c_xy = [
790
+ self._plot_coord(
791
+ x_index,
792
+ clbits_dict[ii]["y"],
793
+ layer_widths[node][0],
794
+ glob_data,
795
+ flow_op,
796
+ )
797
+ for ii in c_indxs
798
+ ]
799
+
800
+ # update index based on the value from plotting
801
+ if flow_parent is None:
802
+ curr_x_index = glob_data["next_x_index"]
803
+ l_width.append(layer_widths[node][0])
804
+ node_data[node].x_index = x_index
805
+
806
+ # Special case of default case with no ops in it, need to push end
807
+ # of switch op one extra x_index
808
+ if isinstance(node.op, SwitchCaseOp):
809
+ if len(node.op.blocks[-1]) == 0:
810
+ curr_x_index += 1
811
+
812
+ # adjust the column if there have been barriers encountered, but not plotted
813
+ barrier_offset = 0
814
+ if not self._plot_barriers:
815
+ # only adjust if everything in the layer wasn't plotted
816
+ barrier_offset = (
817
+ -1 if all(getattr(nd.op, "_directive", False) for nd in layer) else 0
818
+ )
819
+ max_lwidth = max(l_width) if l_width else 0
820
+ prev_x_index = curr_x_index + max_lwidth + barrier_offset - 1
821
+
822
+ return prev_x_index + 1
823
+
824
+ def _get_text_width(self, text, glob_data, fontsize, param=False, reg_remove_under=None):
825
+ """Compute the width of a string in the default font"""
826
+
827
+ from pylatexenc.latex2text import LatexNodes2Text
828
+
829
+ if not text:
830
+ return 0.0
831
+
832
+ math_mode_match = self._mathmode_regex.search(text)
833
+ num_underscores = 0
834
+ num_carets = 0
835
+ if math_mode_match:
836
+ math_mode_text = math_mode_match.group(1)
837
+ num_underscores = math_mode_text.count("_")
838
+ num_carets = math_mode_text.count("^")
839
+ text = LatexNodes2Text().latex_to_text(text.replace("$$", ""))
840
+
841
+ # If there are subscripts or superscripts in mathtext string
842
+ # we need to account for that spacing by manually removing
843
+ # from text string for text length
844
+
845
+ # if it's a register and there's a subscript at the end,
846
+ # remove 1 underscore, otherwise don't remove any
847
+ if reg_remove_under is not None:
848
+ num_underscores = reg_remove_under
849
+ if num_underscores:
850
+ text = text.replace("_", "", num_underscores)
851
+ if num_carets:
852
+ text = text.replace("^", "", num_carets)
853
+
854
+ # This changes hyphen to + to match width of math mode minus sign.
855
+ if param:
856
+ text = text.replace("-", "+")
857
+
858
+ f = 0 if fontsize == self._style["fs"] else 1
859
+ sum_text = 0.0
860
+ for c in text:
861
+ try:
862
+ sum_text += self._char_list[c][f]
863
+ except KeyError:
864
+ # if non-ASCII char, use width of 'c', an average size
865
+ sum_text += self._char_list["c"][f]
866
+ if f == 1:
867
+ sum_text *= glob_data["subfont_factor"]
868
+ return sum_text
869
+
870
+ def _draw_regs_wires(self, num_folds, xmax, max_x_index, qubits_dict, clbits_dict, glob_data):
871
+ """Draw the register names and numbers, wires, and vertical lines at the ends"""
872
+
873
+ for fold_num in range(num_folds + 1):
874
+ # quantum registers
875
+ for qubit in qubits_dict.values():
876
+ qubit_label = qubit["wire_label"]
877
+ y = qubit["y"] - fold_num * (glob_data["n_lines"] + 1)
878
+ self._ax.text(
879
+ glob_data["x_offset"] - 0.2,
880
+ y,
881
+ qubit_label,
882
+ ha="right",
883
+ va="center",
884
+ fontsize=1.25 * self._style["fs"],
885
+ color=self._style["tc"],
886
+ clip_on=True,
887
+ zorder=PORDER_TEXT,
888
+ )
889
+ # draw the qubit wire
890
+ self._line([glob_data["x_offset"], y], [xmax, y], zorder=PORDER_REGLINE)
891
+
892
+ # classical registers
893
+ this_clbit_dict = {}
894
+ for clbit in clbits_dict.values():
895
+ y = clbit["y"] - fold_num * (glob_data["n_lines"] + 1)
896
+ if y not in this_clbit_dict:
897
+ this_clbit_dict[y] = {
898
+ "val": 1,
899
+ "wire_label": clbit["wire_label"],
900
+ "register": clbit["register"],
901
+ }
902
+ else:
903
+ this_clbit_dict[y]["val"] += 1
904
+
905
+ for y, this_clbit in this_clbit_dict.items():
906
+ # cregbundle
907
+ if self._cregbundle and this_clbit["register"] is not None:
908
+ self._ax.plot(
909
+ [glob_data["x_offset"] + 0.2, glob_data["x_offset"] + 0.3],
910
+ [y - 0.1, y + 0.1],
911
+ color=self._style["cc"],
912
+ zorder=PORDER_REGLINE,
913
+ )
914
+ self._ax.text(
915
+ glob_data["x_offset"] + 0.1,
916
+ y + 0.1,
917
+ str(this_clbit["register"].size),
918
+ ha="left",
919
+ va="bottom",
920
+ fontsize=0.8 * self._style["fs"],
921
+ color=self._style["tc"],
922
+ clip_on=True,
923
+ zorder=PORDER_TEXT,
924
+ )
925
+ self._ax.text(
926
+ glob_data["x_offset"] - 0.2,
927
+ y,
928
+ this_clbit["wire_label"],
929
+ ha="right",
930
+ va="center",
931
+ fontsize=1.25 * self._style["fs"],
932
+ color=self._style["tc"],
933
+ clip_on=True,
934
+ zorder=PORDER_TEXT,
935
+ )
936
+ # draw the clbit wire
937
+ self._line(
938
+ [glob_data["x_offset"], y],
939
+ [xmax, y],
940
+ lc=self._style["cc"],
941
+ ls=self._style["cline"],
942
+ zorder=PORDER_REGLINE,
943
+ )
944
+
945
+ # lf vertical line at either end
946
+ feedline_r = num_folds > 0 and num_folds > fold_num
947
+ feedline_l = fold_num > 0
948
+ if feedline_l or feedline_r:
949
+ xpos_l = glob_data["x_offset"] - 0.01
950
+ xpos_r = self._fold + glob_data["x_offset"] + 0.1
951
+ ypos1 = -fold_num * (glob_data["n_lines"] + 1)
952
+ ypos2 = -(fold_num + 1) * (glob_data["n_lines"]) - fold_num + 1
953
+ if feedline_l:
954
+ self._ax.plot(
955
+ [xpos_l, xpos_l],
956
+ [ypos1, ypos2],
957
+ color=self._style["lc"],
958
+ linewidth=self._lwidth15,
959
+ zorder=PORDER_REGLINE,
960
+ )
961
+ if feedline_r:
962
+ self._ax.plot(
963
+ [xpos_r, xpos_r],
964
+ [ypos1, ypos2],
965
+ color=self._style["lc"],
966
+ linewidth=self._lwidth15,
967
+ zorder=PORDER_REGLINE,
968
+ )
969
+ # Mask off any lines or boxes in the bit label area to clean up
970
+ # from folding for ControlFlow and other wrapping gates
971
+ box = glob_data["patches_mod"].Rectangle(
972
+ xy=(glob_data["x_offset"] - 0.1, -fold_num * (glob_data["n_lines"] + 1) + 0.5),
973
+ width=-25.0,
974
+ height=-(fold_num + 1) * (glob_data["n_lines"] + 1),
975
+ fc=self._style["bg"],
976
+ ec=self._style["bg"],
977
+ linewidth=self._lwidth15,
978
+ zorder=PORDER_MASK,
979
+ )
980
+ self._ax.add_patch(box)
981
+
982
+ # draw index number
983
+ if self._style["index"]:
984
+ for layer_num in range(max_x_index):
985
+ if self._fold > 0:
986
+ x_coord = layer_num % self._fold + glob_data["x_offset"] + 0.53
987
+ y_coord = -(layer_num // self._fold) * (glob_data["n_lines"] + 1) + 0.65
988
+ else:
989
+ x_coord = layer_num + glob_data["x_offset"] + 0.53
990
+ y_coord = 0.65
991
+ self._ax.text(
992
+ x_coord,
993
+ y_coord,
994
+ str(layer_num + 1),
995
+ ha="center",
996
+ va="center",
997
+ fontsize=self._style["sfs"],
998
+ color=self._style["tc"],
999
+ clip_on=True,
1000
+ zorder=PORDER_TEXT,
1001
+ )
1002
+
1003
+ def _add_nodes_and_coords(
1004
+ self,
1005
+ nodes,
1006
+ node_data,
1007
+ wire_map,
1008
+ outer_circuit,
1009
+ layer_widths,
1010
+ qubits_dict,
1011
+ clbits_dict,
1012
+ glob_data,
1013
+ ):
1014
+ """Add the nodes from ControlFlowOps and their coordinates to the main circuit"""
1015
+ for flow_drawers in self._flow_drawers.values():
1016
+ for flow_drawer in flow_drawers:
1017
+ nodes += flow_drawer._nodes
1018
+ flow_drawer._get_coords(
1019
+ node_data,
1020
+ flow_drawer._flow_wire_map,
1021
+ outer_circuit,
1022
+ layer_widths,
1023
+ qubits_dict,
1024
+ clbits_dict,
1025
+ glob_data,
1026
+ flow_parent=flow_drawer._flow_parent,
1027
+ )
1028
+ # Recurse for ControlFlowOps inside the flow_drawer
1029
+ flow_drawer._add_nodes_and_coords(
1030
+ nodes,
1031
+ node_data,
1032
+ wire_map,
1033
+ outer_circuit,
1034
+ layer_widths,
1035
+ qubits_dict,
1036
+ clbits_dict,
1037
+ glob_data,
1038
+ )
1039
+
1040
+ def _draw_ops(
1041
+ self,
1042
+ nodes,
1043
+ node_data,
1044
+ wire_map,
1045
+ outer_circuit,
1046
+ layer_widths,
1047
+ qubits_dict,
1048
+ clbits_dict,
1049
+ glob_data,
1050
+ verbose=False,
1051
+ ):
1052
+ """Draw the gates in the circuit"""
1053
+
1054
+ # Add the nodes from all the ControlFlowOps and their coordinates to the main nodes
1055
+ self._add_nodes_and_coords(
1056
+ nodes,
1057
+ node_data,
1058
+ wire_map,
1059
+ outer_circuit,
1060
+ layer_widths,
1061
+ qubits_dict,
1062
+ clbits_dict,
1063
+ glob_data,
1064
+ )
1065
+ prev_x_index = -1
1066
+ for layer in nodes:
1067
+ l_width = []
1068
+ curr_x_index = prev_x_index + 1
1069
+
1070
+ # draw the gates in this layer
1071
+ for node in layer:
1072
+ op = node.op
1073
+
1074
+ self._get_colors(node, node_data)
1075
+
1076
+ if verbose:
1077
+ print(op) # pylint: disable=bad-builtin
1078
+
1079
+ # add conditional
1080
+ if getattr(op, "condition", None) or isinstance(op, SwitchCaseOp):
1081
+ cond_xy = [
1082
+ self._plot_coord(
1083
+ node_data[node].x_index,
1084
+ clbits_dict[ii]["y"],
1085
+ layer_widths[node][0],
1086
+ glob_data,
1087
+ isinstance(op, ControlFlowOp),
1088
+ )
1089
+ for ii in clbits_dict
1090
+ ]
1091
+ self._condition(node, node_data, wire_map, outer_circuit, cond_xy, glob_data)
1092
+
1093
+ # AnnotatedOperation with ControlModifier
1094
+ mod_control = None
1095
+ if getattr(op, "modifiers", None):
1096
+ canonical_modifiers = _canonicalize_modifiers(op.modifiers)
1097
+ for modifier in canonical_modifiers:
1098
+ if isinstance(modifier, ControlModifier):
1099
+ mod_control = modifier
1100
+ break
1101
+
1102
+ # draw measure
1103
+ if isinstance(op, Measure):
1104
+ self._measure(node, node_data, outer_circuit, glob_data)
1105
+
1106
+ # draw barriers, snapshots, etc.
1107
+ elif getattr(op, "_directive", False):
1108
+ if self._plot_barriers:
1109
+ self._barrier(node, node_data, glob_data)
1110
+
1111
+ # draw the box for control flow circuits
1112
+ elif isinstance(op, ControlFlowOp):
1113
+ self._flow_op_gate(node, node_data, glob_data)
1114
+
1115
+ # draw single qubit gates
1116
+ elif len(node_data[node].q_xy) == 1 and not node.cargs:
1117
+ self._gate(node, node_data, glob_data)
1118
+
1119
+ # draw controlled gates
1120
+ elif isinstance(op, ControlledGate) or mod_control:
1121
+ self._control_gate(node, node_data, glob_data, mod_control)
1122
+
1123
+ # draw multi-qubit gate as final default
1124
+ else:
1125
+ self._multiqubit_gate(node, node_data, glob_data)
1126
+
1127
+ # Determine the max width of the circuit only at the top level
1128
+ if not node_data[node].inside_flow:
1129
+ l_width.append(layer_widths[node][0])
1130
+
1131
+ # adjust the column if there have been barriers encountered, but not plotted
1132
+ barrier_offset = 0
1133
+ if not self._plot_barriers:
1134
+ # only adjust if everything in the layer wasn't plotted
1135
+ barrier_offset = (
1136
+ -1 if all(getattr(nd.op, "_directive", False) for nd in layer) else 0
1137
+ )
1138
+ prev_x_index = curr_x_index + (max(l_width) if l_width else 0) + barrier_offset - 1
1139
+
1140
+ def _get_colors(self, node, node_data):
1141
+ """Get all the colors needed for drawing the circuit"""
1142
+
1143
+ op = node.op
1144
+ base_name = getattr(getattr(op, "base_gate", None), "name", None)
1145
+ color = None
1146
+ if node_data[node].raw_gate_text in self._style["dispcol"]:
1147
+ color = self._style["dispcol"][node_data[node].raw_gate_text]
1148
+ elif op.name in self._style["dispcol"]:
1149
+ color = self._style["dispcol"][op.name]
1150
+ if color is not None:
1151
+ # Backward compatibility for style dict using 'displaycolor' with
1152
+ # gate color and no text color, so test for str first
1153
+ if isinstance(color, str):
1154
+ fc = color
1155
+ gt = self._style["gt"]
1156
+ else:
1157
+ fc = color[0]
1158
+ gt = color[1]
1159
+ # Treat special case of classical gates in iqx style by making all
1160
+ # controlled gates of x, dcx, and swap the classical gate color
1161
+ elif self._style["name"] in ["iqp", "iqx", "iqp-dark", "iqx-dark"] and base_name in [
1162
+ "x",
1163
+ "dcx",
1164
+ "swap",
1165
+ ]:
1166
+ color = self._style["dispcol"][base_name]
1167
+ if isinstance(color, str):
1168
+ fc = color
1169
+ gt = self._style["gt"]
1170
+ else:
1171
+ fc = color[0]
1172
+ gt = color[1]
1173
+ else:
1174
+ fc = self._style["gc"]
1175
+ gt = self._style["gt"]
1176
+
1177
+ if self._style["name"] == "bw":
1178
+ ec = self._style["ec"]
1179
+ lc = self._style["lc"]
1180
+ else:
1181
+ ec = fc
1182
+ lc = fc
1183
+ # Subtext needs to be same color as gate text
1184
+ sc = gt
1185
+ node_data[node].fc = fc
1186
+ node_data[node].ec = ec
1187
+ node_data[node].gt = gt
1188
+ node_data[node].tc = self._style["tc"]
1189
+ node_data[node].sc = sc
1190
+ node_data[node].lc = lc
1191
+
1192
+ def _condition(self, node, node_data, wire_map, outer_circuit, cond_xy, glob_data):
1193
+ """Add a conditional to a gate"""
1194
+
1195
+ # For SwitchCaseOp convert the target to a fully closed Clbit or register
1196
+ # in condition format
1197
+ if isinstance(node.op, SwitchCaseOp):
1198
+ if isinstance(node.op.target, expr.Expr):
1199
+ condition = node.op.target
1200
+ elif isinstance(node.op.target, Clbit):
1201
+ condition = (node.op.target, 1)
1202
+ else:
1203
+ condition = (node.op.target, 2 ** (node.op.target.size) - 1)
1204
+ else:
1205
+ condition = node.op.condition
1206
+
1207
+ override_fc = False
1208
+ first_clbit = len(self._qubits)
1209
+ cond_pos = []
1210
+
1211
+ if isinstance(condition, expr.Expr):
1212
+ # If fixing this, please update the docstrings of `QuantumCircuit.draw` and
1213
+ # `visualization.circuit_drawer` to remove warnings.
1214
+
1215
+ condition_bits = condition_resources(condition).clbits
1216
+ label = "[expr]"
1217
+ override_fc = True
1218
+ registers = collections.defaultdict(list)
1219
+ for bit in condition_bits:
1220
+ registers[get_bit_register(outer_circuit, bit)].append(bit)
1221
+ # Registerless bits don't care whether cregbundle is set.
1222
+ cond_pos.extend(cond_xy[wire_map[bit] - first_clbit] for bit in registers.pop(None, ()))
1223
+ if self._cregbundle:
1224
+ cond_pos.extend(cond_xy[wire_map[register] - first_clbit] for register in registers)
1225
+ else:
1226
+ cond_pos.extend(
1227
+ cond_xy[wire_map[bit] - first_clbit]
1228
+ for bit in itertools.chain.from_iterable(registers.values())
1229
+ )
1230
+ val_bits = ["1"] * len(cond_pos)
1231
+ else:
1232
+ label, val_bits = get_condition_label_val(condition, self._circuit, self._cregbundle)
1233
+ cond_bit_reg = condition[0]
1234
+ cond_bit_val = int(condition[1])
1235
+ override_fc = (
1236
+ cond_bit_val != 0
1237
+ and self._cregbundle
1238
+ and isinstance(cond_bit_reg, ClassicalRegister)
1239
+ )
1240
+
1241
+ # In the first case, multiple bits are indicated on the drawing. In all
1242
+ # other cases, only one bit is shown.
1243
+ if not self._cregbundle and isinstance(cond_bit_reg, ClassicalRegister):
1244
+ for idx in range(cond_bit_reg.size):
1245
+ cond_pos.append(cond_xy[wire_map[cond_bit_reg[idx]] - first_clbit])
1246
+
1247
+ # If it's a register bit and cregbundle, need to use the register to find the location
1248
+ elif self._cregbundle and isinstance(cond_bit_reg, Clbit):
1249
+ register = get_bit_register(outer_circuit, cond_bit_reg)
1250
+ if register is not None:
1251
+ cond_pos.append(cond_xy[wire_map[register] - first_clbit])
1252
+ else:
1253
+ cond_pos.append(cond_xy[wire_map[cond_bit_reg] - first_clbit])
1254
+ else:
1255
+ cond_pos.append(cond_xy[wire_map[cond_bit_reg] - first_clbit])
1256
+
1257
+ xy_plot = []
1258
+ for val_bit, xy in zip(val_bits, cond_pos):
1259
+ fc = self._style["lc"] if override_fc or val_bit == "1" else self._style["bg"]
1260
+ box = glob_data["patches_mod"].Circle(
1261
+ xy=xy,
1262
+ radius=WID * 0.15,
1263
+ fc=fc,
1264
+ ec=self._style["lc"],
1265
+ linewidth=self._lwidth15,
1266
+ zorder=PORDER_GATE,
1267
+ )
1268
+ self._ax.add_patch(box)
1269
+ xy_plot.append(xy)
1270
+
1271
+ if not xy_plot:
1272
+ # Expression that's only on new-style `expr.Var` nodes, and doesn't need any vertical
1273
+ # line drawing.
1274
+ return
1275
+
1276
+ qubit_b = min(node_data[node].q_xy, key=lambda xy: xy[1])
1277
+ clbit_b = min(xy_plot, key=lambda xy: xy[1])
1278
+
1279
+ # For IfElseOp, WhileLoopOp or SwitchCaseOp, place the condition line
1280
+ # near the left edge of the box
1281
+ if isinstance(node.op, (IfElseOp, WhileLoopOp, SwitchCaseOp)):
1282
+ qubit_b = (qubit_b[0], qubit_b[1] - (0.5 * HIG + 0.14))
1283
+
1284
+ # display the label at the bottom of the lowest conditional and draw the double line
1285
+ xpos, ypos = clbit_b
1286
+ if isinstance(node.op, Measure):
1287
+ xpos += 0.3
1288
+ self._ax.text(
1289
+ xpos,
1290
+ ypos - 0.3 * HIG,
1291
+ label,
1292
+ ha="center",
1293
+ va="top",
1294
+ fontsize=self._style["sfs"],
1295
+ color=self._style["tc"],
1296
+ clip_on=True,
1297
+ zorder=PORDER_TEXT,
1298
+ )
1299
+ self._line(qubit_b, clbit_b, lc=self._style["cc"], ls=self._style["cline"])
1300
+
1301
+ def _measure(self, node, node_data, outer_circuit, glob_data):
1302
+ """Draw the measure symbol and the line to the clbit"""
1303
+ qx, qy = node_data[node].q_xy[0]
1304
+ cx, cy = node_data[node].c_xy[0]
1305
+ register, _, reg_index = get_bit_reg_index(outer_circuit, node.cargs[0])
1306
+
1307
+ # draw gate box
1308
+ self._gate(node, node_data, glob_data)
1309
+
1310
+ # add measure symbol
1311
+ arc = glob_data["patches_mod"].Arc(
1312
+ xy=(qx, qy - 0.15 * HIG),
1313
+ width=WID * 0.7,
1314
+ height=HIG * 0.7,
1315
+ theta1=0,
1316
+ theta2=180,
1317
+ fill=False,
1318
+ ec=node_data[node].gt,
1319
+ linewidth=self._lwidth2,
1320
+ zorder=PORDER_GATE,
1321
+ )
1322
+ self._ax.add_patch(arc)
1323
+ self._ax.plot(
1324
+ [qx, qx + 0.35 * WID],
1325
+ [qy - 0.15 * HIG, qy + 0.20 * HIG],
1326
+ color=node_data[node].gt,
1327
+ linewidth=self._lwidth2,
1328
+ zorder=PORDER_GATE,
1329
+ )
1330
+ # arrow
1331
+ self._line(
1332
+ node_data[node].q_xy[0],
1333
+ [cx, cy + 0.35 * WID],
1334
+ lc=self._style["cc"],
1335
+ ls=self._style["cline"],
1336
+ )
1337
+ arrowhead = glob_data["patches_mod"].Polygon(
1338
+ (
1339
+ (cx - 0.20 * WID, cy + 0.35 * WID),
1340
+ (cx + 0.20 * WID, cy + 0.35 * WID),
1341
+ (cx, cy + 0.04),
1342
+ ),
1343
+ fc=self._style["cc"],
1344
+ ec=None,
1345
+ )
1346
+ self._ax.add_artist(arrowhead)
1347
+ # target
1348
+ if self._cregbundle and register is not None:
1349
+ self._ax.text(
1350
+ cx + 0.25,
1351
+ cy + 0.1,
1352
+ str(reg_index),
1353
+ ha="left",
1354
+ va="bottom",
1355
+ fontsize=0.8 * self._style["fs"],
1356
+ color=self._style["tc"],
1357
+ clip_on=True,
1358
+ zorder=PORDER_TEXT,
1359
+ )
1360
+
1361
+ def _barrier(self, node, node_data, glob_data):
1362
+ """Draw a barrier"""
1363
+ for i, xy in enumerate(node_data[node].q_xy):
1364
+ xpos, ypos = xy
1365
+ # For the topmost barrier, reduce the rectangle if there's a label to allow for the text.
1366
+ if i == 0 and node.op.label is not None:
1367
+ ypos_adj = -0.35
1368
+ else:
1369
+ ypos_adj = 0.0
1370
+ self._ax.plot(
1371
+ [xpos, xpos],
1372
+ [ypos + 0.5 + ypos_adj, ypos - 0.5],
1373
+ linewidth=self._lwidth1,
1374
+ linestyle="dashed",
1375
+ color=self._style["lc"],
1376
+ zorder=PORDER_TEXT,
1377
+ )
1378
+ box = glob_data["patches_mod"].Rectangle(
1379
+ xy=(xpos - (0.3 * WID), ypos - 0.5),
1380
+ width=0.6 * WID,
1381
+ height=1.0 + ypos_adj,
1382
+ fc=self._style["bc"],
1383
+ ec=None,
1384
+ alpha=0.6,
1385
+ linewidth=self._lwidth15,
1386
+ zorder=PORDER_BARRIER,
1387
+ )
1388
+ self._ax.add_patch(box)
1389
+
1390
+ # display the barrier label at the top if there is one
1391
+ if i == 0 and node.op.label is not None:
1392
+ dir_ypos = ypos + 0.65 * HIG
1393
+ self._ax.text(
1394
+ xpos,
1395
+ dir_ypos,
1396
+ node.op.label,
1397
+ ha="center",
1398
+ va="top",
1399
+ fontsize=self._style["fs"],
1400
+ color=node_data[node].tc,
1401
+ clip_on=True,
1402
+ zorder=PORDER_TEXT,
1403
+ )
1404
+
1405
+ def _gate(self, node, node_data, glob_data, xy=None):
1406
+ """Draw a 1-qubit gate"""
1407
+ if xy is None:
1408
+ xy = node_data[node].q_xy[0]
1409
+ xpos, ypos = xy
1410
+ wid = max(node_data[node].width, WID)
1411
+
1412
+ box = glob_data["patches_mod"].Rectangle(
1413
+ xy=(xpos - 0.5 * wid, ypos - 0.5 * HIG),
1414
+ width=wid,
1415
+ height=HIG,
1416
+ fc=node_data[node].fc,
1417
+ ec=node_data[node].ec,
1418
+ linewidth=self._lwidth15,
1419
+ zorder=PORDER_GATE,
1420
+ )
1421
+ self._ax.add_patch(box)
1422
+
1423
+ if node_data[node].gate_text:
1424
+ gate_ypos = ypos
1425
+ if node_data[node].param_text:
1426
+ gate_ypos = ypos + 0.15 * HIG
1427
+ self._ax.text(
1428
+ xpos,
1429
+ ypos - 0.3 * HIG,
1430
+ node_data[node].param_text,
1431
+ ha="center",
1432
+ va="center",
1433
+ fontsize=self._style["sfs"],
1434
+ color=node_data[node].sc,
1435
+ clip_on=True,
1436
+ zorder=PORDER_TEXT,
1437
+ )
1438
+ self._ax.text(
1439
+ xpos,
1440
+ gate_ypos,
1441
+ node_data[node].gate_text,
1442
+ ha="center",
1443
+ va="center",
1444
+ fontsize=self._style["fs"],
1445
+ color=node_data[node].gt,
1446
+ clip_on=True,
1447
+ zorder=PORDER_TEXT,
1448
+ )
1449
+
1450
+ def _multiqubit_gate(self, node, node_data, glob_data, xy=None):
1451
+ """Draw a gate covering more than one qubit"""
1452
+ op = node.op
1453
+ if xy is None:
1454
+ xy = node_data[node].q_xy
1455
+
1456
+ # Swap gate
1457
+ if isinstance(op, SwapGate):
1458
+ self._swap(xy, node_data[node].lc)
1459
+ return
1460
+
1461
+ # RZZ Gate
1462
+ elif isinstance(op, RZZGate):
1463
+ self._symmetric_gate(node, node_data, RZZGate, glob_data)
1464
+ return
1465
+
1466
+ c_xy = node_data[node].c_xy
1467
+ xpos = min(x[0] for x in xy)
1468
+ ypos = min(y[1] for y in xy)
1469
+ ypos_max = max(y[1] for y in xy)
1470
+ if c_xy:
1471
+ cxpos = min(x[0] for x in c_xy)
1472
+ cypos = min(y[1] for y in c_xy)
1473
+ ypos = min(ypos, cypos)
1474
+
1475
+ wid = max(node_data[node].width + 0.21, WID)
1476
+ qubit_span = abs(ypos) - abs(ypos_max)
1477
+ height = HIG + qubit_span
1478
+
1479
+ box = glob_data["patches_mod"].Rectangle(
1480
+ xy=(xpos - 0.5 * wid, ypos - 0.5 * HIG),
1481
+ width=wid,
1482
+ height=height,
1483
+ fc=node_data[node].fc,
1484
+ ec=node_data[node].ec,
1485
+ linewidth=self._lwidth15,
1486
+ zorder=PORDER_GATE,
1487
+ )
1488
+ self._ax.add_patch(box)
1489
+
1490
+ # annotate inputs
1491
+ for bit, y in enumerate([x[1] for x in xy]):
1492
+ self._ax.text(
1493
+ xpos + 0.07 - 0.5 * wid,
1494
+ y,
1495
+ str(bit),
1496
+ ha="left",
1497
+ va="center",
1498
+ fontsize=self._style["fs"],
1499
+ color=node_data[node].gt,
1500
+ clip_on=True,
1501
+ zorder=PORDER_TEXT,
1502
+ )
1503
+ if c_xy:
1504
+ # annotate classical inputs
1505
+ for bit, y in enumerate([x[1] for x in c_xy]):
1506
+ self._ax.text(
1507
+ cxpos + 0.07 - 0.5 * wid,
1508
+ y,
1509
+ str(bit),
1510
+ ha="left",
1511
+ va="center",
1512
+ fontsize=self._style["fs"],
1513
+ color=node_data[node].gt,
1514
+ clip_on=True,
1515
+ zorder=PORDER_TEXT,
1516
+ )
1517
+ if node_data[node].gate_text:
1518
+ gate_ypos = ypos + 0.5 * qubit_span
1519
+ if node_data[node].param_text:
1520
+ gate_ypos = ypos + 0.4 * height
1521
+ self._ax.text(
1522
+ xpos + 0.11,
1523
+ ypos + 0.2 * height,
1524
+ node_data[node].param_text,
1525
+ ha="center",
1526
+ va="center",
1527
+ fontsize=self._style["sfs"],
1528
+ color=node_data[node].sc,
1529
+ clip_on=True,
1530
+ zorder=PORDER_TEXT,
1531
+ )
1532
+ self._ax.text(
1533
+ xpos + 0.11,
1534
+ gate_ypos,
1535
+ node_data[node].gate_text,
1536
+ ha="center",
1537
+ va="center",
1538
+ fontsize=self._style["fs"],
1539
+ color=node_data[node].gt,
1540
+ clip_on=True,
1541
+ zorder=PORDER_TEXT,
1542
+ )
1543
+
1544
+ def _flow_op_gate(self, node, node_data, glob_data):
1545
+ """Draw the box for a flow op circuit"""
1546
+ xy = node_data[node].q_xy
1547
+ xpos = min(x[0] for x in xy)
1548
+ ypos = min(y[1] for y in xy)
1549
+ ypos_max = max(y[1] for y in xy)
1550
+
1551
+ if_width = node_data[node].width[0] + WID
1552
+ box_width = if_width
1553
+ # Add the else and case widths to the if_width
1554
+ for ewidth in node_data[node].width[1:]:
1555
+ if ewidth > 0.0:
1556
+ box_width += ewidth + WID + 0.3
1557
+
1558
+ qubit_span = abs(ypos) - abs(ypos_max)
1559
+ height = HIG + qubit_span
1560
+
1561
+ # Cycle through box colors based on depth.
1562
+ # Default - blue, purple, green, black
1563
+ colors = [
1564
+ self._style["dispcol"]["h"][0],
1565
+ self._style["dispcol"]["u"][0],
1566
+ self._style["dispcol"]["x"][0],
1567
+ self._style["cc"],
1568
+ ]
1569
+ # To fold box onto next lines, draw it repeatedly, shifting
1570
+ # it left by x_shift and down by y_shift
1571
+ fold_level = 0
1572
+ end_x = xpos + box_width
1573
+
1574
+ while end_x > 0.0:
1575
+ x_shift = fold_level * self._fold
1576
+ y_shift = fold_level * (glob_data["n_lines"] + 1)
1577
+ end_x = xpos + box_width - x_shift if self._fold > 0 else 0.0
1578
+
1579
+ if isinstance(node.op, IfElseOp):
1580
+ flow_text = " If"
1581
+ elif isinstance(node.op, WhileLoopOp):
1582
+ flow_text = " While"
1583
+ elif isinstance(node.op, ForLoopOp):
1584
+ flow_text = " For"
1585
+ elif isinstance(node.op, SwitchCaseOp):
1586
+ flow_text = "Switch"
1587
+ elif isinstance(node.op, BoxOp):
1588
+ flow_text = ""
1589
+ else:
1590
+ raise RuntimeError(f"unhandled control-flow op: {node.name}")
1591
+
1592
+ # Some spacers. op_spacer moves 'Switch' back a bit for alignment,
1593
+ # expr_spacer moves the expr over to line up with 'Switch' and
1594
+ # empty_default_spacer makes the switch box longer if the default
1595
+ # case is empty so text doesn't run past end of box.
1596
+ if isinstance(node.op, SwitchCaseOp):
1597
+ op_spacer = 0.04
1598
+ expr_spacer = 0.0
1599
+ empty_default_spacer = 0.3 if len(node.op.blocks[-1]) == 0 else 0.0
1600
+ elif isinstance(node.op, BoxOp):
1601
+ op_spacer = 0.0
1602
+ expr_spacer = 0.0
1603
+ empty_default_spacer = 0.0
1604
+ else:
1605
+ op_spacer = 0.08
1606
+ expr_spacer = 0.02
1607
+ empty_default_spacer = 0.0
1608
+
1609
+ # FancyBbox allows rounded corners
1610
+ box = glob_data["patches_mod"].FancyBboxPatch(
1611
+ xy=(xpos - x_shift, ypos - 0.5 * HIG - y_shift),
1612
+ width=box_width + empty_default_spacer,
1613
+ height=height,
1614
+ boxstyle="round, pad=0.1",
1615
+ fc="none",
1616
+ ec=colors[node_data[node].nest_depth % 4],
1617
+ linewidth=self._lwidth3,
1618
+ zorder=PORDER_FLOW,
1619
+ )
1620
+ self._ax.add_patch(box)
1621
+
1622
+ # Indicate type of ControlFlowOp and if expression used, print below
1623
+ self._ax.text(
1624
+ xpos - x_shift - op_spacer,
1625
+ ypos_max + 0.2 - y_shift,
1626
+ flow_text,
1627
+ ha="left",
1628
+ va="center",
1629
+ fontsize=self._style["fs"],
1630
+ color=node_data[node].tc,
1631
+ clip_on=True,
1632
+ zorder=PORDER_FLOW,
1633
+ )
1634
+ self._ax.text(
1635
+ xpos - x_shift + expr_spacer,
1636
+ ypos_max + 0.2 - y_shift - 0.4,
1637
+ node_data[node].expr_text,
1638
+ ha="left",
1639
+ va="center",
1640
+ fontsize=self._style["sfs"],
1641
+ color=node_data[node].tc,
1642
+ clip_on=True,
1643
+ zorder=PORDER_FLOW,
1644
+ )
1645
+ if isinstance(node.op, ForLoopOp):
1646
+ idx_set = str(node_data[node].indexset)
1647
+ # If a range was used display 'range' and grab the range value
1648
+ # to be displayed below
1649
+ if "range" in idx_set:
1650
+ idx_set = "r(" + idx_set[6:-1] + ")"
1651
+ else:
1652
+ # If a tuple, show first 4 elements followed by '...'
1653
+ idx_set = str(node_data[node].indexset)[1:-1].split(",")[:5]
1654
+ if len(idx_set) > 4:
1655
+ idx_set[4] = "..."
1656
+ idx_set = f"{','.join(idx_set)}"
1657
+ y_spacer = 0.2 if len(node.qargs) == 1 else 0.5
1658
+ self._ax.text(
1659
+ xpos - x_shift - 0.04,
1660
+ ypos_max - y_spacer - y_shift,
1661
+ idx_set,
1662
+ ha="left",
1663
+ va="center",
1664
+ fontsize=self._style["sfs"],
1665
+ color=node_data[node].tc,
1666
+ clip_on=True,
1667
+ zorder=PORDER_FLOW,
1668
+ )
1669
+ # If there's an else or a case draw the vertical line and the name
1670
+ else_case_text = "Else" if isinstance(node.op, IfElseOp) else "Case"
1671
+ ewidth_incr = if_width
1672
+ for circ_num, ewidth in enumerate(node_data[node].width[1:]):
1673
+ if ewidth > 0.0:
1674
+ self._ax.plot(
1675
+ [xpos + ewidth_incr + 0.3 - x_shift, xpos + ewidth_incr + 0.3 - x_shift],
1676
+ [ypos - 0.5 * HIG - 0.08 - y_shift, ypos + height - 0.22 - y_shift],
1677
+ color=colors[node_data[node].nest_depth % 4],
1678
+ linewidth=3.0,
1679
+ linestyle="solid",
1680
+ zorder=PORDER_FLOW,
1681
+ )
1682
+ self._ax.text(
1683
+ xpos + ewidth_incr + 0.4 - x_shift,
1684
+ ypos_max + 0.2 - y_shift,
1685
+ else_case_text,
1686
+ ha="left",
1687
+ va="center",
1688
+ fontsize=self._style["fs"],
1689
+ color=node_data[node].tc,
1690
+ clip_on=True,
1691
+ zorder=PORDER_FLOW,
1692
+ )
1693
+ if isinstance(node.op, SwitchCaseOp):
1694
+ jump_val = node_data[node].jump_values[circ_num]
1695
+ # If only one value, e.g. (0,)
1696
+ if len(str(jump_val)) == 4:
1697
+ jump_text = str(jump_val)[1]
1698
+ elif "default" in str(jump_val):
1699
+ jump_text = "default"
1700
+ else:
1701
+ # If a tuple, show first 4 elements followed by '...'
1702
+ jump_text = str(jump_val)[1:-1].replace(" ", "").split(",")[:5]
1703
+ if len(jump_text) > 4:
1704
+ jump_text[4] = "..."
1705
+ jump_text = f"{', '.join(jump_text)}"
1706
+ y_spacer = 0.2 if len(node.qargs) == 1 else 0.5
1707
+ self._ax.text(
1708
+ xpos + ewidth_incr + 0.4 - x_shift,
1709
+ ypos_max - y_spacer - y_shift,
1710
+ jump_text,
1711
+ ha="left",
1712
+ va="center",
1713
+ fontsize=self._style["sfs"],
1714
+ color=node_data[node].tc,
1715
+ clip_on=True,
1716
+ zorder=PORDER_FLOW,
1717
+ )
1718
+ ewidth_incr += ewidth + 1
1719
+
1720
+ fold_level += 1
1721
+
1722
+ def _control_gate(self, node, node_data, glob_data, mod_control):
1723
+ """Draw a controlled gate"""
1724
+ op = node.op
1725
+ xy = node_data[node].q_xy
1726
+ base_type = getattr(op, "base_gate", None)
1727
+ qubit_b = min(xy, key=lambda xy: xy[1])
1728
+ qubit_t = max(xy, key=lambda xy: xy[1])
1729
+ num_ctrl_qubits = mod_control.num_ctrl_qubits if mod_control else op.num_ctrl_qubits
1730
+ num_qargs = len(xy) - num_ctrl_qubits
1731
+ ctrl_state = mod_control.ctrl_state if mod_control else op.ctrl_state
1732
+ self._set_ctrl_bits(
1733
+ ctrl_state,
1734
+ num_ctrl_qubits,
1735
+ xy,
1736
+ glob_data,
1737
+ ec=node_data[node].ec,
1738
+ tc=node_data[node].tc,
1739
+ text=node_data[node].ctrl_text,
1740
+ qargs=node.qargs,
1741
+ )
1742
+ self._line(qubit_b, qubit_t, lc=node_data[node].lc)
1743
+
1744
+ if isinstance(op, RZZGate) or isinstance(base_type, (U1Gate, PhaseGate, ZGate, RZZGate)):
1745
+ self._symmetric_gate(node, node_data, base_type, glob_data)
1746
+
1747
+ elif num_qargs == 1 and isinstance(base_type, XGate):
1748
+ tgt_color = self._style["dispcol"]["target"]
1749
+ tgt = tgt_color if isinstance(tgt_color, str) else tgt_color[0]
1750
+ self._x_tgt_qubit(xy[num_ctrl_qubits], glob_data, ec=node_data[node].ec, ac=tgt)
1751
+
1752
+ elif num_qargs == 1:
1753
+ self._gate(node, node_data, glob_data, xy[num_ctrl_qubits:][0])
1754
+
1755
+ elif isinstance(base_type, SwapGate):
1756
+ self._swap(xy[num_ctrl_qubits:], node_data[node].lc)
1757
+
1758
+ else:
1759
+ self._multiqubit_gate(node, node_data, glob_data, xy[num_ctrl_qubits:])
1760
+
1761
+ def _set_ctrl_bits(
1762
+ self, ctrl_state, num_ctrl_qubits, qbit, glob_data, ec=None, tc=None, text="", qargs=None
1763
+ ):
1764
+ """Determine which qubits are controls and whether they are open or closed"""
1765
+ # place the control label at the top or bottom of controls
1766
+ if text:
1767
+ qlist = [self._circuit.find_bit(qubit).index for qubit in qargs]
1768
+ ctbits = qlist[:num_ctrl_qubits]
1769
+ qubits = qlist[num_ctrl_qubits:]
1770
+ max_ctbit = max(ctbits)
1771
+ min_ctbit = min(ctbits)
1772
+ top = min(qubits) > min_ctbit
1773
+
1774
+ # display the control qubits as open or closed based on ctrl_state
1775
+ cstate = f"{ctrl_state:b}".rjust(num_ctrl_qubits, "0")[::-1]
1776
+ for i in range(num_ctrl_qubits):
1777
+ fc_open_close = ec if cstate[i] == "1" else self._style["bg"]
1778
+ text_top = None
1779
+ if text:
1780
+ if top and qlist[i] == min_ctbit:
1781
+ text_top = True
1782
+ elif not top and qlist[i] == max_ctbit:
1783
+ text_top = False
1784
+ self._ctrl_qubit(
1785
+ qbit[i], glob_data, fc=fc_open_close, ec=ec, tc=tc, text=text, text_top=text_top
1786
+ )
1787
+
1788
+ def _ctrl_qubit(self, xy, glob_data, fc=None, ec=None, tc=None, text="", text_top=None):
1789
+ """Draw a control circle and if top or bottom control, draw control label"""
1790
+ xpos, ypos = xy
1791
+ box = glob_data["patches_mod"].Circle(
1792
+ xy=(xpos, ypos),
1793
+ radius=WID * 0.15,
1794
+ fc=fc,
1795
+ ec=ec,
1796
+ linewidth=self._lwidth15,
1797
+ zorder=PORDER_GATE,
1798
+ )
1799
+ self._ax.add_patch(box)
1800
+
1801
+ # adjust label height according to number of lines of text
1802
+ label_padding = 0.7
1803
+ if text is not None:
1804
+ text_lines = text.count("\n")
1805
+ if not text.endswith("(cal)\n"):
1806
+ for _ in range(text_lines):
1807
+ label_padding += 0.3
1808
+
1809
+ if text_top is None:
1810
+ return
1811
+
1812
+ # display the control label at the top or bottom if there is one
1813
+ ctrl_ypos = ypos + label_padding * HIG if text_top else ypos - 0.3 * HIG
1814
+ self._ax.text(
1815
+ xpos,
1816
+ ctrl_ypos,
1817
+ text,
1818
+ ha="center",
1819
+ va="top",
1820
+ fontsize=self._style["sfs"],
1821
+ color=tc,
1822
+ clip_on=True,
1823
+ zorder=PORDER_TEXT,
1824
+ )
1825
+
1826
+ def _x_tgt_qubit(self, xy, glob_data, ec=None, ac=None):
1827
+ """Draw the cnot target symbol"""
1828
+ linewidth = self._lwidth2
1829
+ xpos, ypos = xy
1830
+ box = glob_data["patches_mod"].Circle(
1831
+ xy=(xpos, ypos),
1832
+ radius=HIG * 0.35,
1833
+ fc=ec,
1834
+ ec=ec,
1835
+ linewidth=linewidth,
1836
+ zorder=PORDER_GATE,
1837
+ )
1838
+ self._ax.add_patch(box)
1839
+
1840
+ # add '+' symbol
1841
+ self._ax.plot(
1842
+ [xpos, xpos],
1843
+ [ypos - 0.2 * HIG, ypos + 0.2 * HIG],
1844
+ color=ac,
1845
+ linewidth=linewidth,
1846
+ zorder=PORDER_GATE_PLUS,
1847
+ )
1848
+ self._ax.plot(
1849
+ [xpos - 0.2 * HIG, xpos + 0.2 * HIG],
1850
+ [ypos, ypos],
1851
+ color=ac,
1852
+ linewidth=linewidth,
1853
+ zorder=PORDER_GATE_PLUS,
1854
+ )
1855
+
1856
+ def _symmetric_gate(self, node, node_data, base_type, glob_data):
1857
+ """Draw symmetric gates for cz, cu1, cp, and rzz"""
1858
+ op = node.op
1859
+ xy = node_data[node].q_xy
1860
+ qubit_b = min(xy, key=lambda xy: xy[1])
1861
+ qubit_t = max(xy, key=lambda xy: xy[1])
1862
+ base_type = getattr(op, "base_gate", None)
1863
+ ec = node_data[node].ec
1864
+ tc = node_data[node].tc
1865
+ lc = node_data[node].lc
1866
+
1867
+ # cz and mcz gates
1868
+ if not isinstance(op, ZGate) and isinstance(base_type, ZGate):
1869
+ num_ctrl_qubits = op.num_ctrl_qubits
1870
+ self._ctrl_qubit(xy[-1], glob_data, fc=ec, ec=ec, tc=tc)
1871
+ self._line(qubit_b, qubit_t, lc=lc, zorder=PORDER_LINE_PLUS)
1872
+
1873
+ # cu1, cp, rzz, and controlled rzz gates (sidetext gates)
1874
+ elif isinstance(op, RZZGate) or isinstance(base_type, (U1Gate, PhaseGate, RZZGate)):
1875
+ num_ctrl_qubits = 0 if isinstance(op, RZZGate) else op.num_ctrl_qubits
1876
+ gate_text = "P" if isinstance(base_type, PhaseGate) else node_data[node].gate_text
1877
+
1878
+ self._ctrl_qubit(xy[num_ctrl_qubits], glob_data, fc=ec, ec=ec, tc=tc)
1879
+ if not isinstance(base_type, (U1Gate, PhaseGate)):
1880
+ self._ctrl_qubit(xy[num_ctrl_qubits + 1], glob_data, fc=ec, ec=ec, tc=tc)
1881
+
1882
+ self._sidetext(
1883
+ node,
1884
+ node_data,
1885
+ qubit_b,
1886
+ tc=tc,
1887
+ text=f"{gate_text} ({node_data[node].param_text})",
1888
+ )
1889
+ self._line(qubit_b, qubit_t, lc=lc)
1890
+
1891
+ def _swap(self, xy, color=None):
1892
+ """Draw a Swap gate"""
1893
+ self._swap_cross(xy[0], color=color)
1894
+ self._swap_cross(xy[1], color=color)
1895
+ self._line(xy[0], xy[1], lc=color)
1896
+
1897
+ def _swap_cross(self, xy, color=None):
1898
+ """Draw the Swap cross symbol"""
1899
+ xpos, ypos = xy
1900
+
1901
+ self._ax.plot(
1902
+ [xpos - 0.20 * WID, xpos + 0.20 * WID],
1903
+ [ypos - 0.20 * WID, ypos + 0.20 * WID],
1904
+ color=color,
1905
+ linewidth=self._lwidth2,
1906
+ zorder=PORDER_LINE_PLUS,
1907
+ )
1908
+ self._ax.plot(
1909
+ [xpos - 0.20 * WID, xpos + 0.20 * WID],
1910
+ [ypos + 0.20 * WID, ypos - 0.20 * WID],
1911
+ color=color,
1912
+ linewidth=self._lwidth2,
1913
+ zorder=PORDER_LINE_PLUS,
1914
+ )
1915
+
1916
+ def _sidetext(self, node, node_data, xy, tc=None, text=""):
1917
+ """Draw the sidetext for symmetric gates"""
1918
+ xpos, ypos = xy
1919
+
1920
+ # 0.11 = the initial gap, add 1/2 text width to place on the right
1921
+ xp = xpos + 0.11 + node_data[node].width / 2
1922
+ self._ax.text(
1923
+ xp,
1924
+ ypos + HIG,
1925
+ text,
1926
+ ha="center",
1927
+ va="top",
1928
+ fontsize=self._style["sfs"],
1929
+ color=tc,
1930
+ clip_on=True,
1931
+ zorder=PORDER_TEXT,
1932
+ )
1933
+
1934
+ def _line(self, xy0, xy1, lc=None, ls=None, zorder=PORDER_LINE):
1935
+ """Draw a line from xy0 to xy1"""
1936
+ x0, y0 = xy0
1937
+ x1, y1 = xy1
1938
+ linecolor = self._style["lc"] if lc is None else lc
1939
+ linestyle = "solid" if ls is None else ls
1940
+
1941
+ if linestyle == "doublet":
1942
+ theta = np.arctan2(np.abs(x1 - x0), np.abs(y1 - y0))
1943
+ dx = 0.05 * WID * np.cos(theta)
1944
+ dy = 0.05 * WID * np.sin(theta)
1945
+ self._ax.plot(
1946
+ [x0 + dx, x1 + dx],
1947
+ [y0 + dy, y1 + dy],
1948
+ color=linecolor,
1949
+ linewidth=self._lwidth2,
1950
+ linestyle="solid",
1951
+ zorder=zorder,
1952
+ )
1953
+ self._ax.plot(
1954
+ [x0 - dx, x1 - dx],
1955
+ [y0 - dy, y1 - dy],
1956
+ color=linecolor,
1957
+ linewidth=self._lwidth2,
1958
+ linestyle="solid",
1959
+ zorder=zorder,
1960
+ )
1961
+ else:
1962
+ self._ax.plot(
1963
+ [x0, x1],
1964
+ [y0, y1],
1965
+ color=linecolor,
1966
+ linewidth=self._lwidth2,
1967
+ linestyle=linestyle,
1968
+ zorder=zorder,
1969
+ )
1970
+
1971
+ def _plot_coord(self, x_index, y_index, gate_width, glob_data, flow_op=False):
1972
+ """Get the coord positions for an index"""
1973
+
1974
+ # Check folding
1975
+ fold = self._fold if self._fold > 0 else INFINITE_FOLD
1976
+ h_pos = x_index % fold + 1
1977
+
1978
+ # Don't fold flow_ops here, only gates inside the flow_op
1979
+ if not flow_op and h_pos + (gate_width - 1) > fold:
1980
+ x_index += fold - (h_pos - 1)
1981
+ x_pos = x_index % fold + glob_data["x_offset"] + 0.04
1982
+ if not flow_op:
1983
+ x_pos += 0.5 * gate_width
1984
+ else:
1985
+ x_pos += 0.25
1986
+ y_pos = y_index - (x_index // fold) * (glob_data["n_lines"] + 1)
1987
+
1988
+ # x_index could have been updated, so need to store
1989
+ glob_data["next_x_index"] = x_index
1990
+ return x_pos, y_pos
1991
+
1992
+
1993
+ class NodeData:
1994
+ """Class containing drawing data on a per node basis"""
1995
+
1996
+ def __init__(self):
1997
+ # Node data for positioning
1998
+ self.width = 0.0
1999
+ self.x_index = 0
2000
+ self.q_xy = []
2001
+ self.c_xy = []
2002
+
2003
+ # Node data for text
2004
+ self.gate_text = ""
2005
+ self.raw_gate_text = ""
2006
+ self.ctrl_text = ""
2007
+ self.param_text = ""
2008
+
2009
+ # Node data for color
2010
+ self.fc = self.ec = self.lc = self.sc = self.gt = self.tc = 0
2011
+
2012
+ # Special values stored for ControlFlowOps
2013
+ self.nest_depth = 0
2014
+ self.expr_width = 0.0
2015
+ self.expr_text = ""
2016
+ self.inside_flow = False
2017
+ self.indexset = () # List of indices used for ForLoopOp
2018
+ self.jump_values = [] # List of jump values used for SwitchCaseOp
2019
+ self.circ_num = 0 # Which block is it in op.blocks