qiskit 1.3.0b1__cp39-abi3-win32.whl → 1.3.0rc2__cp39-abi3-win32.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 -1
- qiskit/__init__.py +20 -1
- qiskit/_accelerate.pyd +0 -0
- qiskit/assembler/assemble_schedules.py +2 -0
- qiskit/circuit/__init__.py +44 -1
- qiskit/circuit/_standard_gates_commutations.py +585 -0
- qiskit/circuit/barrier.py +2 -0
- qiskit/circuit/controlflow/builder.py +3 -3
- qiskit/circuit/controlflow/if_else.py +13 -5
- qiskit/circuit/controlflow/while_loop.py +10 -2
- qiskit/circuit/delay.py +20 -3
- qiskit/circuit/equivalence.py +13 -214
- qiskit/circuit/gate.py +3 -1
- qiskit/circuit/instruction.py +32 -11
- qiskit/circuit/instructionset.py +2 -0
- qiskit/circuit/library/__init__.py +110 -14
- qiskit/circuit/library/arithmetic/__init__.py +9 -2
- qiskit/circuit/library/arithmetic/adders/__init__.py +1 -0
- qiskit/circuit/library/arithmetic/adders/adder.py +154 -2
- qiskit/circuit/library/arithmetic/adders/cdkm_ripple_carry_adder.py +20 -56
- qiskit/circuit/library/arithmetic/adders/draper_qft_adder.py +14 -1
- qiskit/circuit/library/arithmetic/adders/vbe_ripple_carry_adder.py +21 -91
- qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +1 -1
- qiskit/circuit/library/arithmetic/multipliers/__init__.py +1 -0
- qiskit/circuit/library/arithmetic/multipliers/hrs_cumulative_multiplier.py +8 -1
- qiskit/circuit/library/arithmetic/multipliers/multiplier.py +94 -3
- qiskit/circuit/library/arithmetic/multipliers/rg_qft_multiplier.py +8 -1
- qiskit/circuit/library/arithmetic/weighted_adder.py +1 -1
- qiskit/circuit/library/basis_change/qft.py +20 -38
- qiskit/circuit/library/blueprintcircuit.py +64 -0
- qiskit/circuit/library/boolean_logic/__init__.py +4 -4
- qiskit/circuit/library/boolean_logic/inner_product.py +81 -4
- qiskit/circuit/library/boolean_logic/quantum_and.py +107 -4
- qiskit/circuit/library/boolean_logic/quantum_or.py +107 -3
- qiskit/circuit/library/boolean_logic/quantum_xor.py +97 -3
- qiskit/circuit/library/data_preparation/__init__.py +6 -3
- qiskit/circuit/library/data_preparation/{z_feature_map.py → _z_feature_map.py} +45 -34
- qiskit/circuit/library/data_preparation/_zz_feature_map.py +150 -0
- qiskit/circuit/library/data_preparation/pauli_feature_map.py +342 -29
- qiskit/circuit/library/fourier_checking.py +72 -11
- qiskit/circuit/library/generalized_gates/__init__.py +1 -1
- qiskit/circuit/library/generalized_gates/diagonal.py +45 -51
- qiskit/circuit/library/generalized_gates/gms.py +67 -14
- qiskit/circuit/library/generalized_gates/gr.py +4 -4
- qiskit/circuit/library/generalized_gates/isometry.py +2 -2
- qiskit/circuit/library/generalized_gates/linear_function.py +12 -6
- qiskit/circuit/library/generalized_gates/mcmt.py +167 -107
- qiskit/circuit/library/generalized_gates/permutation.py +8 -6
- qiskit/circuit/library/generalized_gates/rv.py +8 -9
- qiskit/circuit/library/graph_state.py +93 -10
- qiskit/circuit/library/grover_operator.py +270 -2
- qiskit/circuit/library/hidden_linear_function.py +83 -20
- qiskit/circuit/library/iqp.py +99 -20
- qiskit/circuit/library/n_local/__init__.py +19 -7
- qiskit/circuit/library/n_local/efficient_su2.py +118 -5
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +259 -0
- qiskit/circuit/library/n_local/excitation_preserving.py +130 -6
- qiskit/circuit/library/n_local/n_local.py +406 -5
- qiskit/circuit/library/n_local/pauli_two_design.py +106 -4
- qiskit/circuit/library/n_local/qaoa_ansatz.py +80 -1
- qiskit/circuit/library/n_local/real_amplitudes.py +127 -7
- qiskit/circuit/library/n_local/two_local.py +14 -7
- qiskit/circuit/library/overlap.py +91 -26
- qiskit/circuit/library/pauli_evolution.py +17 -15
- qiskit/circuit/library/phase_estimation.py +80 -4
- qiskit/circuit/library/quantum_volume.py +72 -20
- qiskit/circuit/library/standard_gates/__init__.py +20 -1
- qiskit/circuit/library/standard_gates/dcx.py +2 -1
- qiskit/circuit/library/standard_gates/ecr.py +2 -2
- qiskit/circuit/library/standard_gates/h.py +4 -3
- qiskit/circuit/library/standard_gates/i.py +2 -1
- qiskit/circuit/library/standard_gates/iswap.py +2 -2
- qiskit/circuit/library/standard_gates/p.py +20 -12
- qiskit/circuit/library/standard_gates/r.py +1 -1
- qiskit/circuit/library/standard_gates/rx.py +4 -3
- qiskit/circuit/library/standard_gates/rxx.py +2 -2
- qiskit/circuit/library/standard_gates/ry.py +4 -3
- qiskit/circuit/library/standard_gates/ryy.py +2 -2
- qiskit/circuit/library/standard_gates/rz.py +13 -12
- qiskit/circuit/library/standard_gates/rzx.py +6 -6
- qiskit/circuit/library/standard_gates/rzz.py +1 -1
- qiskit/circuit/library/standard_gates/s.py +4 -4
- qiskit/circuit/library/standard_gates/swap.py +3 -3
- qiskit/circuit/library/standard_gates/sx.py +4 -3
- qiskit/circuit/library/standard_gates/t.py +2 -2
- qiskit/circuit/library/standard_gates/u.py +11 -3
- qiskit/circuit/library/standard_gates/u1.py +65 -15
- qiskit/circuit/library/standard_gates/u2.py +4 -1
- qiskit/circuit/library/standard_gates/u3.py +31 -3
- qiskit/circuit/library/standard_gates/x.py +7 -5
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +2 -2
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +2 -2
- qiskit/circuit/library/standard_gates/y.py +4 -3
- qiskit/circuit/library/standard_gates/z.py +3 -3
- qiskit/circuit/library/templates/clifford/clifford_2_1.py +9 -8
- qiskit/circuit/library/templates/clifford/clifford_2_2.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_2_3.py +9 -7
- qiskit/circuit/library/templates/clifford/clifford_2_4.py +9 -8
- qiskit/circuit/library/templates/clifford/clifford_3_1.py +9 -8
- qiskit/circuit/library/templates/clifford/clifford_4_1.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_4_2.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_4_3.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_4_4.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_5_1.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_6_1.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_6_2.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_6_3.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_6_4.py +9 -8
- qiskit/circuit/library/templates/clifford/clifford_6_5.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_8_1.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_8_2.py +10 -9
- qiskit/circuit/library/templates/clifford/clifford_8_3.py +10 -9
- qiskit/circuit/library/templates/nct/template_nct_2a_1.py +9 -7
- qiskit/circuit/library/templates/nct/template_nct_2a_2.py +10 -8
- qiskit/circuit/library/templates/nct/template_nct_2a_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_4a_1.py +16 -14
- qiskit/circuit/library/templates/nct/template_nct_4a_2.py +14 -12
- qiskit/circuit/library/templates/nct/template_nct_4a_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_4b_1.py +14 -12
- qiskit/circuit/library/templates/nct/template_nct_4b_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_5a_1.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_5a_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_5a_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_5a_4.py +11 -9
- qiskit/circuit/library/templates/nct/template_nct_6a_1.py +11 -9
- qiskit/circuit/library/templates/nct/template_nct_6a_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_6a_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_6a_4.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_6b_1.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_6b_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_6c_1.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_7a_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_7b_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_7c_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_7d_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_7e_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_9a_1.py +13 -11
- qiskit/circuit/library/templates/nct/template_nct_9c_1.py +11 -9
- qiskit/circuit/library/templates/nct/template_nct_9c_10.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_11.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_12.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_4.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_5.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_6.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_7.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_8.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9c_9.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_1.py +11 -9
- qiskit/circuit/library/templates/nct/template_nct_9d_10.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_2.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_3.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_4.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_5.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_6.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_7.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_8.py +12 -10
- qiskit/circuit/library/templates/nct/template_nct_9d_9.py +12 -10
- qiskit/circuit/library/templates/rzx/rzx_cy.py +11 -10
- qiskit/circuit/library/templates/rzx/rzx_xz.py +16 -15
- qiskit/circuit/library/templates/rzx/rzx_yz.py +12 -10
- qiskit/circuit/library/templates/rzx/rzx_zz1.py +22 -20
- qiskit/circuit/library/templates/rzx/rzx_zz2.py +16 -15
- qiskit/circuit/library/templates/rzx/rzx_zz3.py +17 -15
- qiskit/circuit/parameter.py +4 -0
- qiskit/circuit/parameterexpression.py +167 -34
- qiskit/circuit/quantumcircuit.py +162 -126
- qiskit/circuit/singleton.py +2 -0
- qiskit/circuit/store.py +2 -0
- qiskit/circuit/twirling.py +145 -0
- qiskit/compiler/assembler.py +17 -4
- qiskit/compiler/scheduler.py +2 -0
- qiskit/compiler/sequencer.py +2 -0
- qiskit/compiler/transpiler.py +81 -26
- qiskit/converters/circuit_to_dag.py +2 -2
- qiskit/converters/circuit_to_dagdependency.py +1 -1
- qiskit/converters/circuit_to_dagdependency_v2.py +1 -1
- qiskit/converters/circuit_to_instruction.py +1 -1
- qiskit/converters/dag_to_circuit.py +7 -5
- qiskit/converters/dag_to_dagdependency.py +1 -1
- qiskit/converters/dag_to_dagdependency_v2.py +1 -1
- qiskit/converters/dagdependency_to_circuit.py +5 -1
- qiskit/converters/dagdependency_to_dag.py +6 -1
- qiskit/dagcircuit/collect_blocks.py +3 -3
- qiskit/dagcircuit/dagdependency.py +18 -5
- qiskit/dagcircuit/dagdependency_v2.py +1 -1
- qiskit/dagcircuit/dagnode.py +2 -2
- qiskit/passmanager/__init__.py +2 -2
- qiskit/primitives/backend_estimator.py +5 -2
- qiskit/primitives/backend_sampler_v2.py +61 -18
- qiskit/primitives/base/base_estimator.py +2 -2
- qiskit/primitives/containers/data_bin.py +9 -1
- qiskit/primitives/statevector_sampler.py +1 -1
- qiskit/primitives/utils.py +1 -1
- qiskit/providers/__init__.py +3 -3
- qiskit/providers/backend.py +12 -1
- qiskit/providers/backend_compat.py +23 -3
- qiskit/providers/basic_provider/basic_simulator.py +12 -2
- qiskit/providers/fake_provider/fake_pulse_backend.py +6 -1
- qiskit/providers/fake_provider/generic_backend_v2.py +46 -30
- qiskit/providers/models/pulsedefaults.py +2 -0
- qiskit/pulse/builder.py +59 -18
- qiskit/pulse/calibration_entries.py +4 -1
- qiskit/pulse/channels.py +2 -0
- qiskit/pulse/exceptions.py +2 -0
- qiskit/pulse/instruction_schedule_map.py +21 -6
- qiskit/pulse/instructions/acquire.py +2 -0
- qiskit/pulse/instructions/delay.py +2 -0
- qiskit/pulse/instructions/directives.py +8 -0
- qiskit/pulse/instructions/frequency.py +3 -0
- qiskit/pulse/instructions/instruction.py +2 -0
- qiskit/pulse/instructions/phase.py +3 -0
- qiskit/pulse/instructions/play.py +2 -0
- qiskit/pulse/instructions/reference.py +2 -0
- qiskit/pulse/instructions/snapshot.py +2 -0
- qiskit/pulse/library/pulse.py +2 -0
- qiskit/pulse/library/symbolic_pulses.py +28 -0
- qiskit/pulse/library/waveform.py +2 -0
- qiskit/pulse/macros.py +1 -1
- qiskit/pulse/schedule.py +12 -13
- qiskit/pulse/transforms/alignments.py +5 -3
- qiskit/pulse/transforms/dag.py +7 -0
- qiskit/qasm2/export.py +5 -3
- qiskit/qasm2/parse.py +46 -2
- qiskit/qasm3/__init__.py +1 -0
- qiskit/qasm3/ast.py +123 -15
- qiskit/qasm3/exporter.py +103 -77
- qiskit/qobj/converters/pulse_instruction.py +6 -4
- qiskit/qpy/__init__.py +181 -0
- qiskit/qpy/binary_io/circuits.py +20 -5
- qiskit/qpy/binary_io/schedules.py +3 -4
- qiskit/qpy/binary_io/value.py +310 -13
- qiskit/qpy/common.py +46 -2
- qiskit/qpy/formats.py +7 -0
- qiskit/qpy/interface.py +40 -4
- qiskit/quantum_info/__init__.py +4 -0
- qiskit/quantum_info/operators/channel/transformations.py +28 -21
- qiskit/quantum_info/operators/dihedral/dihedral.py +1 -1
- qiskit/quantum_info/operators/operator.py +54 -8
- qiskit/quantum_info/operators/symplectic/base_pauli.py +11 -19
- qiskit/quantum_info/operators/symplectic/clifford.py +1 -1
- qiskit/quantum_info/operators/symplectic/clifford_circuits.py +1 -1
- qiskit/quantum_info/operators/symplectic/pauli.py +2 -0
- qiskit/quantum_info/operators/symplectic/pauli_list.py +4 -4
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +23 -2
- qiskit/quantum_info/states/densitymatrix.py +5 -5
- qiskit/quantum_info/states/stabilizerstate.py +1 -1
- qiskit/quantum_info/states/statevector.py +6 -6
- qiskit/result/mitigation/base_readout_mitigator.py +1 -1
- qiskit/result/mitigation/correlated_readout_mitigator.py +9 -1
- qiskit/result/mitigation/local_readout_mitigator.py +9 -1
- qiskit/result/mitigation/utils.py +57 -0
- qiskit/scheduler/config.py +2 -0
- qiskit/scheduler/methods/basic.py +3 -0
- qiskit/scheduler/schedule_circuit.py +2 -0
- qiskit/scheduler/sequence.py +2 -0
- qiskit/synthesis/__init__.py +25 -0
- qiskit/synthesis/arithmetic/__init__.py +16 -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/multipliers/__init__.py +16 -0
- qiskit/synthesis/arithmetic/multipliers/hrs_cumulative_multiplier.py +102 -0
- qiskit/synthesis/arithmetic/multipliers/rg_qft_multiplier.py +99 -0
- qiskit/synthesis/clifford/clifford_decompose_bm.py +1 -2
- qiskit/synthesis/clifford/clifford_decompose_greedy.py +3 -2
- qiskit/synthesis/clifford/clifford_decompose_layers.py +2 -1
- qiskit/synthesis/evolution/__init__.py +1 -0
- qiskit/synthesis/evolution/lie_trotter.py +16 -42
- qiskit/synthesis/evolution/pauli_network.py +80 -0
- qiskit/synthesis/evolution/product_formula.py +165 -238
- qiskit/synthesis/evolution/qdrift.py +36 -29
- qiskit/synthesis/evolution/suzuki_trotter.py +87 -27
- qiskit/synthesis/multi_controlled/__init__.py +1 -0
- qiskit/synthesis/multi_controlled/mcmt_vchain.py +52 -0
- qiskit/synthesis/qft/qft_decompose_full.py +19 -1
- qiskit/synthesis/qft/qft_decompose_lnn.py +2 -1
- qiskit/synthesis/stabilizer/stabilizer_decompose.py +2 -1
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +4 -63
- qiskit/synthesis/unitary/qsd.py +5 -5
- qiskit/transpiler/__init__.py +21 -14
- qiskit/transpiler/basepasses.py +1 -1
- qiskit/transpiler/passes/__init__.py +2 -0
- qiskit/transpiler/passes/basis/basis_translator.py +9 -565
- qiskit/transpiler/passes/basis/decompose.py +45 -12
- qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
- qiskit/transpiler/passes/basis/unroll_custom_definitions.py +1 -1
- qiskit/transpiler/passes/calibration/pulse_gate.py +4 -2
- qiskit/transpiler/passes/calibration/rx_builder.py +11 -7
- qiskit/transpiler/passes/calibration/rzx_builder.py +46 -30
- qiskit/transpiler/passes/layout/disjoint_utils.py +15 -13
- qiskit/transpiler/passes/layout/sabre_layout.py +7 -2
- qiskit/transpiler/passes/layout/sabre_pre_layout.py +5 -0
- qiskit/transpiler/passes/optimization/__init__.py +1 -0
- qiskit/transpiler/passes/optimization/collect_cliffords.py +19 -3
- qiskit/transpiler/passes/optimization/collect_linear_functions.py +1 -1
- qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +2 -2
- qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py +1 -1
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +48 -131
- qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py +4 -2
- qiskit/transpiler/passes/optimization/elide_permutations.py +9 -32
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +5 -11
- qiskit/transpiler/passes/optimization/optimize_1q_gates.py +1 -1
- qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py +1 -1
- qiskit/transpiler/passes/optimization/remove_identity_equiv.py +69 -0
- qiskit/transpiler/passes/optimization/template_matching/backward_match.py +5 -5
- qiskit/transpiler/passes/optimization/template_matching/forward_match.py +4 -4
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +2 -2
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +1 -1
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/swap_strategy.py +1 -1
- qiskit/transpiler/passes/routing/sabre_swap.py +7 -3
- qiskit/transpiler/passes/routing/star_prerouting.py +2 -2
- qiskit/transpiler/passes/scheduling/alap.py +1 -1
- qiskit/transpiler/passes/scheduling/alignments/align_measures.py +2 -2
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
- qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +2 -0
- qiskit/transpiler/passes/scheduling/alignments/reschedule.py +2 -2
- qiskit/transpiler/passes/scheduling/asap.py +1 -1
- qiskit/transpiler/passes/scheduling/base_scheduler.py +14 -12
- qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +9 -4
- qiskit/transpiler/passes/scheduling/padding/base_padding.py +1 -1
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +16 -5
- qiskit/transpiler/passes/scheduling/padding/pad_delay.py +4 -1
- qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +6 -2
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +9 -4
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +262 -99
- qiskit/transpiler/passes/synthesis/hls_plugins.py +637 -7
- qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +3 -3
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +55 -34
- qiskit/transpiler/passes/utils/barrier_before_final_measurements.py +2 -56
- qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +5 -0
- qiskit/transpiler/passes/utils/gate_direction.py +12 -275
- qiskit/transpiler/passes/utils/gates_basis.py +7 -30
- qiskit/transpiler/passes/utils/merge_adjacent_barriers.py +2 -1
- qiskit/transpiler/passmanager_config.py +22 -4
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +40 -14
- qiskit/transpiler/preset_passmanagers/common.py +5 -3
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +125 -42
- qiskit/transpiler/preset_passmanagers/plugin.py +1 -1
- qiskit/transpiler/target.py +74 -16
- qiskit/utils/deprecate_pulse.py +119 -0
- qiskit/visualization/circuit/_utils.py +2 -2
- qiskit/visualization/circuit/circuit_visualization.py +3 -2
- qiskit/visualization/circuit/matplotlib.py +1 -1
- qiskit/visualization/dag_visualization.py +1 -1
- qiskit/visualization/pass_manager_visualization.py +3 -14
- qiskit/visualization/pulse_v2/interface.py +3 -1
- qiskit/visualization/timeline/core.py +25 -2
- qiskit/visualization/timeline/interface.py +12 -0
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/METADATA +9 -8
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/RECORD +357 -346
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/WHEEL +1 -1
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/entry_points.txt +19 -0
- qiskit/circuit/library/data_preparation/zz_feature_map.py +0 -118
- qiskit/synthesis/two_qubit/weyl.py +0 -97
- qiskit/transpiler/passes/synthesis/qubit_tracker.py +0 -132
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.3.0b1.dist-info → qiskit-1.3.0rc2.dist-info}/top_level.txt +0 -0
@@ -13,29 +13,12 @@
|
|
13
13
|
|
14
14
|
"""Translates gates to a target basis using a given equivalence library."""
|
15
15
|
|
16
|
-
import time
|
17
16
|
import logging
|
18
17
|
|
19
|
-
from functools import singledispatchmethod
|
20
|
-
from itertools import zip_longest
|
21
18
|
from collections import defaultdict
|
22
19
|
|
23
|
-
import rustworkx
|
24
|
-
|
25
|
-
from qiskit.circuit import (
|
26
|
-
Gate,
|
27
|
-
ParameterVector,
|
28
|
-
QuantumRegister,
|
29
|
-
ControlFlowOp,
|
30
|
-
QuantumCircuit,
|
31
|
-
ParameterExpression,
|
32
|
-
)
|
33
|
-
from qiskit.dagcircuit import DAGCircuit, DAGOpNode
|
34
|
-
from qiskit.converters import circuit_to_dag, dag_to_circuit
|
35
|
-
from qiskit.circuit.equivalence import Key, NodeData
|
36
20
|
from qiskit.transpiler.basepasses import TransformationPass
|
37
|
-
from qiskit.
|
38
|
-
from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES
|
21
|
+
from qiskit._accelerate.basis.basis_translator import base_run
|
39
22
|
|
40
23
|
logger = logging.getLogger(__name__)
|
41
24
|
|
@@ -142,552 +125,13 @@ class BasisTranslator(TransformationPass):
|
|
142
125
|
Returns:
|
143
126
|
DAGCircuit: translated circuit.
|
144
127
|
"""
|
145
|
-
if self._target_basis is None and self._target is None:
|
146
|
-
return dag
|
147
|
-
|
148
|
-
qarg_indices = {qubit: index for index, qubit in enumerate(dag.qubits)}
|
149
|
-
|
150
|
-
# Names of instructions assumed to supported by any backend.
|
151
|
-
if self._target is None:
|
152
|
-
basic_instrs = ["measure", "reset", "barrier", "snapshot", "delay", "store"]
|
153
|
-
target_basis = set(self._target_basis)
|
154
|
-
source_basis = set(self._extract_basis(dag))
|
155
|
-
qargs_local_source_basis = {}
|
156
|
-
else:
|
157
|
-
basic_instrs = ["barrier", "snapshot", "store"]
|
158
|
-
target_basis = self._target.keys() - set(self._non_global_operations)
|
159
|
-
source_basis, qargs_local_source_basis = self._extract_basis_target(dag, qarg_indices)
|
160
|
-
|
161
|
-
target_basis = set(target_basis).union(basic_instrs)
|
162
|
-
# If the source basis is a subset of the target basis and we have no circuit
|
163
|
-
# instructions on qargs that have non-global operations there is nothing to
|
164
|
-
# translate and we can exit early.
|
165
|
-
source_basis_names = {x[0] for x in source_basis}
|
166
|
-
if source_basis_names.issubset(target_basis) and not qargs_local_source_basis:
|
167
|
-
return dag
|
168
|
-
|
169
|
-
logger.info(
|
170
|
-
"Begin BasisTranslator from source basis %s to target basis %s.",
|
171
|
-
source_basis,
|
172
|
-
target_basis,
|
173
|
-
)
|
174
|
-
|
175
|
-
# Search for a path from source to target basis.
|
176
|
-
search_start_time = time.time()
|
177
|
-
basis_transforms = _basis_search(self._equiv_lib, source_basis, target_basis)
|
178
|
-
|
179
|
-
qarg_local_basis_transforms = {}
|
180
|
-
for qarg, local_source_basis in qargs_local_source_basis.items():
|
181
|
-
expanded_target = set(target_basis)
|
182
|
-
# For any multiqubit operation that contains a subset of qubits that
|
183
|
-
# has a non-local operation, include that non-local operation in the
|
184
|
-
# search. This matches with the check we did above to include those
|
185
|
-
# subset non-local operations in the check here.
|
186
|
-
if len(qarg) > 1:
|
187
|
-
for non_local_qarg, local_basis in self._qargs_with_non_global_operation.items():
|
188
|
-
if qarg.issuperset(non_local_qarg):
|
189
|
-
expanded_target |= local_basis
|
190
|
-
else:
|
191
|
-
expanded_target |= self._qargs_with_non_global_operation[tuple(qarg)]
|
192
|
-
|
193
|
-
logger.info(
|
194
|
-
"Performing BasisTranslator search from source basis %s to target "
|
195
|
-
"basis %s on qarg %s.",
|
196
|
-
local_source_basis,
|
197
|
-
expanded_target,
|
198
|
-
qarg,
|
199
|
-
)
|
200
|
-
local_basis_transforms = _basis_search(
|
201
|
-
self._equiv_lib, local_source_basis, expanded_target
|
202
|
-
)
|
203
|
-
|
204
|
-
if local_basis_transforms is None:
|
205
|
-
raise TranspilerError(
|
206
|
-
"Unable to translate the operations in the circuit: "
|
207
|
-
f"{[x[0] for x in local_source_basis]} to the backend's (or manually "
|
208
|
-
f"specified) target basis: {list(expanded_target)}. This likely means the "
|
209
|
-
"target basis is not universal or there are additional equivalence rules "
|
210
|
-
"needed in the EquivalenceLibrary being used. For more details on this "
|
211
|
-
"error see: "
|
212
|
-
"https://docs.quantum.ibm.com/api/qiskit/qiskit.transpiler.passes."
|
213
|
-
"BasisTranslator#translation-errors"
|
214
|
-
)
|
215
|
-
|
216
|
-
qarg_local_basis_transforms[qarg] = local_basis_transforms
|
217
|
-
|
218
|
-
search_end_time = time.time()
|
219
|
-
logger.info(
|
220
|
-
"Basis translation path search completed in %.3fs.", search_end_time - search_start_time
|
221
|
-
)
|
222
|
-
|
223
|
-
if basis_transforms is None:
|
224
|
-
raise TranspilerError(
|
225
|
-
"Unable to translate the operations in the circuit: "
|
226
|
-
f"{[x[0] for x in source_basis]} to the backend's (or manually specified) target "
|
227
|
-
f"basis: {list(target_basis)}. This likely means the target basis is not universal "
|
228
|
-
"or there are additional equivalence rules needed in the EquivalenceLibrary being "
|
229
|
-
"used. For more details on this error see: "
|
230
|
-
"https://docs.quantum.ibm.com/api/qiskit/qiskit.transpiler.passes."
|
231
|
-
"BasisTranslator#translation-errors"
|
232
|
-
)
|
233
|
-
|
234
|
-
# Compose found path into a set of instruction substitution rules.
|
235
|
-
|
236
|
-
compose_start_time = time.time()
|
237
|
-
instr_map = _compose_transforms(basis_transforms, source_basis, dag)
|
238
|
-
extra_instr_map = {
|
239
|
-
qarg: _compose_transforms(transforms, qargs_local_source_basis[qarg], dag)
|
240
|
-
for qarg, transforms in qarg_local_basis_transforms.items()
|
241
|
-
}
|
242
|
-
|
243
|
-
compose_end_time = time.time()
|
244
|
-
logger.info(
|
245
|
-
"Basis translation paths composed in %.3fs.", compose_end_time - compose_start_time
|
246
|
-
)
|
247
|
-
|
248
|
-
# Replace source instructions with target translations.
|
249
|
-
|
250
|
-
replace_start_time = time.time()
|
251
|
-
|
252
|
-
def apply_translation(dag, wire_map):
|
253
|
-
is_updated = False
|
254
|
-
out_dag = dag.copy_empty_like()
|
255
|
-
for node in dag.topological_op_nodes():
|
256
|
-
node_qargs = tuple(wire_map[bit] for bit in node.qargs)
|
257
|
-
qubit_set = frozenset(node_qargs)
|
258
|
-
if node.name in target_basis or len(node.qargs) < self._min_qubits:
|
259
|
-
if node.name in CONTROL_FLOW_OP_NAMES:
|
260
|
-
flow_blocks = []
|
261
|
-
for block in node.op.blocks:
|
262
|
-
dag_block = circuit_to_dag(block)
|
263
|
-
updated_dag, is_updated = apply_translation(
|
264
|
-
dag_block,
|
265
|
-
{
|
266
|
-
inner: wire_map[outer]
|
267
|
-
for inner, outer in zip(block.qubits, node.qargs)
|
268
|
-
},
|
269
|
-
)
|
270
|
-
if is_updated:
|
271
|
-
flow_circ_block = dag_to_circuit(updated_dag)
|
272
|
-
else:
|
273
|
-
flow_circ_block = block
|
274
|
-
flow_blocks.append(flow_circ_block)
|
275
|
-
node.op = node.op.replace_blocks(flow_blocks)
|
276
|
-
out_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
|
277
|
-
continue
|
278
|
-
if (
|
279
|
-
node_qargs in self._qargs_with_non_global_operation
|
280
|
-
and node.name in self._qargs_with_non_global_operation[node_qargs]
|
281
|
-
):
|
282
|
-
out_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
|
283
|
-
continue
|
284
|
-
|
285
|
-
if dag.has_calibration_for(node):
|
286
|
-
out_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
|
287
|
-
continue
|
288
|
-
if qubit_set in extra_instr_map:
|
289
|
-
self._replace_node(out_dag, node, extra_instr_map[qubit_set])
|
290
|
-
elif (node.name, node.num_qubits) in instr_map:
|
291
|
-
self._replace_node(out_dag, node, instr_map)
|
292
|
-
else:
|
293
|
-
raise TranspilerError(f"BasisTranslator did not map {node.name}.")
|
294
|
-
is_updated = True
|
295
|
-
return out_dag, is_updated
|
296
128
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
129
|
+
return base_run(
|
130
|
+
dag,
|
131
|
+
self._equiv_lib,
|
132
|
+
self._qargs_with_non_global_operation,
|
133
|
+
self._min_qubits,
|
134
|
+
None if self._target_basis is None else set(self._target_basis),
|
135
|
+
self._target,
|
136
|
+
None if self._non_global_operations is None else set(self._non_global_operations),
|
302
137
|
)
|
303
|
-
|
304
|
-
return out_dag
|
305
|
-
|
306
|
-
def _replace_node(self, dag, node, instr_map):
|
307
|
-
target_params, target_dag = instr_map[node.name, node.num_qubits]
|
308
|
-
if len(node.params) != len(target_params):
|
309
|
-
raise TranspilerError(
|
310
|
-
"Translation num_params not equal to op num_params."
|
311
|
-
f"Op: {node.params} {node.name} Translation: {target_params}\n{target_dag}"
|
312
|
-
)
|
313
|
-
if node.params:
|
314
|
-
parameter_map = dict(zip(target_params, node.params))
|
315
|
-
for inner_node in target_dag.topological_op_nodes():
|
316
|
-
new_node = DAGOpNode.from_instruction(inner_node._to_circuit_instruction())
|
317
|
-
new_node.qargs = tuple(
|
318
|
-
node.qargs[target_dag.find_bit(x).index] for x in inner_node.qargs
|
319
|
-
)
|
320
|
-
new_node.cargs = tuple(
|
321
|
-
node.cargs[target_dag.find_bit(x).index] for x in inner_node.cargs
|
322
|
-
)
|
323
|
-
|
324
|
-
if not new_node.is_standard_gate():
|
325
|
-
new_node.op = new_node.op.copy()
|
326
|
-
if any(isinstance(x, ParameterExpression) for x in inner_node.params):
|
327
|
-
new_params = []
|
328
|
-
for param in new_node.params:
|
329
|
-
if not isinstance(param, ParameterExpression):
|
330
|
-
new_params.append(param)
|
331
|
-
else:
|
332
|
-
bind_dict = {x: parameter_map[x] for x in param.parameters}
|
333
|
-
if any(isinstance(x, ParameterExpression) for x in bind_dict.values()):
|
334
|
-
new_value = param
|
335
|
-
for x in bind_dict.items():
|
336
|
-
new_value = new_value.assign(*x)
|
337
|
-
else:
|
338
|
-
new_value = param.bind(bind_dict)
|
339
|
-
if not new_value.parameters:
|
340
|
-
new_value = new_value.numeric()
|
341
|
-
new_params.append(new_value)
|
342
|
-
new_node.params = new_params
|
343
|
-
if not new_node.is_standard_gate():
|
344
|
-
new_node.op.params = new_params
|
345
|
-
dag._apply_op_node_back(new_node)
|
346
|
-
|
347
|
-
if isinstance(target_dag.global_phase, ParameterExpression):
|
348
|
-
old_phase = target_dag.global_phase
|
349
|
-
bind_dict = {x: parameter_map[x] for x in old_phase.parameters}
|
350
|
-
if any(isinstance(x, ParameterExpression) for x in bind_dict.values()):
|
351
|
-
new_phase = old_phase
|
352
|
-
for x in bind_dict.items():
|
353
|
-
new_phase = new_phase.assign(*x)
|
354
|
-
else:
|
355
|
-
new_phase = old_phase.bind(bind_dict)
|
356
|
-
if not new_phase.parameters:
|
357
|
-
new_phase = new_phase.numeric()
|
358
|
-
if isinstance(new_phase, complex):
|
359
|
-
raise TranspilerError(f"Global phase must be real, but got '{new_phase}'")
|
360
|
-
dag.global_phase += new_phase
|
361
|
-
|
362
|
-
else:
|
363
|
-
for inner_node in target_dag.topological_op_nodes():
|
364
|
-
new_node = DAGOpNode.from_instruction(
|
365
|
-
inner_node._to_circuit_instruction(),
|
366
|
-
)
|
367
|
-
new_node.qargs = tuple(
|
368
|
-
node.qargs[target_dag.find_bit(x).index] for x in inner_node.qargs
|
369
|
-
)
|
370
|
-
new_node.cargs = tuple(
|
371
|
-
node.cargs[target_dag.find_bit(x).index] for x in inner_node.cargs
|
372
|
-
)
|
373
|
-
if not new_node.is_standard_gate:
|
374
|
-
new_node.op = new_node.op.copy()
|
375
|
-
# dag_op may be the same instance as other ops in the dag,
|
376
|
-
# so if there is a condition, need to copy
|
377
|
-
if getattr(node.op, "condition", None):
|
378
|
-
new_node_op = new_node.op.to_mutable()
|
379
|
-
new_node_op.condition = node.op.condition
|
380
|
-
new_node.op = new_node_op
|
381
|
-
dag._apply_op_node_back(new_node)
|
382
|
-
if target_dag.global_phase:
|
383
|
-
dag.global_phase += target_dag.global_phase
|
384
|
-
|
385
|
-
@singledispatchmethod
|
386
|
-
def _extract_basis(self, circuit):
|
387
|
-
return circuit
|
388
|
-
|
389
|
-
@_extract_basis.register
|
390
|
-
def _(self, dag: DAGCircuit):
|
391
|
-
for node in dag.op_nodes():
|
392
|
-
if not dag.has_calibration_for(node) and len(node.qargs) >= self._min_qubits:
|
393
|
-
yield (node.name, node.num_qubits)
|
394
|
-
if node.name in CONTROL_FLOW_OP_NAMES:
|
395
|
-
for block in node.op.blocks:
|
396
|
-
yield from self._extract_basis(block)
|
397
|
-
|
398
|
-
@_extract_basis.register
|
399
|
-
def _(self, circ: QuantumCircuit):
|
400
|
-
for instruction in circ.data:
|
401
|
-
operation = instruction.operation
|
402
|
-
if (
|
403
|
-
not circ.has_calibration_for(instruction)
|
404
|
-
and len(instruction.qubits) >= self._min_qubits
|
405
|
-
):
|
406
|
-
yield (operation.name, operation.num_qubits)
|
407
|
-
if isinstance(operation, ControlFlowOp):
|
408
|
-
for block in operation.blocks:
|
409
|
-
yield from self._extract_basis(block)
|
410
|
-
|
411
|
-
def _extract_basis_target(
|
412
|
-
self, dag, qarg_indices, source_basis=None, qargs_local_source_basis=None
|
413
|
-
):
|
414
|
-
if source_basis is None:
|
415
|
-
source_basis = set()
|
416
|
-
if qargs_local_source_basis is None:
|
417
|
-
qargs_local_source_basis = defaultdict(set)
|
418
|
-
for node in dag.op_nodes():
|
419
|
-
qargs = tuple(qarg_indices[bit] for bit in node.qargs)
|
420
|
-
if dag.has_calibration_for(node) or len(node.qargs) < self._min_qubits:
|
421
|
-
continue
|
422
|
-
# Treat the instruction as on an incomplete basis if the qargs are in the
|
423
|
-
# qargs_with_non_global_operation dictionary or if any of the qubits in qargs
|
424
|
-
# are a superset for a non-local operation. For example, if the qargs
|
425
|
-
# are (0, 1) and that's a global (ie no non-local operations on (0, 1)
|
426
|
-
# operation but there is a non-local operation on (1,) we need to
|
427
|
-
# do an extra non-local search for this op to ensure we include any
|
428
|
-
# single qubit operation for (1,) as valid. This pattern also holds
|
429
|
-
# true for > 2q ops too (so for 4q operations we need to check for 3q, 2q,
|
430
|
-
# and 1q operations in the same manner)
|
431
|
-
if qargs in self._qargs_with_non_global_operation or any(
|
432
|
-
frozenset(qargs).issuperset(incomplete_qargs)
|
433
|
-
for incomplete_qargs in self._qargs_with_non_global_operation
|
434
|
-
):
|
435
|
-
qargs_local_source_basis[frozenset(qargs)].add((node.name, node.num_qubits))
|
436
|
-
else:
|
437
|
-
source_basis.add((node.name, node.num_qubits))
|
438
|
-
if node.name in CONTROL_FLOW_OP_NAMES:
|
439
|
-
for block in node.op.blocks:
|
440
|
-
block_dag = circuit_to_dag(block)
|
441
|
-
source_basis, qargs_local_source_basis = self._extract_basis_target(
|
442
|
-
block_dag,
|
443
|
-
{
|
444
|
-
inner: qarg_indices[outer]
|
445
|
-
for inner, outer in zip(block.qubits, node.qargs)
|
446
|
-
},
|
447
|
-
source_basis=source_basis,
|
448
|
-
qargs_local_source_basis=qargs_local_source_basis,
|
449
|
-
)
|
450
|
-
return source_basis, qargs_local_source_basis
|
451
|
-
|
452
|
-
|
453
|
-
class StopIfBasisRewritable(Exception):
|
454
|
-
"""Custom exception that signals `rustworkx.dijkstra_search` to stop."""
|
455
|
-
|
456
|
-
|
457
|
-
class BasisSearchVisitor(rustworkx.visit.DijkstraVisitor):
|
458
|
-
"""Handles events emitted during `rustworkx.dijkstra_search`."""
|
459
|
-
|
460
|
-
def __init__(self, graph, source_basis, target_basis):
|
461
|
-
self.graph = graph
|
462
|
-
self.target_basis = set(target_basis)
|
463
|
-
self._source_gates_remain = set(source_basis)
|
464
|
-
self._num_gates_remain_for_rule = {}
|
465
|
-
save_index = -1
|
466
|
-
for edata in self.graph.edges():
|
467
|
-
if save_index == edata.index:
|
468
|
-
continue
|
469
|
-
self._num_gates_remain_for_rule[edata.index] = edata.num_gates
|
470
|
-
save_index = edata.index
|
471
|
-
|
472
|
-
self._basis_transforms = []
|
473
|
-
self._predecessors = {}
|
474
|
-
self._opt_cost_map = {}
|
475
|
-
|
476
|
-
def discover_vertex(self, v, score):
|
477
|
-
gate = self.graph[v].key
|
478
|
-
self._source_gates_remain.discard(gate)
|
479
|
-
self._opt_cost_map[gate] = score
|
480
|
-
rule = self._predecessors.get(gate, None)
|
481
|
-
if rule is not None:
|
482
|
-
logger.debug(
|
483
|
-
"Gate %s generated using rule \n%s\n with total cost of %s.",
|
484
|
-
gate.name,
|
485
|
-
rule.circuit,
|
486
|
-
score,
|
487
|
-
)
|
488
|
-
self._basis_transforms.append((gate.name, gate.num_qubits, rule.params, rule.circuit))
|
489
|
-
# we can stop the search if we have found all gates in the original circuit.
|
490
|
-
if not self._source_gates_remain:
|
491
|
-
# if we start from source gates and apply `basis_transforms` in reverse order, we'll end
|
492
|
-
# up with gates in the target basis. Note though that `basis_transforms` may include
|
493
|
-
# additional transformations that are not required to map our source gates to the given
|
494
|
-
# target basis.
|
495
|
-
self._basis_transforms.reverse()
|
496
|
-
raise StopIfBasisRewritable
|
497
|
-
|
498
|
-
def examine_edge(self, edge):
|
499
|
-
_, target, edata = edge
|
500
|
-
if edata is None:
|
501
|
-
return
|
502
|
-
|
503
|
-
self._num_gates_remain_for_rule[edata.index] -= 1
|
504
|
-
|
505
|
-
target = self.graph[target].key
|
506
|
-
# if there are gates in this `rule` that we have not yet generated, we can't apply
|
507
|
-
# this `rule`. if `target` is already in basis, it's not beneficial to use this rule.
|
508
|
-
if self._num_gates_remain_for_rule[edata.index] > 0 or target in self.target_basis:
|
509
|
-
raise rustworkx.visit.PruneSearch
|
510
|
-
|
511
|
-
def edge_relaxed(self, edge):
|
512
|
-
_, target, edata = edge
|
513
|
-
if edata is not None:
|
514
|
-
gate = self.graph[target].key
|
515
|
-
self._predecessors[gate] = edata.rule
|
516
|
-
|
517
|
-
def edge_cost(self, edge_data):
|
518
|
-
"""Returns the cost of an edge.
|
519
|
-
|
520
|
-
This function computes the cost of this edge rule by summing
|
521
|
-
the costs of all gates in the rule equivalence circuit. In the
|
522
|
-
end, we need to subtract the cost of the source since `dijkstra`
|
523
|
-
will later add it.
|
524
|
-
"""
|
525
|
-
|
526
|
-
if edge_data is None:
|
527
|
-
# the target of the edge is a gate in the target basis,
|
528
|
-
# so we return a default value of 1.
|
529
|
-
return 1
|
530
|
-
|
531
|
-
cost_tot = 0
|
532
|
-
for instruction in edge_data.rule.circuit:
|
533
|
-
key = Key(name=instruction.name, num_qubits=len(instruction.qubits))
|
534
|
-
cost_tot += self._opt_cost_map[key]
|
535
|
-
|
536
|
-
return cost_tot - self._opt_cost_map[edge_data.source]
|
537
|
-
|
538
|
-
@property
|
539
|
-
def basis_transforms(self):
|
540
|
-
"""Returns the gate basis transforms."""
|
541
|
-
return self._basis_transforms
|
542
|
-
|
543
|
-
|
544
|
-
def _basis_search(equiv_lib, source_basis, target_basis):
|
545
|
-
"""Search for a set of transformations from source_basis to target_basis.
|
546
|
-
|
547
|
-
Args:
|
548
|
-
equiv_lib (EquivalenceLibrary): Source of valid translations
|
549
|
-
source_basis (Set[Tuple[gate_name: str, gate_num_qubits: int]]): Starting basis.
|
550
|
-
target_basis (Set[gate_name: str]): Target basis.
|
551
|
-
|
552
|
-
Returns:
|
553
|
-
Optional[List[Tuple[gate, equiv_params, equiv_circuit]]]: List of (gate,
|
554
|
-
equiv_params, equiv_circuit) tuples tuples which, if applied in order
|
555
|
-
will map from source_basis to target_basis. Returns None if no path
|
556
|
-
was found.
|
557
|
-
"""
|
558
|
-
|
559
|
-
logger.debug("Begining basis search from %s to %s.", source_basis, target_basis)
|
560
|
-
|
561
|
-
source_basis = {
|
562
|
-
(gate_name, gate_num_qubits)
|
563
|
-
for gate_name, gate_num_qubits in source_basis
|
564
|
-
if gate_name not in target_basis
|
565
|
-
}
|
566
|
-
|
567
|
-
# if source basis is empty, no work to be done.
|
568
|
-
if not source_basis:
|
569
|
-
return []
|
570
|
-
|
571
|
-
# This is only necessary since gates in target basis are currently reported by
|
572
|
-
# their names and we need to have in addition the number of qubits they act on.
|
573
|
-
target_basis_keys = [key for key in equiv_lib.keys() if key.name in target_basis]
|
574
|
-
|
575
|
-
graph = equiv_lib.graph
|
576
|
-
vis = BasisSearchVisitor(graph, source_basis, target_basis_keys)
|
577
|
-
|
578
|
-
# we add a dummy node and connect it with gates in the target basis.
|
579
|
-
# we'll start the search from this dummy node.
|
580
|
-
dummy = graph.add_node(NodeData(key="key", equivs=[("dummy starting node", 0)]))
|
581
|
-
|
582
|
-
try:
|
583
|
-
graph.add_edges_from_no_data(
|
584
|
-
[(dummy, equiv_lib.node_index(key)) for key in target_basis_keys]
|
585
|
-
)
|
586
|
-
rtn = None
|
587
|
-
try:
|
588
|
-
rustworkx.digraph_dijkstra_search(graph, [dummy], vis.edge_cost, vis)
|
589
|
-
except StopIfBasisRewritable:
|
590
|
-
rtn = vis.basis_transforms
|
591
|
-
|
592
|
-
logger.debug("Transformation path:")
|
593
|
-
for gate_name, gate_num_qubits, params, equiv in rtn:
|
594
|
-
logger.debug("%s/%s => %s\n%s", gate_name, gate_num_qubits, params, equiv)
|
595
|
-
finally:
|
596
|
-
# Remove dummy node in order to return graph to original state
|
597
|
-
graph.remove_node(dummy)
|
598
|
-
|
599
|
-
return rtn
|
600
|
-
|
601
|
-
|
602
|
-
def _compose_transforms(basis_transforms, source_basis, source_dag):
|
603
|
-
"""Compose a set of basis transforms into a set of replacements.
|
604
|
-
|
605
|
-
Args:
|
606
|
-
basis_transforms (List[Tuple[gate_name, params, equiv]]): List of
|
607
|
-
transforms to compose.
|
608
|
-
source_basis (Set[Tuple[gate_name: str, gate_num_qubits: int]]): Names
|
609
|
-
of gates which need to be translated.
|
610
|
-
source_dag (DAGCircuit): DAG with example gates from source_basis.
|
611
|
-
(Used to determine num_params for gate in source_basis.)
|
612
|
-
|
613
|
-
Returns:
|
614
|
-
Dict[gate_name, Tuple(params, dag)]: Dictionary mapping between each gate
|
615
|
-
in source_basis and a DAGCircuit instance to replace it. Gates in
|
616
|
-
source_basis but not affected by basis_transforms will be included
|
617
|
-
as a key mapping to itself.
|
618
|
-
"""
|
619
|
-
example_gates = _get_example_gates(source_dag)
|
620
|
-
mapped_instrs = {}
|
621
|
-
|
622
|
-
for gate_name, gate_num_qubits in source_basis:
|
623
|
-
# Need to grab a gate instance to find num_qubits and num_params.
|
624
|
-
# Can be removed following https://github.com/Qiskit/qiskit-terra/pull/3947 .
|
625
|
-
example_gate = example_gates[gate_name, gate_num_qubits]
|
626
|
-
num_params = len(example_gate.params)
|
627
|
-
|
628
|
-
placeholder_params = ParameterVector(gate_name, num_params)
|
629
|
-
placeholder_gate = Gate(gate_name, gate_num_qubits, list(placeholder_params))
|
630
|
-
placeholder_gate.params = list(placeholder_params)
|
631
|
-
|
632
|
-
dag = DAGCircuit()
|
633
|
-
qr = QuantumRegister(gate_num_qubits)
|
634
|
-
dag.add_qreg(qr)
|
635
|
-
dag.apply_operation_back(placeholder_gate, qr, (), check=False)
|
636
|
-
mapped_instrs[gate_name, gate_num_qubits] = placeholder_params, dag
|
637
|
-
|
638
|
-
for gate_name, gate_num_qubits, equiv_params, equiv in basis_transforms:
|
639
|
-
logger.debug(
|
640
|
-
"Composing transform step: %s/%s %s =>\n%s",
|
641
|
-
gate_name,
|
642
|
-
gate_num_qubits,
|
643
|
-
equiv_params,
|
644
|
-
equiv,
|
645
|
-
)
|
646
|
-
|
647
|
-
for mapped_instr_name, (dag_params, dag) in mapped_instrs.items():
|
648
|
-
doomed_nodes = [
|
649
|
-
node
|
650
|
-
for node in dag.op_nodes()
|
651
|
-
if (node.name, node.num_qubits) == (gate_name, gate_num_qubits)
|
652
|
-
]
|
653
|
-
|
654
|
-
if doomed_nodes and logger.isEnabledFor(logging.DEBUG):
|
655
|
-
|
656
|
-
logger.debug(
|
657
|
-
"Updating transform for mapped instr %s %s from \n%s",
|
658
|
-
mapped_instr_name,
|
659
|
-
dag_params,
|
660
|
-
dag_to_circuit(dag, copy_operations=False),
|
661
|
-
)
|
662
|
-
|
663
|
-
for node in doomed_nodes:
|
664
|
-
|
665
|
-
replacement = equiv.assign_parameters(dict(zip_longest(equiv_params, node.params)))
|
666
|
-
|
667
|
-
replacement_dag = circuit_to_dag(replacement)
|
668
|
-
|
669
|
-
dag.substitute_node_with_dag(node, replacement_dag)
|
670
|
-
|
671
|
-
if doomed_nodes and logger.isEnabledFor(logging.DEBUG):
|
672
|
-
|
673
|
-
logger.debug(
|
674
|
-
"Updated transform for mapped instr %s %s to\n%s",
|
675
|
-
mapped_instr_name,
|
676
|
-
dag_params,
|
677
|
-
dag_to_circuit(dag, copy_operations=False),
|
678
|
-
)
|
679
|
-
|
680
|
-
return mapped_instrs
|
681
|
-
|
682
|
-
|
683
|
-
def _get_example_gates(source_dag):
|
684
|
-
def recurse(dag, example_gates=None):
|
685
|
-
example_gates = example_gates or {}
|
686
|
-
for node in dag.op_nodes():
|
687
|
-
example_gates[(node.name, node.num_qubits)] = node
|
688
|
-
if node.name in CONTROL_FLOW_OP_NAMES:
|
689
|
-
for block in node.op.blocks:
|
690
|
-
example_gates = recurse(circuit_to_dag(block), example_gates)
|
691
|
-
return example_gates
|
692
|
-
|
693
|
-
return recurse(source_dag)
|
@@ -11,13 +11,20 @@
|
|
11
11
|
# that they have been altered from the originals.
|
12
12
|
|
13
13
|
"""Expand a gate in a circuit using its decomposition rules."""
|
14
|
-
|
14
|
+
|
15
|
+
from __future__ import annotations
|
16
|
+
|
17
|
+
from collections.abc import Sequence
|
18
|
+
from typing import Type
|
15
19
|
from fnmatch import fnmatch
|
16
20
|
|
17
21
|
from qiskit.transpiler.basepasses import TransformationPass
|
22
|
+
from qiskit.dagcircuit.dagnode import DAGOpNode
|
18
23
|
from qiskit.dagcircuit.dagcircuit import DAGCircuit
|
19
24
|
from qiskit.converters.circuit_to_dag import circuit_to_dag
|
20
|
-
from qiskit.circuit.
|
25
|
+
from qiskit.circuit.instruction import Instruction
|
26
|
+
|
27
|
+
from ..synthesis import HighLevelSynthesis
|
21
28
|
|
22
29
|
|
23
30
|
class Decompose(TransformationPass):
|
@@ -25,16 +32,21 @@ class Decompose(TransformationPass):
|
|
25
32
|
|
26
33
|
def __init__(
|
27
34
|
self,
|
28
|
-
gates_to_decompose:
|
35
|
+
gates_to_decompose: (
|
36
|
+
str | Type[Instruction] | Sequence[str | Type[Instruction]] | None
|
37
|
+
) = None,
|
38
|
+
apply_synthesis: bool = False,
|
29
39
|
) -> None:
|
30
|
-
"""
|
31
|
-
|
40
|
+
"""
|
32
41
|
Args:
|
33
42
|
gates_to_decompose: optional subset of gates to be decomposed,
|
34
43
|
identified by gate label, name or type. Defaults to all gates.
|
44
|
+
apply_synthesis: If ``True``, run :class:`.HighLevelSynthesis` to synthesize operations
|
45
|
+
that do not have a definition attached.
|
35
46
|
"""
|
36
47
|
super().__init__()
|
37
48
|
self.gates_to_decompose = gates_to_decompose
|
49
|
+
self.apply_synthesis = apply_synthesis
|
38
50
|
|
39
51
|
def run(self, dag: DAGCircuit) -> DAGCircuit:
|
40
52
|
"""Run the Decompose pass on `dag`.
|
@@ -45,13 +57,26 @@ class Decompose(TransformationPass):
|
|
45
57
|
Returns:
|
46
58
|
output dag where ``gate`` was expanded.
|
47
59
|
"""
|
60
|
+
# We might use HLS to synthesize objects that do not have a definition
|
61
|
+
hls = HighLevelSynthesis() if self.apply_synthesis else None
|
62
|
+
|
48
63
|
# Walk through the DAG and expand each non-basis node
|
49
64
|
for node in dag.op_nodes():
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
65
|
+
# Check in self.gates_to_decompose if the operation should be decomposed
|
66
|
+
if not self._should_decompose(node):
|
67
|
+
continue
|
68
|
+
|
69
|
+
if getattr(node.op, "definition", None) is None:
|
70
|
+
# if we try to synthesize, turn the node into a DAGCircuit and run HLS
|
71
|
+
if self.apply_synthesis:
|
72
|
+
node_as_dag = _node_to_dag(node)
|
73
|
+
synthesized = hls.run(node_as_dag)
|
74
|
+
dag.substitute_node_with_dag(node, synthesized)
|
75
|
+
|
76
|
+
# else: no definition and synthesis not enabled, so we do nothing
|
77
|
+
else:
|
54
78
|
rule = node.op.definition.data
|
79
|
+
|
55
80
|
if (
|
56
81
|
len(rule) == 1
|
57
82
|
and len(node.qargs) == len(rule[0].qubits) == 1 # to preserve gate order
|
@@ -66,9 +91,8 @@ class Decompose(TransformationPass):
|
|
66
91
|
|
67
92
|
return dag
|
68
93
|
|
69
|
-
def _should_decompose(self, node) -> bool:
|
70
|
-
"""Call a decomposition pass on this circuit
|
71
|
-
to decompose one level (shallow decompose)."""
|
94
|
+
def _should_decompose(self, node: DAGOpNode) -> bool:
|
95
|
+
"""Call a decomposition pass on this circuit to decompose one level (shallow decompose)."""
|
72
96
|
if self.gates_to_decompose is None: # check if no gates given
|
73
97
|
return True
|
74
98
|
|
@@ -96,3 +120,12 @@ class Decompose(TransformationPass):
|
|
96
120
|
return True
|
97
121
|
else:
|
98
122
|
return False
|
123
|
+
|
124
|
+
|
125
|
+
def _node_to_dag(node: DAGOpNode) -> DAGCircuit:
|
126
|
+
dag = DAGCircuit()
|
127
|
+
dag.add_qubits(node.qargs)
|
128
|
+
dag.add_clbits(node.cargs)
|
129
|
+
|
130
|
+
dag.apply_operation_back(node.op, node.qargs, node.cargs)
|
131
|
+
return dag
|