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,1849 @@
|
|
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
|
+
"""
|
14
|
+
A module for drawing circuits in ascii art or some other text representation
|
15
|
+
"""
|
16
|
+
|
17
|
+
from io import StringIO
|
18
|
+
from warnings import warn
|
19
|
+
from shutil import get_terminal_size
|
20
|
+
import collections
|
21
|
+
import sys
|
22
|
+
|
23
|
+
from qiskit.circuit import Qubit, Clbit, ClassicalRegister, CircuitError
|
24
|
+
from qiskit.circuit import ControlledGate, Reset, Measure
|
25
|
+
from qiskit.circuit import ControlFlowOp, WhileLoopOp, IfElseOp, ForLoopOp, SwitchCaseOp, BoxOp
|
26
|
+
from qiskit.circuit.classical import expr
|
27
|
+
from qiskit.circuit.controlflow import node_resources
|
28
|
+
from qiskit.circuit.library.standard_gates import IGate, RZZGate, SwapGate, SXGate, SXdgGate
|
29
|
+
from qiskit.circuit.annotated_operation import _canonicalize_modifiers, ControlModifier
|
30
|
+
from qiskit.circuit.tools.pi_check import pi_check
|
31
|
+
from qiskit.qasm3 import ast
|
32
|
+
from qiskit.qasm3.printer import BasicPrinter
|
33
|
+
from qiskit.qasm3.exporter import _ExprBuilder
|
34
|
+
|
35
|
+
from ._utils import (
|
36
|
+
get_gate_ctrl_text,
|
37
|
+
get_param_str,
|
38
|
+
get_wire_map,
|
39
|
+
get_bit_register,
|
40
|
+
get_bit_reg_index,
|
41
|
+
get_wire_label,
|
42
|
+
get_condition_label_val,
|
43
|
+
_get_layered_instructions,
|
44
|
+
)
|
45
|
+
from ..exceptions import VisualizationError
|
46
|
+
|
47
|
+
# Indicators for left, middle, and right of control flow gates
|
48
|
+
CF_LEFT = 0
|
49
|
+
CF_MID = 1
|
50
|
+
CF_RIGHT = 2
|
51
|
+
|
52
|
+
|
53
|
+
class TextDrawerEncodingError(VisualizationError):
|
54
|
+
"""A problem with encoding"""
|
55
|
+
|
56
|
+
pass
|
57
|
+
|
58
|
+
|
59
|
+
class DrawElement:
|
60
|
+
"""An element is an operation that needs to be drawn."""
|
61
|
+
|
62
|
+
def __init__(self, label=None):
|
63
|
+
self._width = None
|
64
|
+
self.label = self.mid_content = label
|
65
|
+
self.top_format = self.mid_format = self.bot_format = "%s"
|
66
|
+
self.top_connect = self.bot_connect = " "
|
67
|
+
self.top_pad = self._mid_padding = self.bot_pad = " "
|
68
|
+
self.mid_bck = self.top_bck = self.bot_bck = " "
|
69
|
+
self.bot_connector = {}
|
70
|
+
self.top_connector = {}
|
71
|
+
self.right_fill = self.left_fill = self.layer_width = 0
|
72
|
+
self.wire_label = ""
|
73
|
+
|
74
|
+
@property
|
75
|
+
def top(self):
|
76
|
+
"""Constructs the top line of the element"""
|
77
|
+
if (self.width % 2) == 0 and len(self.top_format) % 2 == 1 and len(self.top_connect) == 1:
|
78
|
+
ret = self.top_format % (self.top_pad + self.top_connect).center(
|
79
|
+
self.width, self.top_pad
|
80
|
+
)
|
81
|
+
else:
|
82
|
+
ret = self.top_format % self.top_connect.center(self.width, self.top_pad)
|
83
|
+
if self.right_fill:
|
84
|
+
ret = ret.ljust(self.right_fill, self.top_pad)
|
85
|
+
if self.left_fill:
|
86
|
+
ret = ret.rjust(self.left_fill, self.top_pad)
|
87
|
+
ret = ret.center(self.layer_width, self.top_bck)
|
88
|
+
return ret
|
89
|
+
|
90
|
+
@property
|
91
|
+
def mid(self):
|
92
|
+
"""Constructs the middle line of the element"""
|
93
|
+
ret = self.mid_format % self.mid_content.center(self.width, self._mid_padding)
|
94
|
+
if self.right_fill:
|
95
|
+
ret = ret.ljust(self.right_fill, self._mid_padding)
|
96
|
+
if self.left_fill:
|
97
|
+
ret = ret.rjust(self.left_fill, self._mid_padding)
|
98
|
+
ret = ret.center(self.layer_width, self.mid_bck)
|
99
|
+
return ret
|
100
|
+
|
101
|
+
@property
|
102
|
+
def bot(self):
|
103
|
+
"""Constructs the bottom line of the element"""
|
104
|
+
if (self.width % 2) == 0 and len(self.top_format) % 2 == 1:
|
105
|
+
ret = self.bot_format % (self.bot_pad + self.bot_connect).center(
|
106
|
+
self.width, self.bot_pad
|
107
|
+
)
|
108
|
+
else:
|
109
|
+
ret = self.bot_format % self.bot_connect.center(self.width, self.bot_pad)
|
110
|
+
if self.right_fill:
|
111
|
+
ret = ret.ljust(self.right_fill, self.bot_pad)
|
112
|
+
if self.left_fill:
|
113
|
+
ret = ret.rjust(self.left_fill, self.bot_pad)
|
114
|
+
ret = ret.center(self.layer_width, self.bot_bck)
|
115
|
+
return ret
|
116
|
+
|
117
|
+
@property
|
118
|
+
def length(self):
|
119
|
+
"""Returns the length of the element, including the box around."""
|
120
|
+
return max(len(self.top), len(self.mid), len(self.bot))
|
121
|
+
|
122
|
+
@property
|
123
|
+
def width(self):
|
124
|
+
"""Returns the width of the label, including padding"""
|
125
|
+
if self._width:
|
126
|
+
return self._width
|
127
|
+
return len(self.mid_content)
|
128
|
+
|
129
|
+
@width.setter
|
130
|
+
def width(self, value):
|
131
|
+
self._width = value
|
132
|
+
|
133
|
+
def connect(self, wire_char, where, label=None):
|
134
|
+
"""Connects boxes and elements using wire_char and setting proper connectors.
|
135
|
+
|
136
|
+
Args:
|
137
|
+
wire_char (char): For example '║' or '│'.
|
138
|
+
where (list["top", "bot"]): Where the connector should be set.
|
139
|
+
label (string): Some connectors have a label (see cu1, for example).
|
140
|
+
"""
|
141
|
+
|
142
|
+
if "top" in where and self.top_connector:
|
143
|
+
self.top_connect = self.top_connector[wire_char]
|
144
|
+
|
145
|
+
if "bot" in where and self.bot_connector:
|
146
|
+
self.bot_connect = self.bot_connector[wire_char]
|
147
|
+
|
148
|
+
if label:
|
149
|
+
self.top_format = self.top_format[:-1] + (label if label else "")
|
150
|
+
|
151
|
+
|
152
|
+
class BoxOnClWire(DrawElement):
|
153
|
+
"""Draws a box on the classical wire.
|
154
|
+
|
155
|
+
::
|
156
|
+
|
157
|
+
top: ┌───┐ ┌───┐
|
158
|
+
mid: ╡ A ╞ ══╡ A ╞══
|
159
|
+
bot: └───┘ └───┘
|
160
|
+
"""
|
161
|
+
|
162
|
+
def __init__(self, label="", top_connect="─", bot_connect="─"):
|
163
|
+
super().__init__(label)
|
164
|
+
self.top_format = "┌─%s─┐"
|
165
|
+
self.mid_format = "╡ %s ╞"
|
166
|
+
self.bot_format = "└─%s─┘"
|
167
|
+
self.top_pad = self.bot_pad = "─"
|
168
|
+
self.mid_bck = "═"
|
169
|
+
self.top_connect = top_connect
|
170
|
+
self.bot_connect = bot_connect
|
171
|
+
self.mid_content = label
|
172
|
+
|
173
|
+
|
174
|
+
class BoxOnQuWire(DrawElement):
|
175
|
+
"""Draws a box on the quantum wire.
|
176
|
+
|
177
|
+
::
|
178
|
+
|
179
|
+
top: ┌───┐ ┌───┐
|
180
|
+
mid: ┤ A ├ ──┤ A ├──
|
181
|
+
bot: └───┘ └───┘
|
182
|
+
"""
|
183
|
+
|
184
|
+
def __init__(self, label="", top_connect="─", conditional=False):
|
185
|
+
super().__init__(label)
|
186
|
+
self.top_format = "┌─%s─┐"
|
187
|
+
self.mid_format = "┤ %s ├"
|
188
|
+
self.bot_format = "└─%s─┘"
|
189
|
+
self.top_pad = self.bot_pad = self.mid_bck = "─"
|
190
|
+
self.top_connect = top_connect
|
191
|
+
self.bot_connect = "╥" if conditional else "─"
|
192
|
+
self.mid_content = label
|
193
|
+
self.top_connector = {"│": "┴"}
|
194
|
+
self.bot_connector = {"│": "┬"}
|
195
|
+
|
196
|
+
|
197
|
+
class MeasureTo(DrawElement):
|
198
|
+
"""The element on the classic wire to which the measure is performed.
|
199
|
+
|
200
|
+
::
|
201
|
+
|
202
|
+
top: ║ ║
|
203
|
+
mid: ═╩═ ═══╩═══
|
204
|
+
bot:
|
205
|
+
"""
|
206
|
+
|
207
|
+
def __init__(self, label=""):
|
208
|
+
super().__init__()
|
209
|
+
self.top_connect = " ║ "
|
210
|
+
self.mid_content = "═╩═"
|
211
|
+
self.bot_connect = label
|
212
|
+
self.mid_bck = "═"
|
213
|
+
|
214
|
+
|
215
|
+
class MeasureFrom(BoxOnQuWire):
|
216
|
+
"""The element on the quantum wire in which the measure is performed.
|
217
|
+
|
218
|
+
::
|
219
|
+
|
220
|
+
top: ┌─┐ ┌─┐
|
221
|
+
mid: ┤M├ ───┤M├───
|
222
|
+
bot: └╥┘ └╥┘
|
223
|
+
"""
|
224
|
+
|
225
|
+
def __init__(self):
|
226
|
+
super().__init__()
|
227
|
+
self.top_format = self.mid_format = self.bot_format = "%s"
|
228
|
+
self.top_connect = "┌─┐"
|
229
|
+
self.mid_content = "┤M├"
|
230
|
+
self.bot_connect = "└╥┘"
|
231
|
+
|
232
|
+
self.top_pad = self.bot_pad = " "
|
233
|
+
self._mid_padding = "─"
|
234
|
+
|
235
|
+
|
236
|
+
class MultiBox(DrawElement):
|
237
|
+
"""Elements that are drawn over multiple wires."""
|
238
|
+
|
239
|
+
def center_label(self, input_length, order):
|
240
|
+
"""In multi-bit elements, the label is centered vertically.
|
241
|
+
|
242
|
+
Args:
|
243
|
+
input_length (int): Rhe amount of wires affected.
|
244
|
+
order (int): Which middle element is this one?
|
245
|
+
"""
|
246
|
+
if input_length == order == 0:
|
247
|
+
self.top_connect = self.label
|
248
|
+
return
|
249
|
+
location_in_the_box = "*".center(input_length * 2 - 1).index("*") + 1
|
250
|
+
top_limit = order * 2 + 2
|
251
|
+
bot_limit = top_limit + 2
|
252
|
+
if top_limit <= location_in_the_box < bot_limit:
|
253
|
+
if location_in_the_box == top_limit:
|
254
|
+
self.top_connect = self.label
|
255
|
+
elif location_in_the_box == top_limit + 1:
|
256
|
+
self.mid_content = self.label
|
257
|
+
else:
|
258
|
+
self.bot_connect = self.label
|
259
|
+
|
260
|
+
@property
|
261
|
+
def width(self):
|
262
|
+
"""Returns the width of the label, including padding"""
|
263
|
+
if self._width:
|
264
|
+
return self._width
|
265
|
+
return len(self.label)
|
266
|
+
|
267
|
+
|
268
|
+
class BoxOnQuWireTop(MultiBox, BoxOnQuWire):
|
269
|
+
"""Draws the top part of a box that affects more than one quantum wire"""
|
270
|
+
|
271
|
+
def __init__(self, label="", top_connect=None, wire_label=""):
|
272
|
+
super().__init__(label)
|
273
|
+
self.wire_label = wire_label
|
274
|
+
self.bot_connect = self.bot_pad = " "
|
275
|
+
self.mid_content = "" # The label will be put by some other part of the box.
|
276
|
+
self.left_fill = len(self.wire_label)
|
277
|
+
self.top_format = "┌─" + "s".center(self.left_fill + 1, "─") + "─┐"
|
278
|
+
self.top_format = self.top_format.replace("s", "%s")
|
279
|
+
self.mid_format = f"┤{self.wire_label} %s ├"
|
280
|
+
self.bot_format = f"│{self.bot_pad * self.left_fill} %s │"
|
281
|
+
self.top_connect = top_connect if top_connect else "─"
|
282
|
+
|
283
|
+
|
284
|
+
class BoxOnWireMid(MultiBox):
|
285
|
+
"""A generic middle box"""
|
286
|
+
|
287
|
+
def __init__(self, label, input_length, order, wire_label=""):
|
288
|
+
super().__init__(label)
|
289
|
+
self.top_pad = self.bot_pad = self.top_connect = self.bot_connect = " "
|
290
|
+
self.wire_label = wire_label
|
291
|
+
self.left_fill = len(self.wire_label)
|
292
|
+
self.top_format = f"│{self.top_pad * self.left_fill} %s │"
|
293
|
+
self.bot_format = f"│{self.bot_pad * self.left_fill} %s │"
|
294
|
+
self.top_connect = self.bot_connect = self.mid_content = ""
|
295
|
+
self.center_label(input_length, order)
|
296
|
+
|
297
|
+
|
298
|
+
class BoxOnQuWireMid(BoxOnWireMid, BoxOnQuWire):
|
299
|
+
"""Draws the middle part of a box that affects more than one quantum wire"""
|
300
|
+
|
301
|
+
def __init__(self, label, input_length, order, wire_label="", control_label=None):
|
302
|
+
super().__init__(label, input_length, order, wire_label=wire_label)
|
303
|
+
if control_label:
|
304
|
+
self.mid_format = f"{control_label}{self.wire_label} %s ├"
|
305
|
+
else:
|
306
|
+
self.mid_format = f"┤{self.wire_label} %s ├"
|
307
|
+
|
308
|
+
|
309
|
+
class BoxOnQuWireBot(MultiBox, BoxOnQuWire):
|
310
|
+
"""Draws the bottom part of a box that affects more than one quantum wire"""
|
311
|
+
|
312
|
+
def __init__(self, label, input_length, bot_connect=None, wire_label="", conditional=False):
|
313
|
+
super().__init__(label)
|
314
|
+
self.wire_label = wire_label
|
315
|
+
self.top_pad = " "
|
316
|
+
self.left_fill = len(self.wire_label)
|
317
|
+
self.top_format = f"│{self.top_pad * self.left_fill} %s │"
|
318
|
+
self.mid_format = f"┤{self.wire_label} %s ├"
|
319
|
+
self.bot_format = "└─" + "s".center(self.left_fill + 1, "─") + "─┘"
|
320
|
+
self.bot_format = self.bot_format.replace("s", "%s")
|
321
|
+
bot_connect = bot_connect if bot_connect else "─"
|
322
|
+
self.bot_connect = "╥" if conditional else bot_connect
|
323
|
+
|
324
|
+
self.mid_content = self.top_connect = ""
|
325
|
+
if input_length <= 2:
|
326
|
+
self.top_connect = label
|
327
|
+
|
328
|
+
|
329
|
+
class FlowOnQuWire(DrawElement):
|
330
|
+
"""Draws a box for a ControlFlowOp using a single qubit."""
|
331
|
+
|
332
|
+
def __init__(self, section, label="", top_connect="─", conditional=False):
|
333
|
+
super().__init__(label)
|
334
|
+
if section == CF_RIGHT:
|
335
|
+
self.top_format = " ─%s─┐"
|
336
|
+
self.mid_format = " %s ├"
|
337
|
+
self.bot_format = " ─%s─┘"
|
338
|
+
else:
|
339
|
+
self.top_format = "┌─%s─ "
|
340
|
+
self.mid_format = "┤ %s "
|
341
|
+
self.bot_format = "└─%s─ "
|
342
|
+
self.top_pad = self.bot_pad = self.mid_bck = "─"
|
343
|
+
self.top_connect = top_connect
|
344
|
+
self.bot_connect = "╥" if conditional else "─"
|
345
|
+
self.mid_content = label
|
346
|
+
self.top_connector = {"│": "┴"}
|
347
|
+
self.bot_connector = {"│": "┬"}
|
348
|
+
|
349
|
+
|
350
|
+
class FlowOnQuWireTop(MultiBox, BoxOnQuWire):
|
351
|
+
"""Draws the top of a box for a ControlFlowOp that uses more than one qubit."""
|
352
|
+
|
353
|
+
def __init__(self, section, label="", top_connect=None, wire_label=""):
|
354
|
+
super().__init__(label)
|
355
|
+
self.wire_label = wire_label
|
356
|
+
self.bot_connect = self.bot_pad = " "
|
357
|
+
self.mid_content = "" # The label will be put by some other part of the box.
|
358
|
+
self.left_fill = len(self.wire_label)
|
359
|
+
if section == CF_RIGHT:
|
360
|
+
self.top_format = "s".center(self.left_fill + 2, "─") + "─┐"
|
361
|
+
self.top_format = self.top_format.replace("s", "%s")
|
362
|
+
self.mid_format = f" {self.wire_label} %s ├"
|
363
|
+
self.bot_format = f" {self.bot_pad * self.left_fill} %s │"
|
364
|
+
else:
|
365
|
+
self.top_format = "┌─" + "s".center(self.left_fill + 2, "─") + " "
|
366
|
+
self.top_format = self.top_format.replace("s", "%s")
|
367
|
+
self.mid_format = f"┤{self.wire_label} %s "
|
368
|
+
self.bot_format = f"│{self.bot_pad * self.left_fill} %s "
|
369
|
+
self.top_connect = top_connect if top_connect else "─"
|
370
|
+
|
371
|
+
|
372
|
+
class FlowOnQuWireMid(MultiBox, BoxOnQuWire):
|
373
|
+
"""Draws the middle of a box for a ControlFlowOp that uses more than one qubit."""
|
374
|
+
|
375
|
+
def __init__(self, section, label, input_length, order, wire_label=""):
|
376
|
+
super().__init__(label)
|
377
|
+
self.top_pad = self.bot_pad = self.top_connect = self.bot_connect = " "
|
378
|
+
self.wire_label = wire_label
|
379
|
+
self.left_fill = len(self.wire_label)
|
380
|
+
if section == CF_RIGHT:
|
381
|
+
self.top_format = f" {self.top_pad * self.left_fill} %s │"
|
382
|
+
self.bot_format = f" {self.bot_pad * self.left_fill} %s │"
|
383
|
+
self.mid_format = f" {self.wire_label} %s ├"
|
384
|
+
else:
|
385
|
+
self.top_format = f"│{self.top_pad * self.left_fill} %s "
|
386
|
+
self.bot_format = f"│{self.bot_pad * self.left_fill} %s "
|
387
|
+
self.mid_format = f"┤{self.wire_label} %s "
|
388
|
+
self.top_connect = self.bot_connect = self.mid_content = ""
|
389
|
+
self.center_label(input_length, order)
|
390
|
+
|
391
|
+
|
392
|
+
class FlowOnQuWireBot(MultiBox, BoxOnQuWire):
|
393
|
+
"""Draws the bottom of a box for a ControlFlowOp that uses more than one qubit."""
|
394
|
+
|
395
|
+
def __init__(
|
396
|
+
self,
|
397
|
+
section,
|
398
|
+
label,
|
399
|
+
input_length,
|
400
|
+
bot_connect=None,
|
401
|
+
wire_label="",
|
402
|
+
conditional=False,
|
403
|
+
):
|
404
|
+
super().__init__(label)
|
405
|
+
self.wire_label = wire_label
|
406
|
+
self.top_pad = " "
|
407
|
+
self.left_fill = len(self.wire_label)
|
408
|
+
if section == CF_RIGHT:
|
409
|
+
self.top_format = f" {self.top_pad * self.left_fill} %s │"
|
410
|
+
self.mid_format = f" {self.wire_label} %s ├"
|
411
|
+
self.bot_format = " " + "s".center(self.left_fill + 2, "─") + "─┘"
|
412
|
+
self.bot_format = self.bot_format.replace("s", "%s")
|
413
|
+
else:
|
414
|
+
self.top_format = f"│{self.top_pad * self.left_fill} %s "
|
415
|
+
self.mid_format = f"┤{self.wire_label} %s "
|
416
|
+
self.bot_format = "└─" + "s".center(self.left_fill + 2, "─") + " "
|
417
|
+
self.bot_format = self.bot_format.replace("s", "%s")
|
418
|
+
bot_connect = bot_connect if bot_connect else "─"
|
419
|
+
self.bot_connect = "╥" if conditional else bot_connect
|
420
|
+
|
421
|
+
self.mid_content = self.top_connect = ""
|
422
|
+
if input_length <= 2:
|
423
|
+
self.top_connect = label
|
424
|
+
|
425
|
+
|
426
|
+
class BoxOnClWireTop(MultiBox, BoxOnClWire):
|
427
|
+
"""Draws the top part of a conditional box that affects more than one classical wire"""
|
428
|
+
|
429
|
+
def __init__(self, label="", top_connect=None, wire_label=""):
|
430
|
+
super().__init__(label)
|
431
|
+
self.wire_label = wire_label
|
432
|
+
self.mid_content = "" # The label will be put by some other part of the box.
|
433
|
+
self.bot_format = "│ %s │"
|
434
|
+
self.top_connect = top_connect if top_connect else "─"
|
435
|
+
self.bot_connect = self.bot_pad = " "
|
436
|
+
|
437
|
+
|
438
|
+
class BoxOnClWireMid(BoxOnWireMid, BoxOnClWire):
|
439
|
+
"""Draws the middle part of a conditional box that affects more than one classical wire"""
|
440
|
+
|
441
|
+
def __init__(self, label, input_length, order, wire_label="", **_):
|
442
|
+
super().__init__(label, input_length, order, wire_label=wire_label)
|
443
|
+
self.mid_format = f"╡{self.wire_label} %s ╞"
|
444
|
+
|
445
|
+
|
446
|
+
class BoxOnClWireBot(MultiBox, BoxOnClWire):
|
447
|
+
"""Draws the bottom part of a conditional box that affects more than one classical wire"""
|
448
|
+
|
449
|
+
def __init__(self, label, input_length, bot_connect="─", wire_label="", **_):
|
450
|
+
super().__init__(label)
|
451
|
+
self.wire_label = wire_label
|
452
|
+
self.left_fill = len(self.wire_label)
|
453
|
+
self.top_pad = " "
|
454
|
+
self.bot_pad = "─"
|
455
|
+
self.top_format = f"│{self.top_pad * self.left_fill} %s │"
|
456
|
+
self.mid_format = f"╡{self.wire_label} %s ╞"
|
457
|
+
self.bot_format = "└─" + "s".center(self.left_fill + 1, "─") + "─┘"
|
458
|
+
self.bot_format = self.bot_format.replace("s", "%s")
|
459
|
+
bot_connect = bot_connect if bot_connect else "─"
|
460
|
+
self.bot_connect = bot_connect
|
461
|
+
|
462
|
+
self.mid_content = self.top_connect = ""
|
463
|
+
if input_length <= 2:
|
464
|
+
self.top_connect = label
|
465
|
+
|
466
|
+
|
467
|
+
class DirectOnQuWire(DrawElement):
|
468
|
+
"""
|
469
|
+
Element to the wire (without the box).
|
470
|
+
"""
|
471
|
+
|
472
|
+
def __init__(self, label=""):
|
473
|
+
super().__init__(label)
|
474
|
+
self.top_format = " %s "
|
475
|
+
self.mid_format = "─%s─"
|
476
|
+
self.bot_format = " %s "
|
477
|
+
self._mid_padding = self.mid_bck = "─"
|
478
|
+
self.top_connector = {"│": "│", "║": "║"}
|
479
|
+
self.bot_connector = {"│": "│", "║": "║"}
|
480
|
+
|
481
|
+
|
482
|
+
class Barrier(DirectOnQuWire):
|
483
|
+
"""Draws a barrier with a label at the top if there is one.
|
484
|
+
|
485
|
+
::
|
486
|
+
|
487
|
+
top: ░ label
|
488
|
+
mid: ─░─ ───░───
|
489
|
+
bot: ░ ░
|
490
|
+
"""
|
491
|
+
|
492
|
+
def __init__(self, label=""):
|
493
|
+
super().__init__("░")
|
494
|
+
self.top_connect = label if label else "░"
|
495
|
+
self.bot_connect = "░"
|
496
|
+
self.top_connector = {}
|
497
|
+
self.bot_connector = {}
|
498
|
+
|
499
|
+
|
500
|
+
class Ex(DirectOnQuWire):
|
501
|
+
"""Draws an X (usually with a connector). E.g. the top part of a swap gate.
|
502
|
+
|
503
|
+
::
|
504
|
+
|
505
|
+
top:
|
506
|
+
mid: ─X─ ───X───
|
507
|
+
bot: │ │
|
508
|
+
"""
|
509
|
+
|
510
|
+
def __init__(self, bot_connect=" ", top_connect=" ", conditional=False):
|
511
|
+
super().__init__("X")
|
512
|
+
self.bot_connect = "║" if conditional else bot_connect
|
513
|
+
self.top_connect = top_connect
|
514
|
+
|
515
|
+
|
516
|
+
class ResetDisplay(DirectOnQuWire):
|
517
|
+
"""Draws a reset gate"""
|
518
|
+
|
519
|
+
def __init__(self, conditional=False):
|
520
|
+
super().__init__("|0>")
|
521
|
+
if conditional:
|
522
|
+
self.bot_connect = "║"
|
523
|
+
|
524
|
+
|
525
|
+
class Bullet(DirectOnQuWire):
|
526
|
+
"""Draws a bullet (usually with a connector). E.g. the top part of a CX gate.
|
527
|
+
|
528
|
+
::
|
529
|
+
|
530
|
+
top:
|
531
|
+
mid: ─■─ ───■───
|
532
|
+
bot: │ │
|
533
|
+
"""
|
534
|
+
|
535
|
+
def __init__(self, top_connect="", bot_connect="", conditional=False, label=None, bottom=False):
|
536
|
+
super().__init__("■")
|
537
|
+
self.conditional = conditional
|
538
|
+
self.top_connect = top_connect
|
539
|
+
self.bot_connect = "║" if conditional else bot_connect
|
540
|
+
if label and bottom:
|
541
|
+
self.bot_connect = label
|
542
|
+
elif label:
|
543
|
+
self.top_connect = label
|
544
|
+
self.mid_bck = "─"
|
545
|
+
|
546
|
+
|
547
|
+
class OpenBullet(DirectOnQuWire):
|
548
|
+
"""Draws an open bullet (usually with a connector). E.g. the top part of a CX gate.
|
549
|
+
|
550
|
+
::
|
551
|
+
|
552
|
+
top:
|
553
|
+
mid: ─o─ ───o───
|
554
|
+
bot: │ │
|
555
|
+
"""
|
556
|
+
|
557
|
+
def __init__(self, top_connect="", bot_connect="", conditional=False, label=None, bottom=False):
|
558
|
+
super().__init__("o")
|
559
|
+
self.conditional = conditional
|
560
|
+
self.top_connect = top_connect
|
561
|
+
self.bot_connect = "║" if conditional else bot_connect
|
562
|
+
if label and bottom:
|
563
|
+
self.bot_connect = label
|
564
|
+
elif label:
|
565
|
+
self.top_connect = label
|
566
|
+
self.mid_bck = "─"
|
567
|
+
|
568
|
+
|
569
|
+
class DirectOnClWire(DrawElement):
|
570
|
+
"""
|
571
|
+
Element to the classical wire (without the box).
|
572
|
+
"""
|
573
|
+
|
574
|
+
def __init__(self, label=""):
|
575
|
+
super().__init__(label)
|
576
|
+
self.top_format = " %s "
|
577
|
+
self.mid_format = "═%s═"
|
578
|
+
self.bot_format = " %s "
|
579
|
+
self._mid_padding = self.mid_bck = "═"
|
580
|
+
self.top_connector = {"│": "│", "║": "║"}
|
581
|
+
self.bot_connector = {"│": "│", "║": "║"}
|
582
|
+
|
583
|
+
|
584
|
+
class ClBullet(DirectOnClWire):
|
585
|
+
"""Draws a bullet on classical wire (usually with a connector). E.g. the top part of a CX gate.
|
586
|
+
|
587
|
+
::
|
588
|
+
|
589
|
+
top:
|
590
|
+
mid: ═■═ ═══■═══
|
591
|
+
bot: │ │
|
592
|
+
"""
|
593
|
+
|
594
|
+
def __init__(self, top_connect="", bot_connect="", conditional=False, label=None, bottom=False):
|
595
|
+
super().__init__("■")
|
596
|
+
self.top_connect = top_connect
|
597
|
+
self.bot_connect = "║" if conditional else bot_connect
|
598
|
+
if label and bottom:
|
599
|
+
self.bot_connect = label
|
600
|
+
elif label:
|
601
|
+
self.top_connect = label
|
602
|
+
self.mid_bck = "═"
|
603
|
+
|
604
|
+
|
605
|
+
class ClOpenBullet(DirectOnClWire):
|
606
|
+
"""Draws an open bullet on classical wire (usually with a connector). E.g. the top part of a CX gate.
|
607
|
+
|
608
|
+
::
|
609
|
+
|
610
|
+
top:
|
611
|
+
mid: ═o═ ═══o═══
|
612
|
+
bot: │ │
|
613
|
+
"""
|
614
|
+
|
615
|
+
def __init__(self, top_connect="", bot_connect="", conditional=False, label=None, bottom=False):
|
616
|
+
super().__init__("o")
|
617
|
+
self.top_connect = top_connect
|
618
|
+
self.bot_connect = "║" if conditional else bot_connect
|
619
|
+
if label and bottom:
|
620
|
+
self.bot_connect = label
|
621
|
+
elif label:
|
622
|
+
self.top_connect = label
|
623
|
+
self.mid_bck = "═"
|
624
|
+
|
625
|
+
|
626
|
+
class EmptyWire(DrawElement):
|
627
|
+
"""This element is just the wire, with no operations."""
|
628
|
+
|
629
|
+
def __init__(self, wire):
|
630
|
+
super().__init__(wire)
|
631
|
+
self._mid_padding = self.mid_bck = wire
|
632
|
+
|
633
|
+
@staticmethod
|
634
|
+
def fillup_layer(layer, first_clbit):
|
635
|
+
"""Given a layer, replace the Nones in it with EmptyWire elements.
|
636
|
+
|
637
|
+
Args:
|
638
|
+
layer (list): The layer that contains Nones.
|
639
|
+
first_clbit (int): The first wire that is classic.
|
640
|
+
|
641
|
+
Returns:
|
642
|
+
list: The new layer, with no Nones.
|
643
|
+
"""
|
644
|
+
for nones in [i for i, x in enumerate(layer) if x is None]:
|
645
|
+
layer[nones] = EmptyWire("═") if nones >= first_clbit else EmptyWire("─")
|
646
|
+
return layer
|
647
|
+
|
648
|
+
|
649
|
+
class BreakWire(DrawElement):
|
650
|
+
"""This element is used to break the drawing in several pages."""
|
651
|
+
|
652
|
+
def __init__(self, arrow_char):
|
653
|
+
super().__init__()
|
654
|
+
self.top_format = self.mid_format = self.bot_format = "%s"
|
655
|
+
self.top_connect = arrow_char
|
656
|
+
self.mid_content = arrow_char
|
657
|
+
self.bot_connect = arrow_char
|
658
|
+
|
659
|
+
@staticmethod
|
660
|
+
def fillup_layer(layer_length, arrow_char):
|
661
|
+
"""Creates a layer with BreakWire elements.
|
662
|
+
|
663
|
+
Args:
|
664
|
+
layer_length (int): The length of the layer to create
|
665
|
+
arrow_char (char): The char used to create the BreakWire element.
|
666
|
+
|
667
|
+
Returns:
|
668
|
+
list: The new layer.
|
669
|
+
"""
|
670
|
+
breakwire_layer = []
|
671
|
+
for _ in range(layer_length):
|
672
|
+
breakwire_layer.append(BreakWire(arrow_char))
|
673
|
+
return breakwire_layer
|
674
|
+
|
675
|
+
|
676
|
+
class InputWire(DrawElement):
|
677
|
+
"""This element is the label and the initial value of a wire."""
|
678
|
+
|
679
|
+
def __init__(self, label):
|
680
|
+
super().__init__(label)
|
681
|
+
|
682
|
+
@staticmethod
|
683
|
+
def fillup_layer(names):
|
684
|
+
"""Creates a layer with InputWire elements.
|
685
|
+
|
686
|
+
Args:
|
687
|
+
names (list): List of names for the wires.
|
688
|
+
|
689
|
+
Returns:
|
690
|
+
list: The new layer
|
691
|
+
"""
|
692
|
+
longest = max(len(name) for name in names)
|
693
|
+
inputs_wires = []
|
694
|
+
for name in names:
|
695
|
+
inputs_wires.append(InputWire(name.rjust(longest)))
|
696
|
+
return inputs_wires
|
697
|
+
|
698
|
+
|
699
|
+
class TextDrawing:
|
700
|
+
"""The text drawing"""
|
701
|
+
|
702
|
+
def __init__(
|
703
|
+
self,
|
704
|
+
qubits,
|
705
|
+
clbits,
|
706
|
+
nodes,
|
707
|
+
circuit,
|
708
|
+
reverse_bits=False,
|
709
|
+
plotbarriers=True,
|
710
|
+
line_length=None,
|
711
|
+
vertical_compression="high",
|
712
|
+
initial_state=True,
|
713
|
+
cregbundle=None,
|
714
|
+
encoding=None,
|
715
|
+
with_layout=False,
|
716
|
+
expr_len=30,
|
717
|
+
):
|
718
|
+
self.qubits = qubits
|
719
|
+
self.clbits = clbits
|
720
|
+
self.nodes = nodes
|
721
|
+
self._circuit = circuit
|
722
|
+
if with_layout:
|
723
|
+
if self._circuit._layout:
|
724
|
+
self.layout = self._circuit._layout.initial_layout
|
725
|
+
else:
|
726
|
+
self.layout = None
|
727
|
+
else:
|
728
|
+
self.layout = None
|
729
|
+
|
730
|
+
self.initial_state = initial_state
|
731
|
+
self.global_phase = circuit.global_phase
|
732
|
+
self.plotbarriers = plotbarriers
|
733
|
+
self.reverse_bits = reverse_bits
|
734
|
+
self.line_length = line_length
|
735
|
+
self.expr_len = expr_len
|
736
|
+
if vertical_compression not in ["high", "medium", "low"]:
|
737
|
+
raise ValueError("Vertical compression can only be 'high', 'medium', or 'low'")
|
738
|
+
self.vertical_compression = vertical_compression
|
739
|
+
self._wire_map = {}
|
740
|
+
self.cregbundle = cregbundle
|
741
|
+
|
742
|
+
self.encoding = encoding or sys.stdout.encoding or "utf8"
|
743
|
+
|
744
|
+
self._nest_depth = 0 # nesting depth for control flow ops
|
745
|
+
self._expr_text = "" # expression text to display
|
746
|
+
|
747
|
+
# Because jupyter calls both __repr__ and __repr_html__ for some backends,
|
748
|
+
# the entire drawer can be run twice which can result in different output
|
749
|
+
# for different backends. This var caches the output so the drawer only runs once.
|
750
|
+
self._single_string = ""
|
751
|
+
|
752
|
+
def __str__(self):
|
753
|
+
return self.single_string()
|
754
|
+
|
755
|
+
def _repr_html_(self):
|
756
|
+
return (
|
757
|
+
'<pre style="word-wrap: normal;'
|
758
|
+
"white-space: pre;"
|
759
|
+
"background: #fff0;"
|
760
|
+
"line-height: 1.1;"
|
761
|
+
'font-family: "Courier New",Courier,monospace">'
|
762
|
+
f"{self.single_string()}</pre>"
|
763
|
+
)
|
764
|
+
|
765
|
+
def __repr__(self):
|
766
|
+
return self.single_string()
|
767
|
+
|
768
|
+
def single_string(self):
|
769
|
+
"""Creates a long string with the ascii art.
|
770
|
+
Returns:
|
771
|
+
str: The lines joined by a newline (``\\n``)
|
772
|
+
"""
|
773
|
+
# Because jupyter calls both __repr__ and __repr_html__, this prevents the code
|
774
|
+
# from running twice.
|
775
|
+
if self._single_string:
|
776
|
+
return self._single_string
|
777
|
+
try:
|
778
|
+
self._single_string = (
|
779
|
+
"\n".join(self.lines()).encode(self.encoding).decode(self.encoding)
|
780
|
+
)
|
781
|
+
except (UnicodeEncodeError, UnicodeDecodeError):
|
782
|
+
warn(
|
783
|
+
f"The encoding {self.encoding} has a limited charset."
|
784
|
+
" Consider a different encoding in your "
|
785
|
+
"environment. UTF-8 is being used instead",
|
786
|
+
RuntimeWarning,
|
787
|
+
)
|
788
|
+
self.encoding = "utf-8"
|
789
|
+
self._single_string = (
|
790
|
+
"\n".join(self.lines()).encode(self.encoding).decode(self.encoding)
|
791
|
+
)
|
792
|
+
return self._single_string
|
793
|
+
|
794
|
+
def dump(self, filename, encoding=None):
|
795
|
+
"""Dumps the ascii art in the file.
|
796
|
+
|
797
|
+
Args:
|
798
|
+
filename (str): File to dump the ascii art.
|
799
|
+
encoding (str): Optional. Force encoding, instead of self.encoding.
|
800
|
+
"""
|
801
|
+
with open(filename, mode="w", encoding=encoding or self.encoding) as text_file:
|
802
|
+
text_file.write(self.single_string())
|
803
|
+
|
804
|
+
def lines(self, line_length=None):
|
805
|
+
"""Generates a list with lines. These lines form the text drawing.
|
806
|
+
|
807
|
+
Args:
|
808
|
+
line_length (int): Optional. Breaks the circuit drawing to this length. This is
|
809
|
+
useful when the drawing does not fit in the console. If
|
810
|
+
None (default), it will try to guess the console width using
|
811
|
+
shutil.get_terminal_size(). If you don't want pagination
|
812
|
+
at all, set line_length=-1.
|
813
|
+
|
814
|
+
Returns:
|
815
|
+
list: A list of lines with the text drawing.
|
816
|
+
"""
|
817
|
+
if line_length is None:
|
818
|
+
line_length = self.line_length
|
819
|
+
if not line_length:
|
820
|
+
if ("ipykernel" in sys.modules) and ("spyder" not in sys.modules):
|
821
|
+
line_length = 80
|
822
|
+
else:
|
823
|
+
line_length, _ = get_terminal_size()
|
824
|
+
|
825
|
+
noqubits = len(self.qubits)
|
826
|
+
|
827
|
+
layers = self.build_layers()
|
828
|
+
layer_groups = [[]]
|
829
|
+
rest_of_the_line = line_length
|
830
|
+
for layerno, layer in enumerate(layers):
|
831
|
+
# Replace the Nones with EmptyWire
|
832
|
+
layers[layerno] = EmptyWire.fillup_layer(layer, noqubits)
|
833
|
+
|
834
|
+
TextDrawing.normalize_width(layer)
|
835
|
+
|
836
|
+
if line_length == -1:
|
837
|
+
# Do not use pagination (aka line breaking. aka ignore line_length).
|
838
|
+
layer_groups[-1].append(layer)
|
839
|
+
continue
|
840
|
+
|
841
|
+
# chop the layer to the line_length (pager)
|
842
|
+
layer_length = layers[layerno][0].length
|
843
|
+
|
844
|
+
if layer_length < rest_of_the_line:
|
845
|
+
layer_groups[-1].append(layer)
|
846
|
+
rest_of_the_line -= layer_length
|
847
|
+
else:
|
848
|
+
layer_groups[-1].append(BreakWire.fillup_layer(len(layer), "»"))
|
849
|
+
|
850
|
+
# New group
|
851
|
+
layer_groups.append([BreakWire.fillup_layer(len(layer), "«")])
|
852
|
+
rest_of_the_line = line_length - layer_groups[-1][-1][0].length
|
853
|
+
|
854
|
+
layer_groups[-1].append(
|
855
|
+
InputWire.fillup_layer(self.wire_names(with_initial_state=False))
|
856
|
+
)
|
857
|
+
rest_of_the_line -= layer_groups[-1][-1][0].length
|
858
|
+
|
859
|
+
layer_groups[-1].append(layer)
|
860
|
+
rest_of_the_line -= layer_groups[-1][-1][0].length
|
861
|
+
|
862
|
+
lines = []
|
863
|
+
|
864
|
+
if self.global_phase:
|
865
|
+
lines.append(f"global phase: {pi_check(self.global_phase, ndigits=5)}")
|
866
|
+
|
867
|
+
for layer_group in layer_groups:
|
868
|
+
wires = list(zip(*layer_group))
|
869
|
+
lines += self.draw_wires(wires)
|
870
|
+
|
871
|
+
return lines
|
872
|
+
|
873
|
+
def wire_names(self, with_initial_state=False):
|
874
|
+
"""Returns a list of names for each wire.
|
875
|
+
|
876
|
+
Args:
|
877
|
+
with_initial_state (bool): Optional (Default: False). If true, adds
|
878
|
+
the initial value to the name.
|
879
|
+
|
880
|
+
Returns:
|
881
|
+
List: The list of wire names.
|
882
|
+
"""
|
883
|
+
if with_initial_state:
|
884
|
+
initial_qubit_value = "|0>"
|
885
|
+
initial_clbit_value = "0 "
|
886
|
+
else:
|
887
|
+
initial_qubit_value = ""
|
888
|
+
initial_clbit_value = ""
|
889
|
+
|
890
|
+
self._wire_map = get_wire_map(self._circuit, (self.qubits + self.clbits), self.cregbundle)
|
891
|
+
wire_labels = []
|
892
|
+
for wire, index in self._wire_map.items():
|
893
|
+
if isinstance(wire, ClassicalRegister):
|
894
|
+
register = wire
|
895
|
+
else:
|
896
|
+
register, bit_index, reg_index = get_bit_reg_index(self._circuit, wire)
|
897
|
+
index = bit_index if register is None else reg_index
|
898
|
+
|
899
|
+
wire_label = get_wire_label(
|
900
|
+
"text", register, index, layout=self.layout, cregbundle=self.cregbundle
|
901
|
+
)
|
902
|
+
wire_label += " " if self.layout is not None and isinstance(wire, Qubit) else ": "
|
903
|
+
|
904
|
+
cregb_add = ""
|
905
|
+
if isinstance(wire, Qubit):
|
906
|
+
initial_bit_value = initial_qubit_value
|
907
|
+
else:
|
908
|
+
initial_bit_value = initial_clbit_value
|
909
|
+
if self.cregbundle and register is not None:
|
910
|
+
cregb_add = str(register.size) + "/"
|
911
|
+
wire_labels.append(wire_label + initial_bit_value + cregb_add)
|
912
|
+
|
913
|
+
return wire_labels
|
914
|
+
|
915
|
+
def should_compress(self, top_line, bot_line):
|
916
|
+
"""Decides if the top_line and bot_line should be merged,
|
917
|
+
based on `self.vertical_compression`."""
|
918
|
+
if self.vertical_compression == "high":
|
919
|
+
return True
|
920
|
+
if self.vertical_compression == "low":
|
921
|
+
return False
|
922
|
+
for top, bot in zip(top_line, bot_line):
|
923
|
+
if top in ["┴", "╨"] and bot in ["┬", "╥"]:
|
924
|
+
return False
|
925
|
+
if (top.isalnum() and bot != " ") or (bot.isalnum() and top != " "):
|
926
|
+
return False
|
927
|
+
return True
|
928
|
+
|
929
|
+
def draw_wires(self, wires):
|
930
|
+
"""Given a list of wires, creates a list of lines with the text drawing.
|
931
|
+
|
932
|
+
Args:
|
933
|
+
wires (list): A list of wires with nodes.
|
934
|
+
Returns:
|
935
|
+
list: A list of lines with the text drawing.
|
936
|
+
"""
|
937
|
+
lines = []
|
938
|
+
bot_line = None
|
939
|
+
for wire in wires:
|
940
|
+
# TOP
|
941
|
+
top_line = ""
|
942
|
+
for node in wire:
|
943
|
+
top_line += node.top
|
944
|
+
|
945
|
+
if bot_line is None:
|
946
|
+
lines.append(top_line)
|
947
|
+
else:
|
948
|
+
if self.should_compress(top_line, bot_line):
|
949
|
+
lines.append(TextDrawing.merge_lines(lines.pop(), top_line))
|
950
|
+
else:
|
951
|
+
lines.append(TextDrawing.merge_lines(lines[-1], top_line, icod="bot"))
|
952
|
+
|
953
|
+
# MID
|
954
|
+
mid_line = ""
|
955
|
+
for node in wire:
|
956
|
+
mid_line += node.mid
|
957
|
+
lines.append(TextDrawing.merge_lines(lines[-1], mid_line, icod="bot"))
|
958
|
+
|
959
|
+
# BOT
|
960
|
+
bot_line = ""
|
961
|
+
for node in wire:
|
962
|
+
bot_line += node.bot
|
963
|
+
lines.append(TextDrawing.merge_lines(lines[-1], bot_line, icod="bot"))
|
964
|
+
|
965
|
+
return lines
|
966
|
+
|
967
|
+
@staticmethod
|
968
|
+
def special_label(node):
|
969
|
+
"""Some instructions have special labels"""
|
970
|
+
labels = {IGate: "I", SXGate: "√X", SXdgGate: "√Xdg"}
|
971
|
+
node_type = getattr(node, "base_class", None)
|
972
|
+
return labels.get(node_type, None)
|
973
|
+
|
974
|
+
@staticmethod
|
975
|
+
def merge_lines(top, bot, icod="top"):
|
976
|
+
"""Merges two lines (top and bot) in a way that the overlapping makes sense.
|
977
|
+
|
978
|
+
Args:
|
979
|
+
top (str): the top line
|
980
|
+
bot (str): the bottom line
|
981
|
+
icod (top or bot): in case of doubt, which line should have priority? Default: "top".
|
982
|
+
Returns:
|
983
|
+
str: The merge of both lines.
|
984
|
+
"""
|
985
|
+
ret = ""
|
986
|
+
for topc, botc in zip(top, bot):
|
987
|
+
if topc == botc:
|
988
|
+
ret += topc
|
989
|
+
elif topc in "┼╪" and botc == " ":
|
990
|
+
ret += "│"
|
991
|
+
elif topc == " ":
|
992
|
+
ret += botc
|
993
|
+
elif topc in "┬╥" and botc in " ║│" and icod == "top":
|
994
|
+
ret += topc
|
995
|
+
elif topc in "┬" and botc == " " and icod == "bot":
|
996
|
+
ret += "│"
|
997
|
+
elif topc in "╥" and botc == " " and icod == "bot":
|
998
|
+
ret += "║"
|
999
|
+
elif topc in "┬│" and botc == "═":
|
1000
|
+
ret += "╪"
|
1001
|
+
elif topc in "┬│" and botc == "─":
|
1002
|
+
ret += "┼"
|
1003
|
+
elif topc in "└┘║│░" and botc == " " and icod == "top":
|
1004
|
+
ret += topc
|
1005
|
+
elif topc in "─═" and botc == " " and icod == "top":
|
1006
|
+
ret += topc
|
1007
|
+
elif topc in "─═" and botc == " " and icod == "bot":
|
1008
|
+
ret += botc
|
1009
|
+
elif topc in "║╥" and botc in "═":
|
1010
|
+
ret += "╬"
|
1011
|
+
elif topc in "║╥" and botc in "─":
|
1012
|
+
ret += "╫"
|
1013
|
+
elif topc in "║╫╬" and botc in " ":
|
1014
|
+
ret += "║"
|
1015
|
+
elif topc in "│┼╪" and botc in " ":
|
1016
|
+
ret += "│"
|
1017
|
+
elif topc == "└" and botc == "┌" and icod == "top":
|
1018
|
+
ret += "├"
|
1019
|
+
elif topc == "┘" and botc == "┐" and icod == "top":
|
1020
|
+
ret += "┤"
|
1021
|
+
elif botc in "┐┌" and icod == "top":
|
1022
|
+
ret += "┬"
|
1023
|
+
elif topc in "┘└" and botc in "─" and icod == "top":
|
1024
|
+
ret += "┴"
|
1025
|
+
elif botc == " " and icod == "top":
|
1026
|
+
ret += topc
|
1027
|
+
else:
|
1028
|
+
ret += botc
|
1029
|
+
return ret
|
1030
|
+
|
1031
|
+
@staticmethod
|
1032
|
+
def normalize_width(layer):
|
1033
|
+
"""
|
1034
|
+
When the elements of the layer have different widths, sets the width to the max elements.
|
1035
|
+
|
1036
|
+
Args:
|
1037
|
+
layer (list): A list of elements.
|
1038
|
+
"""
|
1039
|
+
nodes = list(filter(lambda x: x is not None, layer))
|
1040
|
+
longest = max(node.length for node in nodes)
|
1041
|
+
for node in nodes:
|
1042
|
+
node.layer_width = longest
|
1043
|
+
|
1044
|
+
@staticmethod
|
1045
|
+
def controlled_wires(node, wire_map, ctrl_text, conditional, mod_control):
|
1046
|
+
"""
|
1047
|
+
Analyzes the node in the layer and checks if the controlled arguments are in
|
1048
|
+
the box or out of the box.
|
1049
|
+
|
1050
|
+
Args:
|
1051
|
+
node (DAGNode): node to analyse
|
1052
|
+
wire_map (dict): map of qubits/clbits to position
|
1053
|
+
ctrl_text (str): text for a control label
|
1054
|
+
conditional (bool): is this a node with a condition
|
1055
|
+
mod_control (ControlModifier): an instance of a modifier for an
|
1056
|
+
AnnotatedOperation
|
1057
|
+
|
1058
|
+
Returns:
|
1059
|
+
Tuple(list, list, list):
|
1060
|
+
- tuple: controlled arguments on top of the "node box", and its status
|
1061
|
+
- tuple: controlled arguments on bottom of the "node box", and its status
|
1062
|
+
- tuple: controlled arguments in the "node box", and its status
|
1063
|
+
- the rest of the arguments
|
1064
|
+
"""
|
1065
|
+
op = node.op
|
1066
|
+
num_ctrl_qubits = mod_control.num_ctrl_qubits if mod_control else op.num_ctrl_qubits
|
1067
|
+
ctrl_qubits = node.qargs[:num_ctrl_qubits]
|
1068
|
+
args_qubits = node.qargs[num_ctrl_qubits:]
|
1069
|
+
ctrl_state = mod_control.ctrl_state if mod_control else op.ctrl_state
|
1070
|
+
ctrl_state = f"{ctrl_state:b}".rjust(num_ctrl_qubits, "0")[::-1]
|
1071
|
+
|
1072
|
+
in_box = []
|
1073
|
+
top_box = []
|
1074
|
+
bot_box = []
|
1075
|
+
|
1076
|
+
qubit_indices = sorted(wire_map[x] for x in wire_map if x in args_qubits)
|
1077
|
+
|
1078
|
+
for ctrl_qubit in zip(ctrl_qubits, ctrl_state):
|
1079
|
+
if min(qubit_indices) > wire_map[ctrl_qubit[0]]:
|
1080
|
+
top_box.append(ctrl_qubit)
|
1081
|
+
elif max(qubit_indices) < wire_map[ctrl_qubit[0]]:
|
1082
|
+
bot_box.append(ctrl_qubit)
|
1083
|
+
else:
|
1084
|
+
in_box.append(ctrl_qubit)
|
1085
|
+
|
1086
|
+
gates = []
|
1087
|
+
for i in range(len(ctrl_qubits)):
|
1088
|
+
# For sidetext gate alignment, need to set every Bullet with
|
1089
|
+
# conditional on if there's a condition.
|
1090
|
+
if getattr(op, "condition", None) is not None:
|
1091
|
+
conditional = True
|
1092
|
+
if ctrl_state[i] == "1":
|
1093
|
+
gates.append(Bullet(conditional=conditional, label=ctrl_text, bottom=bool(bot_box)))
|
1094
|
+
else:
|
1095
|
+
gates.append(
|
1096
|
+
OpenBullet(conditional=conditional, label=ctrl_text, bottom=bool(bot_box))
|
1097
|
+
)
|
1098
|
+
return (gates, top_box, bot_box, in_box, args_qubits)
|
1099
|
+
|
1100
|
+
def _node_to_gate(self, node, layer, gate_wire_map):
|
1101
|
+
"""Convert a dag op node into its corresponding Gate object, and establish
|
1102
|
+
any connections it introduces between qubits. gate_wire_map is the flow_wire_map
|
1103
|
+
if gate is inside a ControlFlowOp, else it's self._wire_map"""
|
1104
|
+
op = node.op
|
1105
|
+
current_cons = []
|
1106
|
+
current_cons_cond = []
|
1107
|
+
connection_label = None
|
1108
|
+
conditional = False
|
1109
|
+
base_gate = getattr(op, "base_gate", None)
|
1110
|
+
|
1111
|
+
params = get_param_str(op, "text", ndigits=5)
|
1112
|
+
if not isinstance(op, (Measure, SwapGate, Reset)) and not getattr(op, "_directive", False):
|
1113
|
+
gate_text, ctrl_text, _ = get_gate_ctrl_text(op, "text")
|
1114
|
+
gate_text = TextDrawing.special_label(op) or gate_text
|
1115
|
+
gate_text = gate_text + params
|
1116
|
+
|
1117
|
+
if getattr(op, "condition", None) is not None:
|
1118
|
+
# conditional
|
1119
|
+
current_cons_cond += layer.set_cl_multibox(op.condition, gate_wire_map, top_connect="╨")
|
1120
|
+
conditional = True
|
1121
|
+
|
1122
|
+
# add in a gate that operates over multiple qubits
|
1123
|
+
def add_connected_gate(node, gates, layer, current_cons, gate_wire_map):
|
1124
|
+
for i, gate in enumerate(gates):
|
1125
|
+
actual_index = gate_wire_map[node.qargs[i]]
|
1126
|
+
if actual_index not in [i for i, j in current_cons]:
|
1127
|
+
layer.set_qubit(node.qargs[i], gate)
|
1128
|
+
current_cons.append((actual_index, gate))
|
1129
|
+
|
1130
|
+
# AnnotatedOperation with ControlModifier
|
1131
|
+
mod_control = None
|
1132
|
+
if getattr(op, "modifiers", None):
|
1133
|
+
canonical_modifiers = _canonicalize_modifiers(op.modifiers)
|
1134
|
+
for modifier in canonical_modifiers:
|
1135
|
+
if isinstance(modifier, ControlModifier):
|
1136
|
+
mod_control = modifier
|
1137
|
+
break
|
1138
|
+
|
1139
|
+
if isinstance(op, Measure):
|
1140
|
+
gate = MeasureFrom()
|
1141
|
+
layer.set_qubit(node.qargs[0], gate)
|
1142
|
+
register, _, reg_index = get_bit_reg_index(self._circuit, node.cargs[0])
|
1143
|
+
if self.cregbundle and register is not None:
|
1144
|
+
layer.set_clbit(
|
1145
|
+
node.cargs[0],
|
1146
|
+
MeasureTo(str(reg_index)),
|
1147
|
+
)
|
1148
|
+
else:
|
1149
|
+
layer.set_clbit(node.cargs[0], MeasureTo())
|
1150
|
+
|
1151
|
+
elif getattr(op, "_directive", False):
|
1152
|
+
# barrier
|
1153
|
+
if not self.plotbarriers:
|
1154
|
+
return layer, current_cons, current_cons_cond, connection_label
|
1155
|
+
|
1156
|
+
top_qubit = min(node.qargs, key=lambda q: self._wire_map.get(q, float("inf")))
|
1157
|
+
for qubit in node.qargs:
|
1158
|
+
if qubit in self.qubits:
|
1159
|
+
label = op.label if qubit == top_qubit else ""
|
1160
|
+
layer.set_qubit(qubit, Barrier(label))
|
1161
|
+
|
1162
|
+
elif isinstance(op, SwapGate):
|
1163
|
+
# swap
|
1164
|
+
gates = [Ex(conditional=conditional) for _ in range(len(node.qargs))]
|
1165
|
+
add_connected_gate(node, gates, layer, current_cons, gate_wire_map)
|
1166
|
+
|
1167
|
+
elif isinstance(op, Reset):
|
1168
|
+
# reset
|
1169
|
+
layer.set_qubit(node.qargs[0], ResetDisplay(conditional=conditional))
|
1170
|
+
|
1171
|
+
elif isinstance(op, RZZGate):
|
1172
|
+
# rzz
|
1173
|
+
connection_label = f"ZZ{params}"
|
1174
|
+
gates = [Bullet(conditional=conditional), Bullet(conditional=conditional)]
|
1175
|
+
add_connected_gate(node, gates, layer, current_cons, gate_wire_map)
|
1176
|
+
|
1177
|
+
elif len(node.qargs) == 1 and not node.cargs:
|
1178
|
+
# unitary gate
|
1179
|
+
layer.set_qubit(node.qargs[0], BoxOnQuWire(gate_text, conditional=conditional))
|
1180
|
+
|
1181
|
+
elif isinstance(op, ControlledGate) or mod_control:
|
1182
|
+
controls_array = TextDrawing.controlled_wires(
|
1183
|
+
node, gate_wire_map, ctrl_text, conditional, mod_control
|
1184
|
+
)
|
1185
|
+
gates, controlled_top, controlled_bot, controlled_edge, rest = controls_array
|
1186
|
+
if mod_control:
|
1187
|
+
if len(rest) == 1:
|
1188
|
+
gates.append(BoxOnQuWire(gate_text, conditional=conditional))
|
1189
|
+
else:
|
1190
|
+
top_connect = "┴" if controlled_top else None
|
1191
|
+
bot_connect = "┬" if controlled_bot else None
|
1192
|
+
indexes = layer.set_qu_multibox(
|
1193
|
+
rest,
|
1194
|
+
gate_text,
|
1195
|
+
conditional=conditional,
|
1196
|
+
controlled_edge=controlled_edge,
|
1197
|
+
top_connect=top_connect,
|
1198
|
+
bot_connect=bot_connect,
|
1199
|
+
)
|
1200
|
+
for index in range(min(indexes), max(indexes) + 1):
|
1201
|
+
# Dummy element to connect the multibox with the bullets
|
1202
|
+
current_cons.append((index, DrawElement("")))
|
1203
|
+
elif base_gate.name == "z":
|
1204
|
+
# cz
|
1205
|
+
gates.append(Bullet(conditional=conditional))
|
1206
|
+
elif base_gate.name in ["u1", "p"]:
|
1207
|
+
# cu1
|
1208
|
+
connection_label = f"{base_gate.name.upper()}{params}"
|
1209
|
+
gates.append(Bullet(conditional=conditional))
|
1210
|
+
elif base_gate.name == "swap":
|
1211
|
+
# cswap
|
1212
|
+
gates += [Ex(conditional=conditional), Ex(conditional=conditional)]
|
1213
|
+
add_connected_gate(node, gates, layer, current_cons, gate_wire_map)
|
1214
|
+
elif base_gate.name == "rzz":
|
1215
|
+
# crzz
|
1216
|
+
connection_label = f"ZZ{params}"
|
1217
|
+
gates += [Bullet(conditional=conditional), Bullet(conditional=conditional)]
|
1218
|
+
elif len(rest) > 1:
|
1219
|
+
top_connect = "┴" if controlled_top else None
|
1220
|
+
bot_connect = "┬" if controlled_bot else None
|
1221
|
+
indexes = layer.set_qu_multibox(
|
1222
|
+
rest,
|
1223
|
+
gate_text,
|
1224
|
+
conditional=conditional,
|
1225
|
+
controlled_edge=controlled_edge,
|
1226
|
+
top_connect=top_connect,
|
1227
|
+
bot_connect=bot_connect,
|
1228
|
+
)
|
1229
|
+
for index in range(min(indexes), max(indexes) + 1):
|
1230
|
+
# Dummy element to connect the multibox with the bullets
|
1231
|
+
current_cons.append((index, DrawElement("")))
|
1232
|
+
else:
|
1233
|
+
gates.append(BoxOnQuWire(gate_text, conditional=conditional))
|
1234
|
+
|
1235
|
+
add_connected_gate(node, gates, layer, current_cons, gate_wire_map)
|
1236
|
+
|
1237
|
+
elif len(node.qargs) >= 2 and not node.cargs:
|
1238
|
+
layer.set_qu_multibox(node.qargs, gate_text, conditional=conditional)
|
1239
|
+
|
1240
|
+
elif node.qargs and node.cargs:
|
1241
|
+
layer._set_multibox(
|
1242
|
+
gate_text,
|
1243
|
+
qargs=node.qargs,
|
1244
|
+
cargs=node.cargs,
|
1245
|
+
conditional=conditional,
|
1246
|
+
)
|
1247
|
+
else:
|
1248
|
+
raise VisualizationError(
|
1249
|
+
"Text visualizer does not know how to handle this node: ", op.name
|
1250
|
+
)
|
1251
|
+
|
1252
|
+
# sort into the order they were declared in, to ensure that connected boxes have
|
1253
|
+
# lines in the right direction
|
1254
|
+
current_cons.sort(key=lambda tup: tup[0])
|
1255
|
+
current_cons = [g for q, g in current_cons]
|
1256
|
+
current_cons_cond.sort(key=lambda tup: tup[0])
|
1257
|
+
current_cons_cond = [g for c, g in current_cons_cond]
|
1258
|
+
|
1259
|
+
return layer, current_cons, current_cons_cond, connection_label
|
1260
|
+
|
1261
|
+
def build_layers(self):
|
1262
|
+
"""
|
1263
|
+
Constructs layers.
|
1264
|
+
Returns:
|
1265
|
+
list: List of DrawElements.
|
1266
|
+
Raises:
|
1267
|
+
VisualizationError: When the drawing is, for some reason, impossible to be drawn.
|
1268
|
+
"""
|
1269
|
+
wire_names = self.wire_names(with_initial_state=self.initial_state)
|
1270
|
+
if not wire_names:
|
1271
|
+
return []
|
1272
|
+
|
1273
|
+
layers = [InputWire.fillup_layer(wire_names)]
|
1274
|
+
|
1275
|
+
for node_layer in self.nodes:
|
1276
|
+
layer = Layer(
|
1277
|
+
self.qubits,
|
1278
|
+
self.clbits,
|
1279
|
+
self.cregbundle,
|
1280
|
+
self._circuit,
|
1281
|
+
self._wire_map,
|
1282
|
+
)
|
1283
|
+
for node in node_layer:
|
1284
|
+
if isinstance(node.op, ControlFlowOp):
|
1285
|
+
self._nest_depth = 0
|
1286
|
+
self.add_control_flow(node, layers, self._wire_map)
|
1287
|
+
else:
|
1288
|
+
layer, current_cons, current_cons_cond, connection_label = self._node_to_gate(
|
1289
|
+
node, layer, self._wire_map
|
1290
|
+
)
|
1291
|
+
layer.connections.append((connection_label, current_cons))
|
1292
|
+
layer.connections.append((None, current_cons_cond))
|
1293
|
+
layer.connect_with("│")
|
1294
|
+
layers.append(layer.full_layer)
|
1295
|
+
|
1296
|
+
return layers
|
1297
|
+
|
1298
|
+
def add_control_flow(self, node, layers, wire_map):
|
1299
|
+
"""Add control flow ops to the circuit drawing."""
|
1300
|
+
|
1301
|
+
if (isinstance(node.op, SwitchCaseOp) and isinstance(node.op.target, expr.Expr)) or (
|
1302
|
+
getattr(node.op, "condition", None) and isinstance(node.op.condition, expr.Expr)
|
1303
|
+
):
|
1304
|
+
|
1305
|
+
def lookup_var(var):
|
1306
|
+
"""Look up a classical-expression variable or register/bit in our internal symbol
|
1307
|
+
table, and return an OQ3-like identifier."""
|
1308
|
+
# We don't attempt to disambiguate anything like register/var naming collisions; we
|
1309
|
+
# already don't really show classical variables.
|
1310
|
+
if isinstance(var, expr.Var):
|
1311
|
+
return ast.Identifier(var.name)
|
1312
|
+
if isinstance(var, ClassicalRegister):
|
1313
|
+
return ast.Identifier(var.name)
|
1314
|
+
# Single clbit. This is not actually the correct way to lookup a bit on the
|
1315
|
+
# circuit (it doesn't handle bit bindings fully), but the text drawer doesn't
|
1316
|
+
# completely track inner-outer _bit_ bindings, only inner-indices, so we can't fully
|
1317
|
+
# recover the information losslessly. Since most control-flow uses the control-flow
|
1318
|
+
# builders, we should decay to something usable most of the time.
|
1319
|
+
try:
|
1320
|
+
register, bit_index, reg_index = get_bit_reg_index(self._circuit, var)
|
1321
|
+
except CircuitError:
|
1322
|
+
# We failed to find the bit due to binding problems - fall back to something
|
1323
|
+
# that's probably wrong, but at least disambiguating.
|
1324
|
+
return ast.Identifier(f"_bit{wire_map[var]}")
|
1325
|
+
if register is None:
|
1326
|
+
return ast.Identifier(f"_bit{bit_index}")
|
1327
|
+
return ast.SubscriptedIdentifier(register.name, ast.IntegerLiteral(reg_index))
|
1328
|
+
|
1329
|
+
condition = node.op.target if isinstance(node.op, SwitchCaseOp) else node.op.condition
|
1330
|
+
draw_conditional = bool(node_resources(condition).clbits)
|
1331
|
+
stream = StringIO()
|
1332
|
+
BasicPrinter(stream, indent=" ").visit(condition.accept(_ExprBuilder(lookup_var)))
|
1333
|
+
self._expr_text = stream.getvalue()
|
1334
|
+
# Truncate expr_text at 30 chars or user-set expr_len
|
1335
|
+
if len(self._expr_text) > self.expr_len:
|
1336
|
+
self._expr_text = self._expr_text[: self.expr_len] + "..."
|
1337
|
+
else:
|
1338
|
+
draw_conditional = isinstance(node.op, (IfElseOp, WhileLoopOp, SwitchCaseOp))
|
1339
|
+
|
1340
|
+
# # Draw a left box such as If, While, For, and Switch
|
1341
|
+
flow_layer = self.draw_flow_box(node, wire_map, CF_LEFT, conditional=draw_conditional)
|
1342
|
+
layers.append(flow_layer.full_layer)
|
1343
|
+
|
1344
|
+
# Get the list of circuits in the ControlFlowOp from the node blocks
|
1345
|
+
circuit_list = list(node.op.blocks)
|
1346
|
+
|
1347
|
+
if isinstance(node.op, SwitchCaseOp):
|
1348
|
+
# Create an empty circuit at the head of the circuit_list if a Switch box
|
1349
|
+
circuit_list.insert(0, list(node.op.cases_specifier())[0][1].copy_empty_like())
|
1350
|
+
|
1351
|
+
for circ_num, circuit in enumerate(circuit_list):
|
1352
|
+
# Update the wire_map with the qubits and clbits from the inner circuit
|
1353
|
+
flow_wire_map = wire_map.copy()
|
1354
|
+
flow_wire_map.update(
|
1355
|
+
{inner: wire_map[outer] for outer, inner in zip(node.qargs, circuit.qubits)}
|
1356
|
+
)
|
1357
|
+
for outer, inner in zip(node.cargs, circuit.clbits):
|
1358
|
+
if self.cregbundle and (
|
1359
|
+
(in_reg := get_bit_register(self._circuit, inner)) is not None
|
1360
|
+
):
|
1361
|
+
out_reg = get_bit_register(self._circuit, outer)
|
1362
|
+
flow_wire_map.update({in_reg: wire_map[out_reg]})
|
1363
|
+
else:
|
1364
|
+
flow_wire_map.update({inner: wire_map[outer]})
|
1365
|
+
|
1366
|
+
if circ_num > 0:
|
1367
|
+
# Draw a middle box such as Else and Case
|
1368
|
+
flow_layer = self.draw_flow_box(
|
1369
|
+
node, flow_wire_map, CF_MID, circ_num - 1, conditional=False
|
1370
|
+
)
|
1371
|
+
layers.append(flow_layer.full_layer)
|
1372
|
+
|
1373
|
+
_, _, nodes = _get_layered_instructions(circuit, wire_map=flow_wire_map)
|
1374
|
+
for layer_nodes in nodes:
|
1375
|
+
# Limit qubits sent to only ones from main circuit, so qubit_layer is correct length
|
1376
|
+
flow_layer2 = Layer(
|
1377
|
+
self.qubits, self.clbits, self.cregbundle, self._circuit, flow_wire_map
|
1378
|
+
)
|
1379
|
+
for layer_node in layer_nodes:
|
1380
|
+
if isinstance(layer_node.op, ControlFlowOp):
|
1381
|
+
# Recurse on this function if nested ControlFlowOps
|
1382
|
+
self._nest_depth += 1
|
1383
|
+
self.add_control_flow(layer_node, layers, flow_wire_map)
|
1384
|
+
self._nest_depth -= 1
|
1385
|
+
else:
|
1386
|
+
(
|
1387
|
+
flow_layer2,
|
1388
|
+
current_cons,
|
1389
|
+
current_cons_cond,
|
1390
|
+
connection_label,
|
1391
|
+
) = self._node_to_gate(layer_node, flow_layer2, flow_wire_map)
|
1392
|
+
flow_layer2.connections.append((connection_label, current_cons))
|
1393
|
+
flow_layer2.connections.append((None, current_cons_cond))
|
1394
|
+
|
1395
|
+
flow_layer2.connect_with("│")
|
1396
|
+
layers.append(flow_layer2.full_layer)
|
1397
|
+
|
1398
|
+
# Draw the right box for End
|
1399
|
+
flow_layer = self.draw_flow_box(node, wire_map, CF_RIGHT, conditional=False)
|
1400
|
+
layers.append(flow_layer.full_layer)
|
1401
|
+
|
1402
|
+
def draw_flow_box(self, node, flow_wire_map, section, circ_num=0, conditional=False):
|
1403
|
+
"""Draw the left, middle, or right of a control flow box"""
|
1404
|
+
|
1405
|
+
op = node.op
|
1406
|
+
depth = str(self._nest_depth)
|
1407
|
+
if section == CF_LEFT:
|
1408
|
+
etext = ""
|
1409
|
+
if self._expr_text:
|
1410
|
+
etext = " " + self._expr_text
|
1411
|
+
if isinstance(op, IfElseOp):
|
1412
|
+
label = "If-" + depth + etext
|
1413
|
+
elif isinstance(op, WhileLoopOp):
|
1414
|
+
label = "While-" + depth + etext
|
1415
|
+
elif isinstance(op, ForLoopOp):
|
1416
|
+
indexset = op.params[0]
|
1417
|
+
# If tuple of values instead of range, cut it off at 4 items
|
1418
|
+
if "range" not in str(indexset) and len(indexset) > 4:
|
1419
|
+
index_str = str(indexset[:4])
|
1420
|
+
index_str = index_str[:-1] + ", ...)"
|
1421
|
+
else:
|
1422
|
+
index_str = str(indexset)
|
1423
|
+
label = "For-" + depth + " " + index_str
|
1424
|
+
elif isinstance(op, BoxOp):
|
1425
|
+
label = "Box-" + depth + etext
|
1426
|
+
elif isinstance(op, SwitchCaseOp):
|
1427
|
+
label = "Switch-" + depth + etext
|
1428
|
+
else:
|
1429
|
+
raise RuntimeError(f"unhandled control-flow operation: {node.name}")
|
1430
|
+
elif section == CF_MID:
|
1431
|
+
if isinstance(op, IfElseOp):
|
1432
|
+
label = "Else-" + depth
|
1433
|
+
else:
|
1434
|
+
jump_list = []
|
1435
|
+
for jump_values, _ in list(op.cases_specifier()):
|
1436
|
+
jump_list.append(jump_values)
|
1437
|
+
|
1438
|
+
if "default" in str(jump_list[circ_num][0]):
|
1439
|
+
jump_str = "default"
|
1440
|
+
else:
|
1441
|
+
jump_str = str(jump_list[circ_num]).replace(",)", ")")
|
1442
|
+
label = "Case-" + depth + " " + jump_str
|
1443
|
+
|
1444
|
+
else:
|
1445
|
+
label = "End-" + depth
|
1446
|
+
|
1447
|
+
flow_layer = Layer(
|
1448
|
+
self.qubits,
|
1449
|
+
self.clbits,
|
1450
|
+
self.cregbundle,
|
1451
|
+
self._circuit,
|
1452
|
+
flow_wire_map,
|
1453
|
+
)
|
1454
|
+
# If only 1 qubit, draw basic 1 qubit box
|
1455
|
+
if len(node.qargs) == 1:
|
1456
|
+
flow_layer.set_qubit(
|
1457
|
+
self.qubits[flow_wire_map[node.qargs[0]]],
|
1458
|
+
FlowOnQuWire(section, label=label, conditional=conditional),
|
1459
|
+
)
|
1460
|
+
else:
|
1461
|
+
# If multiple qubits, must use wire_map to handle wire_order changes.
|
1462
|
+
idx_list = [flow_wire_map[qarg] for qarg in node.qargs]
|
1463
|
+
min_idx = min(idx_list)
|
1464
|
+
max_idx = max(idx_list)
|
1465
|
+
box_height = max_idx - min_idx + 1
|
1466
|
+
|
1467
|
+
flow_layer.set_qubit(
|
1468
|
+
self.qubits[min_idx], FlowOnQuWireTop(section, label=label, wire_label="")
|
1469
|
+
)
|
1470
|
+
for order, i in enumerate(range(min_idx + 1, max_idx)):
|
1471
|
+
flow_layer.set_qubit(
|
1472
|
+
self.qubits[i],
|
1473
|
+
FlowOnQuWireMid(
|
1474
|
+
section,
|
1475
|
+
label=label,
|
1476
|
+
input_length=box_height,
|
1477
|
+
order=order,
|
1478
|
+
wire_label="",
|
1479
|
+
),
|
1480
|
+
)
|
1481
|
+
flow_layer.set_qubit(
|
1482
|
+
self.qubits[max_idx],
|
1483
|
+
FlowOnQuWireBot(
|
1484
|
+
section,
|
1485
|
+
label=label,
|
1486
|
+
input_length=box_height,
|
1487
|
+
conditional=conditional,
|
1488
|
+
wire_label="",
|
1489
|
+
),
|
1490
|
+
)
|
1491
|
+
if conditional:
|
1492
|
+
if isinstance(node.op, SwitchCaseOp):
|
1493
|
+
if isinstance(node.op.target, expr.Expr):
|
1494
|
+
condition = node.op.target
|
1495
|
+
elif isinstance(node.op.target, Clbit):
|
1496
|
+
condition = (node.op.target, 1)
|
1497
|
+
else:
|
1498
|
+
condition = (node.op.target, 2 ** (node.op.target.size) - 1)
|
1499
|
+
else:
|
1500
|
+
condition = node.op.condition
|
1501
|
+
_ = flow_layer.set_cl_multibox(condition, flow_wire_map, top_connect="╨")
|
1502
|
+
|
1503
|
+
return flow_layer
|
1504
|
+
|
1505
|
+
|
1506
|
+
class Layer:
|
1507
|
+
"""A layer is the "column" of the circuit."""
|
1508
|
+
|
1509
|
+
def __init__(self, qubits, clbits, cregbundle, circuit, wire_map):
|
1510
|
+
self.qubits = qubits
|
1511
|
+
self._circuit = circuit
|
1512
|
+
if cregbundle:
|
1513
|
+
self.clbits = []
|
1514
|
+
previous_creg = None
|
1515
|
+
for bit in clbits:
|
1516
|
+
register = get_bit_register(self._circuit, bit)
|
1517
|
+
if previous_creg and previous_creg == register:
|
1518
|
+
continue
|
1519
|
+
if register is None:
|
1520
|
+
self.clbits.append(bit)
|
1521
|
+
else:
|
1522
|
+
previous_creg = register
|
1523
|
+
self.clbits.append(previous_creg)
|
1524
|
+
else:
|
1525
|
+
self.clbits = clbits
|
1526
|
+
self.qubit_layer = [None] * len(qubits)
|
1527
|
+
self.connections = []
|
1528
|
+
self.clbit_layer = [None] * len(clbits)
|
1529
|
+
self.cregbundle = cregbundle
|
1530
|
+
self._wire_map = wire_map
|
1531
|
+
|
1532
|
+
@property
|
1533
|
+
def full_layer(self):
|
1534
|
+
"""
|
1535
|
+
Returns the composition of qubits and classic wires.
|
1536
|
+
Returns:
|
1537
|
+
String: self.qubit_layer + self.clbit_layer
|
1538
|
+
"""
|
1539
|
+
return self.qubit_layer + self.clbit_layer
|
1540
|
+
|
1541
|
+
def set_qubit(self, qubit, element):
|
1542
|
+
"""Sets the qubit to the element.
|
1543
|
+
|
1544
|
+
Args:
|
1545
|
+
qubit (qbit): Element of self.qubits.
|
1546
|
+
element (DrawElement): Element to set in the qubit
|
1547
|
+
"""
|
1548
|
+
self.qubit_layer[self._wire_map[qubit]] = element
|
1549
|
+
|
1550
|
+
def set_clbit(self, clbit, element):
|
1551
|
+
"""Sets the clbit to the element.
|
1552
|
+
|
1553
|
+
Args:
|
1554
|
+
clbit (cbit): Element of self.clbits.
|
1555
|
+
element (DrawElement): Element to set in the clbit
|
1556
|
+
"""
|
1557
|
+
register = get_bit_register(self._circuit, clbit)
|
1558
|
+
if self.cregbundle and register is not None:
|
1559
|
+
self.clbit_layer[self._wire_map[register] - len(self.qubits)] = element
|
1560
|
+
else:
|
1561
|
+
self.clbit_layer[self._wire_map[clbit] - len(self.qubits)] = element
|
1562
|
+
|
1563
|
+
def _set_multibox(
|
1564
|
+
self,
|
1565
|
+
label,
|
1566
|
+
qargs=None,
|
1567
|
+
cargs=None,
|
1568
|
+
top_connect=None,
|
1569
|
+
bot_connect=None,
|
1570
|
+
conditional=False,
|
1571
|
+
controlled_edge=None,
|
1572
|
+
):
|
1573
|
+
if qargs is not None and cargs is not None:
|
1574
|
+
qarg_indices = sorted(i for i, x in enumerate(self.qubits) if x in qargs)
|
1575
|
+
carg_indices = sorted(i for i, x in enumerate(self.clbits) if x in cargs)
|
1576
|
+
|
1577
|
+
# Further below, indices are used as wire labels. Here, get the length of
|
1578
|
+
# the longest label, and pad all labels with spaces to this length.
|
1579
|
+
wire_label_len = max(len(str(len(qargs) - 1)), len(str(len(cargs) - 1)))
|
1580
|
+
qargs_str = [
|
1581
|
+
str(qargs.index(qbit)).ljust(wire_label_len, " ")
|
1582
|
+
for qbit in self.qubits
|
1583
|
+
if qbit in qargs
|
1584
|
+
]
|
1585
|
+
cargs_str = [
|
1586
|
+
str(cargs.index(cbit)).ljust(wire_label_len, " ")
|
1587
|
+
for cbit in self.clbits
|
1588
|
+
if cbit in cargs
|
1589
|
+
]
|
1590
|
+
|
1591
|
+
qargs = sorted(qargs, key=self.qubits.index)
|
1592
|
+
cargs = sorted(cargs, key=self.clbits.index)
|
1593
|
+
|
1594
|
+
box_height = len(self.qubits) - min(qarg_indices) + max(carg_indices) + 1
|
1595
|
+
|
1596
|
+
self.set_qubit(qargs.pop(0), BoxOnQuWireTop(label, wire_label=qargs_str.pop(0)))
|
1597
|
+
order = 0
|
1598
|
+
for order, bit_i in enumerate(range(min(qarg_indices) + 1, len(self.qubits))):
|
1599
|
+
if bit_i in qarg_indices:
|
1600
|
+
named_bit = qargs.pop(0)
|
1601
|
+
wire_label = qargs_str.pop(0)
|
1602
|
+
else:
|
1603
|
+
named_bit = self.qubits[bit_i]
|
1604
|
+
wire_label = " " * wire_label_len
|
1605
|
+
self.set_qubit(
|
1606
|
+
named_bit, BoxOnQuWireMid(label, box_height, order, wire_label=wire_label)
|
1607
|
+
)
|
1608
|
+
for order, bit_i in enumerate(range(max(carg_indices)), order + 1):
|
1609
|
+
if bit_i in carg_indices:
|
1610
|
+
named_bit = cargs.pop(0)
|
1611
|
+
wire_label = cargs_str.pop(0)
|
1612
|
+
else:
|
1613
|
+
named_bit = self.clbits[bit_i]
|
1614
|
+
wire_label = " " * wire_label_len
|
1615
|
+
self.set_clbit(
|
1616
|
+
named_bit, BoxOnClWireMid(label, box_height, order, wire_label=wire_label)
|
1617
|
+
)
|
1618
|
+
self.set_clbit(
|
1619
|
+
cargs.pop(0), BoxOnClWireBot(label, box_height, wire_label=cargs_str.pop(0))
|
1620
|
+
)
|
1621
|
+
return carg_indices
|
1622
|
+
|
1623
|
+
if qargs is None and cargs is not None:
|
1624
|
+
bits = list(cargs)
|
1625
|
+
bit_indices = sorted(i for i, x in enumerate(self.clbits) if x in bits)
|
1626
|
+
wire_label_len = len(str(len(bits) - 1))
|
1627
|
+
bits.sort(key=self.clbits.index)
|
1628
|
+
qargs_str = [""] * len(bits)
|
1629
|
+
set_bit = self.set_clbit
|
1630
|
+
OnWire = BoxOnClWire
|
1631
|
+
OnWireTop = BoxOnClWireTop
|
1632
|
+
OnWireMid = BoxOnClWireMid
|
1633
|
+
OnWireBot = BoxOnClWireBot
|
1634
|
+
|
1635
|
+
elif cargs is None and qargs is not None:
|
1636
|
+
bits = list(qargs)
|
1637
|
+
bit_indices = sorted(i for i, x in enumerate(self.qubits) if x in bits)
|
1638
|
+
wire_label_len = len(str(len(bits) - 1))
|
1639
|
+
qargs_str = [
|
1640
|
+
str(bits.index(qbit)).ljust(wire_label_len, " ")
|
1641
|
+
for qbit in self.qubits
|
1642
|
+
if qbit in bits
|
1643
|
+
]
|
1644
|
+
bits.sort(key=self.qubits.index)
|
1645
|
+
set_bit = self.set_qubit
|
1646
|
+
OnWire = BoxOnQuWire
|
1647
|
+
OnWireTop = BoxOnQuWireTop
|
1648
|
+
OnWireMid = BoxOnQuWireMid
|
1649
|
+
OnWireBot = BoxOnQuWireBot
|
1650
|
+
else:
|
1651
|
+
raise VisualizationError("_set_multibox error!.")
|
1652
|
+
|
1653
|
+
control_index = {}
|
1654
|
+
if controlled_edge:
|
1655
|
+
for index, qubit in enumerate(self.qubits):
|
1656
|
+
for qubit_in_edge, value in controlled_edge:
|
1657
|
+
if qubit == qubit_in_edge:
|
1658
|
+
control_index[index] = "■" if value == "1" else "o"
|
1659
|
+
if len(bit_indices) == 1:
|
1660
|
+
set_bit(bits[0], OnWire(label, top_connect=top_connect))
|
1661
|
+
else:
|
1662
|
+
box_height = max(bit_indices) - min(bit_indices) + 1
|
1663
|
+
set_bit(
|
1664
|
+
bits.pop(0), OnWireTop(label, top_connect=top_connect, wire_label=qargs_str.pop(0))
|
1665
|
+
)
|
1666
|
+
for order, bit_i in enumerate(range(min(bit_indices) + 1, max(bit_indices))):
|
1667
|
+
if bit_i in bit_indices:
|
1668
|
+
named_bit = bits.pop(0)
|
1669
|
+
wire_label = qargs_str.pop(0)
|
1670
|
+
else:
|
1671
|
+
named_bit = (self.qubits + self.clbits)[bit_i]
|
1672
|
+
wire_label = " " * wire_label_len
|
1673
|
+
|
1674
|
+
control_label = control_index.get(bit_i)
|
1675
|
+
set_bit(
|
1676
|
+
named_bit,
|
1677
|
+
OnWireMid(
|
1678
|
+
label, box_height, order, wire_label=wire_label, control_label=control_label
|
1679
|
+
),
|
1680
|
+
)
|
1681
|
+
set_bit(
|
1682
|
+
bits.pop(0),
|
1683
|
+
OnWireBot(
|
1684
|
+
label,
|
1685
|
+
box_height,
|
1686
|
+
bot_connect=bot_connect,
|
1687
|
+
wire_label=qargs_str.pop(0),
|
1688
|
+
conditional=conditional,
|
1689
|
+
),
|
1690
|
+
)
|
1691
|
+
return bit_indices
|
1692
|
+
|
1693
|
+
def set_cl_multibox(self, condition, wire_map, top_connect="┴"):
|
1694
|
+
"""Sets the multi clbit box.
|
1695
|
+
|
1696
|
+
Args:
|
1697
|
+
condition (list[Union(Clbit, ClassicalRegister), int]): The condition
|
1698
|
+
wire_map (dict): Map of bits to indices
|
1699
|
+
top_connect (char): The char to connect the box on the top.
|
1700
|
+
|
1701
|
+
Returns:
|
1702
|
+
List: list of tuples of connections between clbits for multi-bit conditions
|
1703
|
+
"""
|
1704
|
+
if isinstance(condition, expr.Expr):
|
1705
|
+
# If fixing this, please update the docstrings of `QuantumCircuit.draw` and
|
1706
|
+
# `visualization.circuit_drawer` to remove warnings.
|
1707
|
+
label = "[expr]"
|
1708
|
+
out = []
|
1709
|
+
condition_bits = node_resources(condition).clbits
|
1710
|
+
registers = collections.defaultdict(list)
|
1711
|
+
for bit in condition_bits:
|
1712
|
+
registers[get_bit_register(self._circuit, bit)].append(bit)
|
1713
|
+
if registerless := registers.pop(None, ()):
|
1714
|
+
out.extend(
|
1715
|
+
self.set_cond_bullets(label, ["1"] * len(registerless), registerless, wire_map)
|
1716
|
+
)
|
1717
|
+
if self.cregbundle:
|
1718
|
+
# It's hard to do something properly sensible here without more major rewrites, so
|
1719
|
+
# as a minimum to *not crash* we'll just treat a condition that touches part of a
|
1720
|
+
# register like it touched the whole register.
|
1721
|
+
for register in registers:
|
1722
|
+
self.set_clbit(register[0], BoxOnClWire(label=label, top_connect=top_connect))
|
1723
|
+
else:
|
1724
|
+
for register, bits in registers.items():
|
1725
|
+
out.extend(self.set_cond_bullets(label, ["1"] * len(bits), bits, wire_map))
|
1726
|
+
return out
|
1727
|
+
|
1728
|
+
label, val_bits = get_condition_label_val(condition, self._circuit, self.cregbundle)
|
1729
|
+
if isinstance(condition[0], ClassicalRegister):
|
1730
|
+
cond_reg = condition[0]
|
1731
|
+
else:
|
1732
|
+
cond_reg = get_bit_register(self._circuit, condition[0])
|
1733
|
+
if self.cregbundle:
|
1734
|
+
if isinstance(condition[0], Clbit):
|
1735
|
+
# if it's a registerless Clbit
|
1736
|
+
if cond_reg is None:
|
1737
|
+
self.set_cond_bullets(label, val_bits, [condition[0]], wire_map)
|
1738
|
+
# if it's a single bit in a register
|
1739
|
+
else:
|
1740
|
+
self.set_clbit(condition[0], BoxOnClWire(label=label, top_connect=top_connect))
|
1741
|
+
# if it's a whole register
|
1742
|
+
else:
|
1743
|
+
self.set_clbit(condition[0][0], BoxOnClWire(label=label, top_connect=top_connect))
|
1744
|
+
return []
|
1745
|
+
else:
|
1746
|
+
if isinstance(condition[0], Clbit):
|
1747
|
+
clbits = [condition[0]]
|
1748
|
+
else:
|
1749
|
+
clbits = [cond_reg[idx] for idx in range(cond_reg.size)]
|
1750
|
+
return self.set_cond_bullets(label, val_bits, clbits, wire_map)
|
1751
|
+
|
1752
|
+
def set_cond_bullets(self, label, val_bits, clbits, wire_map):
|
1753
|
+
"""Sets bullets for classical conditioning when cregbundle=False.
|
1754
|
+
|
1755
|
+
Args:
|
1756
|
+
label (str): String to display below the condition
|
1757
|
+
val_bits (list(int)): A list of bit values
|
1758
|
+
clbits (list[Clbit]): The list of classical bits on
|
1759
|
+
which the instruction is conditioned.
|
1760
|
+
wire_map (dict): Map of bits to indices
|
1761
|
+
|
1762
|
+
Returns:
|
1763
|
+
List: list of tuples of open or closed bullets for condition bits
|
1764
|
+
"""
|
1765
|
+
current_cons = []
|
1766
|
+
wire_max = max(wire_map[bit] for bit in clbits)
|
1767
|
+
for i, bit in enumerate(clbits):
|
1768
|
+
bot_connect = " "
|
1769
|
+
if wire_map[bit] == wire_max:
|
1770
|
+
bot_connect = label
|
1771
|
+
if val_bits[i] == "1":
|
1772
|
+
self.clbit_layer[wire_map[bit] - len(self.qubits)] = ClBullet(
|
1773
|
+
top_connect="║", bot_connect=bot_connect
|
1774
|
+
)
|
1775
|
+
elif val_bits[i] == "0":
|
1776
|
+
self.clbit_layer[wire_map[bit] - len(self.qubits)] = ClOpenBullet(
|
1777
|
+
top_connect="║", bot_connect=bot_connect
|
1778
|
+
)
|
1779
|
+
actual_index = wire_map[bit]
|
1780
|
+
if actual_index not in [i for i, j in current_cons]:
|
1781
|
+
current_cons.append(
|
1782
|
+
(actual_index, self.clbit_layer[wire_map[bit] - len(self.qubits)])
|
1783
|
+
)
|
1784
|
+
return current_cons
|
1785
|
+
|
1786
|
+
def set_qu_multibox(
|
1787
|
+
self,
|
1788
|
+
bits,
|
1789
|
+
label,
|
1790
|
+
top_connect=None,
|
1791
|
+
bot_connect=None,
|
1792
|
+
conditional=False,
|
1793
|
+
controlled_edge=None,
|
1794
|
+
):
|
1795
|
+
"""Sets the multi qubit box.
|
1796
|
+
|
1797
|
+
Args:
|
1798
|
+
bits (list[int]): A list of affected bits.
|
1799
|
+
label (string): The label for the multi qubit box.
|
1800
|
+
top_connect (char): None or a char connector on the top
|
1801
|
+
bot_connect (char): None or a char connector on the bottom
|
1802
|
+
conditional (bool): If the box has a conditional
|
1803
|
+
controlled_edge (list): A list of bit that are controlled (to draw them at the edge)
|
1804
|
+
Return:
|
1805
|
+
List: A list of indexes of the box.
|
1806
|
+
"""
|
1807
|
+
return self._set_multibox(
|
1808
|
+
label,
|
1809
|
+
qargs=bits,
|
1810
|
+
top_connect=top_connect,
|
1811
|
+
bot_connect=bot_connect,
|
1812
|
+
conditional=conditional,
|
1813
|
+
controlled_edge=controlled_edge,
|
1814
|
+
)
|
1815
|
+
|
1816
|
+
def connect_with(self, wire_char):
|
1817
|
+
"""Connects the elements in the layer using wire_char.
|
1818
|
+
|
1819
|
+
Args:
|
1820
|
+
wire_char (char): For example '║' or '│'.
|
1821
|
+
"""
|
1822
|
+
|
1823
|
+
for label, affected_bits in self.connections:
|
1824
|
+
|
1825
|
+
if not affected_bits:
|
1826
|
+
continue
|
1827
|
+
|
1828
|
+
for index, affected_bit in enumerate(affected_bits):
|
1829
|
+
if isinstance(affected_bit, (ClBullet, ClOpenBullet)):
|
1830
|
+
wire_char = "║"
|
1831
|
+
if index == 0 and len(affected_bits) > 1:
|
1832
|
+
affected_bit.connect(wire_char, ["bot"])
|
1833
|
+
elif index == len(affected_bits) - 1:
|
1834
|
+
affected_bit.connect(wire_char, ["top"])
|
1835
|
+
else:
|
1836
|
+
affected_bit.connect(wire_char, ["bot", "top"])
|
1837
|
+
else:
|
1838
|
+
if index == 0:
|
1839
|
+
affected_bit.connect(wire_char, ["bot"])
|
1840
|
+
elif index == len(affected_bits) - 1:
|
1841
|
+
affected_bit.connect(wire_char, ["top"], label)
|
1842
|
+
else:
|
1843
|
+
affected_bit.connect(wire_char, ["bot", "top"])
|
1844
|
+
|
1845
|
+
if label:
|
1846
|
+
for affected_bit in affected_bits:
|
1847
|
+
affected_bit.right_fill = len(label) + len(affected_bit.mid)
|
1848
|
+
if isinstance(affected_bit, (Bullet, OpenBullet)) and affected_bit.conditional:
|
1849
|
+
affected_bit.left_fill = len(label) + len(affected_bit.mid)
|