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