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