qiskit 1.4.2__cp39-abi3-macosx_11_0_arm64.whl → 2.0.0__cp39-abi3-macosx_11_0_arm64.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 +3 -9
- qiskit/_accelerate.abi3.so +0 -0
- qiskit/circuit/__init__.py +35 -10
- qiskit/circuit/{add_control.py → _add_control.py} +32 -12
- qiskit/circuit/_classical_resource_map.py +5 -3
- qiskit/circuit/barrier.py +3 -7
- qiskit/circuit/classical/expr/__init__.py +31 -3
- qiskit/circuit/classical/expr/constructors.py +236 -28
- qiskit/circuit/classical/expr/expr.py +104 -3
- qiskit/circuit/classical/expr/visitors.py +75 -0
- qiskit/circuit/classical/types/__init__.py +12 -8
- qiskit/circuit/classical/types/ordering.py +14 -7
- qiskit/circuit/classical/types/types.py +36 -0
- qiskit/circuit/commutation_checker.py +34 -7
- qiskit/circuit/controlflow/__init__.py +32 -1
- qiskit/circuit/controlflow/_builder_utils.py +9 -5
- qiskit/circuit/controlflow/box.py +163 -0
- qiskit/circuit/controlflow/break_loop.py +1 -1
- qiskit/circuit/controlflow/builder.py +139 -39
- qiskit/circuit/controlflow/continue_loop.py +1 -3
- qiskit/circuit/controlflow/control_flow.py +10 -0
- qiskit/circuit/controlflow/for_loop.py +2 -1
- qiskit/circuit/controlflow/if_else.py +3 -16
- qiskit/circuit/controlflow/switch_case.py +2 -8
- qiskit/circuit/controlflow/while_loop.py +2 -7
- qiskit/circuit/controlledgate.py +2 -4
- qiskit/circuit/delay.py +40 -11
- qiskit/circuit/duration.py +0 -15
- qiskit/circuit/gate.py +2 -4
- qiskit/circuit/instruction.py +2 -141
- qiskit/circuit/instructionset.py +7 -54
- qiskit/circuit/library/__init__.py +469 -154
- qiskit/circuit/library/arithmetic/__init__.py +16 -10
- qiskit/circuit/library/arithmetic/adders/cdkm_ripple_carry_adder.py +1 -1
- qiskit/circuit/library/arithmetic/adders/draper_qft_adder.py +2 -2
- qiskit/circuit/library/arithmetic/adders/vbe_ripple_carry_adder.py +1 -1
- qiskit/circuit/library/arithmetic/exact_reciprocal.py +64 -21
- qiskit/circuit/library/arithmetic/integer_comparator.py +37 -80
- qiskit/circuit/library/arithmetic/linear_amplitude_function.py +169 -2
- qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +59 -5
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +154 -6
- qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +114 -4
- qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +191 -15
- qiskit/circuit/library/arithmetic/polynomial_pauli_rotations.py +93 -39
- qiskit/circuit/library/arithmetic/quadratic_form.py +168 -2
- qiskit/circuit/library/arithmetic/weighted_adder.py +73 -1
- qiskit/circuit/library/bit_flip_oracle.py +130 -0
- qiskit/circuit/library/blueprintcircuit.py +52 -16
- qiskit/circuit/library/data_preparation/initializer.py +1 -1
- qiskit/circuit/library/data_preparation/pauli_feature_map.py +4 -4
- qiskit/circuit/library/data_preparation/state_preparation.py +1 -1
- qiskit/circuit/library/generalized_gates/gms.py +1 -1
- qiskit/circuit/library/generalized_gates/isometry.py +1 -1
- qiskit/circuit/library/generalized_gates/pauli.py +1 -2
- qiskit/circuit/library/generalized_gates/uc.py +97 -7
- qiskit/circuit/library/generalized_gates/uc_pauli_rot.py +1 -1
- qiskit/circuit/library/generalized_gates/unitary.py +4 -2
- qiskit/circuit/library/graph_state.py +1 -0
- qiskit/circuit/library/hamiltonian_gate.py +1 -1
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +1 -1
- qiskit/circuit/library/n_local/n_local.py +1 -1
- qiskit/circuit/library/n_local/qaoa_ansatz.py +1 -1
- qiskit/circuit/library/overlap.py +2 -2
- qiskit/circuit/library/pauli_evolution.py +39 -24
- qiskit/circuit/library/phase_oracle.py +130 -51
- qiskit/circuit/library/standard_gates/__init__.py +0 -1
- qiskit/circuit/library/standard_gates/dcx.py +3 -4
- qiskit/circuit/library/standard_gates/ecr.py +3 -4
- qiskit/circuit/library/standard_gates/global_phase.py +5 -6
- qiskit/circuit/library/standard_gates/h.py +4 -9
- qiskit/circuit/library/standard_gates/i.py +2 -2
- qiskit/circuit/library/standard_gates/iswap.py +3 -4
- qiskit/circuit/library/standard_gates/p.py +15 -34
- qiskit/circuit/library/standard_gates/r.py +7 -10
- qiskit/circuit/library/standard_gates/rx.py +5 -15
- qiskit/circuit/library/standard_gates/rxx.py +3 -6
- qiskit/circuit/library/standard_gates/ry.py +5 -17
- qiskit/circuit/library/standard_gates/ryy.py +3 -6
- qiskit/circuit/library/standard_gates/rz.py +5 -17
- qiskit/circuit/library/standard_gates/rzx.py +3 -6
- qiskit/circuit/library/standard_gates/rzz.py +3 -6
- qiskit/circuit/library/standard_gates/s.py +6 -15
- qiskit/circuit/library/standard_gates/swap.py +4 -11
- qiskit/circuit/library/standard_gates/sx.py +7 -12
- qiskit/circuit/library/standard_gates/t.py +6 -7
- qiskit/circuit/library/standard_gates/u.py +2 -10
- qiskit/circuit/library/standard_gates/u1.py +5 -16
- qiskit/circuit/library/standard_gates/u2.py +2 -6
- qiskit/circuit/library/standard_gates/u3.py +3 -11
- qiskit/circuit/library/standard_gates/x.py +14 -62
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +2 -5
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +2 -5
- qiskit/circuit/library/standard_gates/y.py +4 -9
- qiskit/circuit/library/standard_gates/z.py +5 -15
- qiskit/circuit/measure.py +11 -2
- qiskit/circuit/parameterexpression.py +7 -1
- qiskit/circuit/quantumcircuit.py +890 -564
- qiskit/circuit/random/utils.py +12 -6
- qiskit/circuit/reset.py +5 -2
- qiskit/circuit/singleton.py +5 -11
- qiskit/circuit/store.py +0 -8
- qiskit/compiler/__init__.py +1 -7
- qiskit/compiler/transpiler.py +38 -196
- qiskit/converters/circuit_to_dag.py +6 -4
- qiskit/converters/circuit_to_dagdependency.py +0 -2
- qiskit/converters/circuit_to_dagdependency_v2.py +0 -1
- qiskit/converters/circuit_to_gate.py +1 -1
- qiskit/converters/circuit_to_instruction.py +16 -29
- qiskit/converters/dag_to_circuit.py +7 -8
- qiskit/converters/dag_to_dagdependency.py +0 -1
- qiskit/converters/dag_to_dagdependency_v2.py +0 -1
- qiskit/converters/dagdependency_to_circuit.py +0 -6
- qiskit/converters/dagdependency_to_dag.py +0 -6
- qiskit/dagcircuit/collect_blocks.py +32 -20
- qiskit/dagcircuit/dagdependency.py +3 -37
- qiskit/dagcircuit/dagdependency_v2.py +5 -82
- qiskit/dagcircuit/dagnode.py +14 -2
- qiskit/passmanager/__init__.py +24 -6
- qiskit/passmanager/passmanager.py +26 -24
- qiskit/primitives/__init__.py +44 -35
- qiskit/primitives/backend_estimator_v2.py +102 -23
- qiskit/primitives/backend_sampler_v2.py +5 -20
- qiskit/primitives/base/__init__.py +4 -4
- qiskit/primitives/base/base_estimator.py +77 -82
- qiskit/primitives/base/base_primitive_job.py +2 -2
- qiskit/primitives/base/{base_primitive.py → base_primitive_v1.py} +1 -1
- qiskit/primitives/base/{base_result.py → base_result_v1.py} +1 -1
- qiskit/primitives/base/base_sampler.py +52 -60
- qiskit/primitives/base/{estimator_result.py → estimator_result_v1.py} +2 -2
- qiskit/primitives/base/{sampler_result.py → sampler_result_v1.py} +2 -2
- qiskit/primitives/base/{validation.py → validation_v1.py} +34 -15
- qiskit/primitives/containers/bindings_array.py +3 -1
- qiskit/primitives/containers/bit_array.py +23 -0
- qiskit/primitives/containers/data_bin.py +3 -1
- qiskit/primitives/containers/observables_array.py +19 -2
- qiskit/primitives/statevector_sampler.py +6 -8
- qiskit/primitives/utils.py +14 -189
- qiskit/providers/__init__.py +4 -130
- qiskit/providers/backend.py +11 -314
- qiskit/providers/basic_provider/__init__.py +3 -1
- qiskit/providers/basic_provider/basic_provider.py +29 -9
- qiskit/providers/basic_provider/basic_simulator.py +158 -298
- qiskit/providers/exceptions.py +0 -33
- qiskit/providers/fake_provider/__init__.py +0 -37
- qiskit/providers/fake_provider/generic_backend_v2.py +32 -693
- qiskit/qasm2/__init__.py +21 -6
- qiskit/qasm2/export.py +2 -10
- qiskit/qasm2/parse.py +11 -25
- qiskit/qasm3/__init__.py +5 -1
- qiskit/qasm3/ast.py +44 -0
- qiskit/qasm3/exporter.py +65 -27
- qiskit/qasm3/printer.py +35 -4
- qiskit/qpy/__init__.py +162 -19
- qiskit/qpy/binary_io/__init__.py +0 -1
- qiskit/qpy/binary_io/circuits.py +98 -130
- qiskit/qpy/binary_io/schedules.py +69 -439
- qiskit/qpy/binary_io/value.py +154 -31
- qiskit/qpy/common.py +10 -7
- qiskit/qpy/formats.py +41 -0
- qiskit/qpy/interface.py +34 -81
- qiskit/qpy/type_keys.py +58 -221
- qiskit/quantum_info/analysis/distance.py +3 -1
- qiskit/quantum_info/operators/dihedral/dihedral.py +3 -1
- qiskit/quantum_info/operators/operator.py +6 -2
- qiskit/quantum_info/operators/symplectic/clifford.py +3 -1
- qiskit/quantum_info/operators/symplectic/pauli.py +4 -2
- qiskit/quantum_info/operators/symplectic/pauli_list.py +17 -5
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +40 -6
- qiskit/quantum_info/states/densitymatrix.py +16 -6
- qiskit/quantum_info/states/stabilizerstate.py +35 -4
- qiskit/quantum_info/states/statevector.py +16 -6
- qiskit/result/__init__.py +5 -17
- qiskit/result/models.py +18 -11
- qiskit/result/result.py +38 -134
- qiskit/result/sampled_expval.py +1 -2
- qiskit/result/utils.py +3 -4
- qiskit/synthesis/__init__.py +21 -1
- qiskit/synthesis/arithmetic/__init__.py +3 -1
- qiskit/synthesis/arithmetic/adders/cdkm_ripple_carry_adder.py +1 -1
- qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +1 -1
- qiskit/synthesis/arithmetic/adders/vbe_ripple_carry_adder.py +2 -2
- qiskit/{providers/fake_provider/backends_v1/fake_20q → synthesis/arithmetic/comparators}/__init__.py +4 -6
- qiskit/synthesis/arithmetic/comparators/compare_2s.py +112 -0
- qiskit/synthesis/arithmetic/comparators/compare_greedy.py +66 -0
- qiskit/synthesis/arithmetic/multipliers/hrs_cumulative_multiplier.py +1 -1
- qiskit/synthesis/arithmetic/multipliers/rg_qft_multiplier.py +1 -1
- qiskit/synthesis/arithmetic/weighted_sum.py +155 -0
- qiskit/{result/mitigation → synthesis/boolean}/__init__.py +2 -2
- 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/evolution/lie_trotter.py +10 -7
- qiskit/synthesis/evolution/product_formula.py +44 -35
- qiskit/synthesis/evolution/qdrift.py +17 -24
- qiskit/synthesis/evolution/suzuki_trotter.py +20 -27
- qiskit/synthesis/linear/linear_depth_lnn.py +6 -221
- qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py +4 -205
- qiskit/synthesis/multi_controlled/__init__.py +1 -0
- qiskit/synthesis/multi_controlled/mcx_synthesis.py +5 -2
- qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +206 -0
- qiskit/synthesis/one_qubit/one_qubit_decompose.py +1 -1
- qiskit/synthesis/two_qubit/__init__.py +1 -0
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +28 -145
- qiskit/transpiler/__init__.py +32 -232
- qiskit/transpiler/basepasses.py +20 -51
- qiskit/transpiler/layout.py +1 -1
- qiskit/transpiler/passes/__init__.py +4 -40
- qiskit/transpiler/passes/basis/basis_translator.py +5 -4
- qiskit/transpiler/passes/basis/decompose.py +1 -15
- qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -5
- qiskit/transpiler/passes/basis/unroll_custom_definitions.py +3 -2
- qiskit/transpiler/passes/layout/apply_layout.py +4 -0
- qiskit/transpiler/passes/layout/dense_layout.py +2 -39
- qiskit/transpiler/passes/layout/full_ancilla_allocation.py +3 -4
- qiskit/transpiler/passes/layout/sabre_layout.py +7 -3
- qiskit/transpiler/passes/layout/vf2_layout.py +2 -20
- qiskit/transpiler/passes/layout/vf2_post_layout.py +60 -125
- qiskit/transpiler/passes/layout/vf2_utils.py +2 -26
- qiskit/transpiler/passes/optimization/__init__.py +2 -3
- qiskit/transpiler/passes/optimization/collect_and_collapse.py +2 -0
- qiskit/transpiler/passes/optimization/collect_cliffords.py +5 -0
- qiskit/transpiler/passes/optimization/collect_linear_functions.py +5 -0
- qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +16 -1
- qiskit/transpiler/passes/optimization/commutation_analysis.py +3 -3
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +41 -19
- qiskit/transpiler/passes/optimization/contract_idle_wires_in_control_flow.py +104 -0
- qiskit/transpiler/passes/optimization/light_cone.py +135 -0
- qiskit/transpiler/passes/optimization/optimize_1q_commutation.py +0 -1
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +18 -22
- qiskit/transpiler/passes/optimization/optimize_annotated.py +3 -2
- qiskit/transpiler/passes/optimization/remove_identity_equiv.py +6 -4
- qiskit/transpiler/passes/optimization/reset_after_measure_simplification.py +5 -2
- qiskit/transpiler/passes/optimization/split_2q_unitaries.py +26 -3
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +1 -0
- qiskit/transpiler/passes/routing/__init__.py +0 -1
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +3 -1
- qiskit/transpiler/passes/routing/sabre_swap.py +14 -6
- qiskit/transpiler/passes/routing/star_prerouting.py +1 -1
- qiskit/transpiler/passes/scheduling/__init__.py +1 -7
- qiskit/transpiler/passes/scheduling/alignments/__init__.py +2 -4
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -9
- qiskit/transpiler/passes/scheduling/alignments/reschedule.py +17 -16
- qiskit/transpiler/passes/scheduling/padding/base_padding.py +32 -4
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +25 -63
- qiskit/transpiler/passes/scheduling/padding/pad_delay.py +12 -4
- qiskit/transpiler/passes/scheduling/scheduling/alap.py +5 -39
- qiskit/transpiler/passes/scheduling/scheduling/asap.py +4 -35
- qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +10 -16
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +134 -62
- qiskit/transpiler/passes/synthesis/default_unitary_synth_plugin.py +653 -0
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +176 -601
- qiskit/transpiler/passes/synthesis/hls_plugins.py +294 -1
- qiskit/transpiler/passes/synthesis/plugin.py +4 -0
- qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +16 -10
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +34 -697
- qiskit/transpiler/passes/utils/__init__.py +0 -1
- qiskit/transpiler/passes/utils/check_gate_direction.py +13 -5
- qiskit/transpiler/passes/utils/control_flow.py +2 -6
- qiskit/transpiler/passes/utils/gate_direction.py +7 -0
- qiskit/transpiler/passes/utils/remove_final_measurements.py +40 -33
- qiskit/transpiler/passmanager.py +13 -0
- qiskit/transpiler/passmanager_config.py +5 -81
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +225 -344
- qiskit/transpiler/preset_passmanagers/common.py +140 -167
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +107 -322
- qiskit/transpiler/preset_passmanagers/level0.py +2 -11
- qiskit/transpiler/preset_passmanagers/level1.py +2 -14
- qiskit/transpiler/preset_passmanagers/level2.py +2 -12
- qiskit/transpiler/preset_passmanagers/level3.py +2 -11
- qiskit/transpiler/preset_passmanagers/plugin.py +5 -3
- qiskit/transpiler/target.py +78 -524
- qiskit/user_config.py +8 -4
- qiskit/utils/__init__.py +13 -12
- qiskit/utils/deprecation.py +4 -112
- qiskit/utils/optionals.py +11 -4
- qiskit/utils/parallel.py +214 -87
- qiskit/utils/units.py +4 -1
- qiskit/visualization/__init__.py +3 -7
- qiskit/visualization/array.py +4 -1
- qiskit/visualization/bloch.py +1 -1
- qiskit/visualization/circuit/_utils.py +19 -19
- qiskit/visualization/circuit/circuit_visualization.py +11 -4
- qiskit/visualization/circuit/matplotlib.py +13 -23
- qiskit/visualization/circuit/text.py +7 -3
- qiskit/visualization/counts_visualization.py +4 -0
- qiskit/visualization/dag_visualization.py +2 -1
- qiskit/visualization/gate_map.py +39 -154
- qiskit/visualization/library.py +4 -1
- qiskit/visualization/pass_manager_visualization.py +6 -2
- qiskit/visualization/state_visualization.py +19 -2
- qiskit/visualization/timeline/core.py +19 -13
- qiskit/visualization/timeline/interface.py +19 -18
- qiskit/visualization/timeline/plotters/matplotlib.py +4 -1
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/METADATA +4 -3
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/RECORD +300 -447
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/WHEEL +2 -1
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/entry_points.txt +8 -2
- qiskit/assembler/__init__.py +0 -42
- qiskit/assembler/assemble_circuits.py +0 -451
- qiskit/assembler/assemble_schedules.py +0 -367
- qiskit/assembler/disassemble.py +0 -310
- qiskit/assembler/run_config.py +0 -77
- qiskit/circuit/bit.py +0 -106
- qiskit/circuit/classicalfunction/__init__.py +0 -152
- qiskit/circuit/classicalfunction/boolean_expression.py +0 -138
- qiskit/circuit/classicalfunction/classical_element.py +0 -54
- qiskit/circuit/classicalfunction/classical_function_visitor.py +0 -155
- qiskit/circuit/classicalfunction/classicalfunction.py +0 -182
- qiskit/circuit/classicalfunction/exceptions.py +0 -41
- qiskit/circuit/classicalfunction/types.py +0 -18
- qiskit/circuit/classicalfunction/utils.py +0 -91
- qiskit/circuit/classicalregister.py +0 -57
- qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +0 -405
- qiskit/circuit/quantumregister.py +0 -75
- qiskit/circuit/register.py +0 -246
- qiskit/compiler/assembler.py +0 -689
- qiskit/compiler/scheduler.py +0 -109
- qiskit/compiler/sequencer.py +0 -71
- qiskit/primitives/backend_estimator.py +0 -486
- qiskit/primitives/backend_sampler.py +0 -222
- qiskit/primitives/estimator.py +0 -172
- qiskit/primitives/sampler.py +0 -162
- qiskit/providers/backend_compat.py +0 -507
- qiskit/providers/fake_provider/backends_v1/__init__.py +0 -22
- qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/__init__.py +0 -18
- qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/conf_washington.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/defs_washington.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/fake_127q_pulse_v1.py +0 -37
- qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/props_washington.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_20q/conf_singapore.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_20q/fake_20q.py +0 -43
- qiskit/providers/fake_provider/backends_v1/fake_20q/props_singapore.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/__init__.py +0 -18
- qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/conf_hanoi.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/defs_hanoi.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/fake_27q_pulse_v1.py +0 -50
- qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/props_hanoi.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_5q/__init__.py +0 -18
- qiskit/providers/fake_provider/backends_v1/fake_5q/conf_yorktown.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_5q/fake_5q_v1.py +0 -41
- qiskit/providers/fake_provider/backends_v1/fake_5q/props_yorktown.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/__init__.py +0 -18
- qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/conf_nairobi.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/defs_nairobi.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/fake_7q_pulse_v1.py +0 -44
- qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/props_nairobi.json +0 -1
- qiskit/providers/fake_provider/fake_1q.py +0 -91
- qiskit/providers/fake_provider/fake_backend.py +0 -165
- qiskit/providers/fake_provider/fake_openpulse_2q.py +0 -391
- qiskit/providers/fake_provider/fake_openpulse_3q.py +0 -340
- qiskit/providers/fake_provider/fake_pulse_backend.py +0 -49
- qiskit/providers/fake_provider/fake_qasm_backend.py +0 -77
- qiskit/providers/fake_provider/utils/backend_converter.py +0 -150
- qiskit/providers/fake_provider/utils/json_decoder.py +0 -109
- qiskit/providers/models/__init__.py +0 -89
- qiskit/providers/models/backendconfiguration.py +0 -1040
- qiskit/providers/models/backendproperties.py +0 -535
- qiskit/providers/models/backendstatus.py +0 -104
- qiskit/providers/models/jobstatus.py +0 -77
- qiskit/providers/models/pulsedefaults.py +0 -305
- qiskit/providers/provider.py +0 -95
- qiskit/pulse/__init__.py +0 -158
- qiskit/pulse/builder.py +0 -2262
- qiskit/pulse/calibration_entries.py +0 -381
- qiskit/pulse/channels.py +0 -227
- qiskit/pulse/configuration.py +0 -245
- qiskit/pulse/exceptions.py +0 -45
- qiskit/pulse/filters.py +0 -309
- qiskit/pulse/instruction_schedule_map.py +0 -424
- qiskit/pulse/instructions/__init__.py +0 -67
- qiskit/pulse/instructions/acquire.py +0 -150
- qiskit/pulse/instructions/delay.py +0 -71
- qiskit/pulse/instructions/directives.py +0 -154
- qiskit/pulse/instructions/frequency.py +0 -135
- qiskit/pulse/instructions/instruction.py +0 -270
- qiskit/pulse/instructions/phase.py +0 -152
- qiskit/pulse/instructions/play.py +0 -99
- qiskit/pulse/instructions/reference.py +0 -100
- qiskit/pulse/instructions/snapshot.py +0 -82
- qiskit/pulse/library/__init__.py +0 -97
- qiskit/pulse/library/continuous.py +0 -430
- qiskit/pulse/library/pulse.py +0 -148
- qiskit/pulse/library/samplers/__init__.py +0 -15
- qiskit/pulse/library/samplers/decorators.py +0 -295
- qiskit/pulse/library/samplers/strategies.py +0 -71
- qiskit/pulse/library/symbolic_pulses.py +0 -1989
- qiskit/pulse/library/waveform.py +0 -136
- qiskit/pulse/macros.py +0 -262
- qiskit/pulse/parameter_manager.py +0 -445
- qiskit/pulse/parser.py +0 -314
- qiskit/pulse/reference_manager.py +0 -58
- qiskit/pulse/schedule.py +0 -1854
- qiskit/pulse/transforms/__init__.py +0 -106
- qiskit/pulse/transforms/alignments.py +0 -406
- qiskit/pulse/transforms/base_transforms.py +0 -71
- qiskit/pulse/transforms/canonicalization.py +0 -498
- qiskit/pulse/transforms/dag.py +0 -122
- qiskit/pulse/utils.py +0 -149
- qiskit/qobj/__init__.py +0 -75
- qiskit/qobj/common.py +0 -81
- qiskit/qobj/converters/__init__.py +0 -18
- qiskit/qobj/converters/lo_config.py +0 -177
- qiskit/qobj/converters/pulse_instruction.py +0 -897
- qiskit/qobj/pulse_qobj.py +0 -709
- qiskit/qobj/qasm_qobj.py +0 -708
- qiskit/qobj/utils.py +0 -46
- qiskit/result/mitigation/base_readout_mitigator.py +0 -79
- qiskit/result/mitigation/correlated_readout_mitigator.py +0 -277
- qiskit/result/mitigation/local_readout_mitigator.py +0 -328
- qiskit/result/mitigation/utils.py +0 -217
- qiskit/scheduler/__init__.py +0 -40
- qiskit/scheduler/config.py +0 -37
- qiskit/scheduler/lowering.py +0 -187
- qiskit/scheduler/methods/__init__.py +0 -15
- qiskit/scheduler/methods/basic.py +0 -140
- qiskit/scheduler/schedule_circuit.py +0 -69
- qiskit/scheduler/sequence.py +0 -104
- qiskit/transpiler/passes/calibration/__init__.py +0 -17
- qiskit/transpiler/passes/calibration/base_builder.py +0 -79
- qiskit/transpiler/passes/calibration/builders.py +0 -20
- qiskit/transpiler/passes/calibration/exceptions.py +0 -22
- qiskit/transpiler/passes/calibration/pulse_gate.py +0 -100
- qiskit/transpiler/passes/calibration/rx_builder.py +0 -164
- qiskit/transpiler/passes/calibration/rzx_builder.py +0 -411
- qiskit/transpiler/passes/calibration/rzx_templates.py +0 -58
- qiskit/transpiler/passes/optimization/cx_cancellation.py +0 -65
- qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py +0 -162
- qiskit/transpiler/passes/optimization/normalize_rx_angle.py +0 -157
- qiskit/transpiler/passes/routing/stochastic_swap.py +0 -532
- qiskit/transpiler/passes/scheduling/alap.py +0 -153
- qiskit/transpiler/passes/scheduling/alignments/align_measures.py +0 -255
- qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +0 -107
- qiskit/transpiler/passes/scheduling/asap.py +0 -175
- qiskit/transpiler/passes/scheduling/base_scheduler.py +0 -310
- qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +0 -313
- qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +0 -93
- qiskit/utils/deprecate_pulse.py +0 -119
- qiskit/utils/multiprocessing.py +0 -56
- qiskit/visualization/pulse_v2/__init__.py +0 -21
- qiskit/visualization/pulse_v2/core.py +0 -901
- qiskit/visualization/pulse_v2/device_info.py +0 -173
- qiskit/visualization/pulse_v2/drawings.py +0 -253
- qiskit/visualization/pulse_v2/events.py +0 -254
- qiskit/visualization/pulse_v2/generators/__init__.py +0 -40
- qiskit/visualization/pulse_v2/generators/barrier.py +0 -76
- qiskit/visualization/pulse_v2/generators/chart.py +0 -208
- qiskit/visualization/pulse_v2/generators/frame.py +0 -436
- qiskit/visualization/pulse_v2/generators/snapshot.py +0 -133
- qiskit/visualization/pulse_v2/generators/waveform.py +0 -645
- qiskit/visualization/pulse_v2/interface.py +0 -459
- qiskit/visualization/pulse_v2/layouts.py +0 -387
- qiskit/visualization/pulse_v2/plotters/__init__.py +0 -17
- qiskit/visualization/pulse_v2/plotters/base_plotter.py +0 -53
- qiskit/visualization/pulse_v2/plotters/matplotlib.py +0 -201
- qiskit/visualization/pulse_v2/stylesheet.py +0 -312
- qiskit/visualization/pulse_v2/types.py +0 -242
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info/licenses}/LICENSE.txt +0 -0
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/top_level.txt +0 -0
@@ -17,32 +17,25 @@ High-level-synthesis transpiler pass.
|
|
17
17
|
from __future__ import annotations
|
18
18
|
|
19
19
|
import typing
|
20
|
-
from functools import partial
|
21
20
|
from collections.abc import Callable
|
22
21
|
|
23
22
|
import numpy as np
|
24
23
|
|
25
|
-
from qiskit.circuit.annotated_operation import Modifier
|
26
24
|
from qiskit.circuit.operation import Operation
|
27
|
-
from qiskit.circuit.instruction import Instruction
|
28
|
-
from qiskit.converters import circuit_to_dag, dag_to_circuit
|
29
25
|
from qiskit.transpiler.basepasses import TransformationPass
|
30
26
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
31
|
-
from qiskit.circuit import
|
32
|
-
from qiskit.transpiler.passes.utils import control_flow
|
27
|
+
from qiskit.circuit import EquivalenceLibrary
|
33
28
|
from qiskit.transpiler.target import Target
|
34
29
|
from qiskit.transpiler.coupling import CouplingMap
|
35
30
|
from qiskit.dagcircuit.dagcircuit import DAGCircuit
|
36
31
|
from qiskit.transpiler.exceptions import TranspilerError
|
37
32
|
|
38
|
-
from qiskit.
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
PowerModifier,
|
33
|
+
from qiskit._accelerate.high_level_synthesis import (
|
34
|
+
QubitTracker,
|
35
|
+
HighLevelSynthesisData,
|
36
|
+
run_on_dag,
|
43
37
|
)
|
44
38
|
|
45
|
-
from qiskit._accelerate.high_level_synthesis import QubitTracker, QubitContext
|
46
39
|
from .plugin import HighLevelSynthesisPluginManager
|
47
40
|
|
48
41
|
if typing.TYPE_CHECKING:
|
@@ -230,32 +223,43 @@ class HighLevelSynthesis(TransformationPass):
|
|
230
223
|
"""
|
231
224
|
super().__init__()
|
232
225
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
self._coupling_map = coupling_map
|
242
|
-
self._target = target
|
243
|
-
self._use_qubit_indices = use_qubit_indices
|
244
|
-
self.qubits_initially_zero = qubits_initially_zero
|
226
|
+
# When the config file is not provided, we will use the "default" method
|
227
|
+
# to synthesize Operations (when available).
|
228
|
+
hls_config = hls_config or HLSConfig(True)
|
229
|
+
hls_plugin_manager = HighLevelSynthesisPluginManager()
|
230
|
+
hls_op_names = set(hls_plugin_manager.plugins_by_op.keys()).union(
|
231
|
+
set(hls_config.methods.keys())
|
232
|
+
)
|
233
|
+
|
245
234
|
if target is not None:
|
246
|
-
|
247
|
-
self._equiv_lib = equivalence_library
|
248
|
-
self._basis_gates = basis_gates
|
249
|
-
self._min_qubits = min_qubits
|
235
|
+
coupling_map = target.build_coupling_map()
|
250
236
|
|
251
|
-
|
237
|
+
unroll_definitions = not (
|
238
|
+
(basis_gates is None or len(basis_gates) == 0)
|
239
|
+
and (target is None or len(target.operation_names) == 0)
|
240
|
+
)
|
252
241
|
|
253
242
|
# include path for when target exists but target.num_qubits is None (BasicSimulator)
|
254
|
-
if
|
243
|
+
if unroll_definitions and (target is None or target.num_qubits is None):
|
255
244
|
basic_insts = {"measure", "reset", "barrier", "snapshot", "delay", "store"}
|
256
|
-
|
245
|
+
device_insts = basic_insts | set(basis_gates)
|
257
246
|
else:
|
258
|
-
|
247
|
+
device_insts = set()
|
248
|
+
|
249
|
+
self.qubits_initially_zero = qubits_initially_zero
|
250
|
+
|
251
|
+
self.data = HighLevelSynthesisData(
|
252
|
+
hls_config=hls_config,
|
253
|
+
hls_plugin_manager=hls_plugin_manager,
|
254
|
+
coupling_map=coupling_map,
|
255
|
+
target=target,
|
256
|
+
equivalence_library=equivalence_library,
|
257
|
+
hls_op_names=hls_op_names,
|
258
|
+
device_insts=device_insts,
|
259
|
+
use_physical_indices=use_qubit_indices,
|
260
|
+
min_qubits=min_qubits,
|
261
|
+
unroll_definitions=unroll_definitions,
|
262
|
+
)
|
259
263
|
|
260
264
|
def run(self, dag: DAGCircuit) -> DAGCircuit:
|
261
265
|
"""Run the HighLevelSynthesis pass on `dag`.
|
@@ -270,585 +274,156 @@ class HighLevelSynthesis(TransformationPass):
|
|
270
274
|
TranspilerError: when the transpiler is unable to synthesize the given DAG
|
271
275
|
(for instance, when the specified synthesis method is not available).
|
272
276
|
"""
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
""
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
Note that by using the auxiliary qubits to synthesize operations present in the input DAG,
|
303
|
-
the synthesized DAG may be defined over more qubits than the input DAG. In this case,
|
304
|
-
the function update in-place the global qubits tracker and extends the local-to-global
|
305
|
-
context.
|
306
|
-
"""
|
307
|
-
|
308
|
-
if dag.num_qubits() != context.num_qubits():
|
309
|
-
raise TranspilerError("HighLevelSynthesis internal error.")
|
310
|
-
|
311
|
-
# STEP 1: Check if HighLevelSynthesis can be skipped altogether. This is only
|
312
|
-
# done at the top-level since this does not update the global qubits tracker.
|
313
|
-
if top_level:
|
314
|
-
for node in dag.op_nodes():
|
315
|
-
qubits = tuple(dag.find_bit(q).index for q in node.qargs)
|
316
|
-
if not self._definitely_skip_node(node, qubits, dag):
|
317
|
-
break
|
318
|
-
else:
|
319
|
-
# The for-loop terminates without reaching the break statement
|
320
|
-
if dag.num_qubits() != context.num_qubits():
|
321
|
-
raise TranspilerError("HighLevelSynthesis internal error.")
|
322
|
-
return dag
|
323
|
-
|
324
|
-
# STEP 2: Analyze the nodes in the DAG. For each node in the DAG that needs
|
325
|
-
# to be synthesized, we recursively synthesize it and store the result. For
|
326
|
-
# instance, the result of synthesizing a custom gate is a DAGCircuit corresponding
|
327
|
-
# to the (recursively synthesized) gate's definition. When the result is a
|
328
|
-
# DAG, we also store its context (the mapping of its qubits to global qubits).
|
329
|
-
# In addition, we keep track of the qubit states using the (global) qubits tracker.
|
330
|
-
#
|
331
|
-
# Note: This is a first version of a potentially more elaborate approach to find
|
332
|
-
# good operation/ancilla allocations. The current approach is greedy and just gives
|
333
|
-
# all available ancilla qubits to the current operation ("the-first-takes-all" approach).
|
334
|
-
# It does not distribute ancilla qubits between different operations present in the DAG.
|
335
|
-
synthesized_nodes = {}
|
336
|
-
|
337
|
-
for node in dag.topological_op_nodes():
|
338
|
-
qubits = tuple(dag.find_bit(q).index for q in node.qargs)
|
339
|
-
processed = False
|
340
|
-
synthesized = None
|
341
|
-
synthesized_context = None
|
342
|
-
|
343
|
-
# Start by handling special operations. Other cases can also be
|
344
|
-
# considered: swaps, automatically simplifying control gate (e.g. if
|
345
|
-
# a control is 0).
|
346
|
-
if node.op.name in ["id", "delay", "barrier"]:
|
347
|
-
# tracker not updated, these are no-ops
|
348
|
-
processed = True
|
349
|
-
|
350
|
-
elif node.op.name == "reset":
|
351
|
-
# reset qubits to 0
|
352
|
-
tracker.set_clean(context.to_globals(qubits))
|
353
|
-
processed = True
|
354
|
-
|
355
|
-
# check if synthesis for the operation can be skipped
|
356
|
-
elif self._definitely_skip_node(node, qubits, dag):
|
357
|
-
tracker.set_dirty(context.to_globals(qubits))
|
358
|
-
|
359
|
-
# next check control flow
|
360
|
-
elif node.is_control_flow():
|
361
|
-
inner_context = context.restrict(qubits)
|
362
|
-
synthesized = control_flow.map_blocks(
|
363
|
-
partial(
|
364
|
-
self._run,
|
365
|
-
tracker=tracker,
|
366
|
-
context=inner_context,
|
367
|
-
use_ancillas=False,
|
368
|
-
top_level=False,
|
369
|
-
),
|
370
|
-
node.op,
|
371
|
-
)
|
372
|
-
|
373
|
-
# now we are free to synthesize
|
374
|
-
else:
|
375
|
-
# This returns the synthesized operation and its context (when the result is
|
376
|
-
# a DAG, it's the correspondence between its qubits and the global qubits).
|
377
|
-
# Also note that the DAG may use auxiliary qubits. The qubits tracker and the
|
378
|
-
# current DAG's context are updated in-place.
|
379
|
-
synthesized, synthesized_context = self._synthesize_operation(
|
380
|
-
node.op, qubits, tracker, context, use_ancillas=use_ancillas
|
381
|
-
)
|
382
|
-
|
383
|
-
# If the synthesis changed the operation (i.e. it is not None), store the result.
|
384
|
-
if synthesized is not None:
|
385
|
-
synthesized_nodes[node._node_id] = (synthesized, synthesized_context)
|
386
|
-
|
387
|
-
# If the synthesis did not change anything, just update the qubit tracker.
|
388
|
-
elif not processed:
|
389
|
-
tracker.set_dirty(context.to_globals(qubits))
|
390
|
-
|
391
|
-
# We did not change anything just return the input.
|
392
|
-
if len(synthesized_nodes) == 0:
|
393
|
-
if dag.num_qubits() != context.num_qubits():
|
394
|
-
raise TranspilerError("HighLevelSynthesis internal error.")
|
395
|
-
return dag
|
396
|
-
|
397
|
-
# STEP 3. We rebuild the DAG with new operations. Note that we could also
|
398
|
-
# check if no operation changed in size and substitute in-place, but rebuilding is
|
399
|
-
# generally as fast or faster, unless very few operations are changed.
|
400
|
-
out = dag.copy_empty_like()
|
401
|
-
num_additional_qubits = context.num_qubits() - out.num_qubits()
|
402
|
-
|
403
|
-
if num_additional_qubits > 0:
|
404
|
-
out.add_qubits([Qubit() for _ in range(num_additional_qubits)])
|
405
|
-
|
406
|
-
index_to_qubit = dict(enumerate(out.qubits))
|
407
|
-
outer_to_local = context.to_local_mapping()
|
408
|
-
|
409
|
-
for node in dag.topological_op_nodes():
|
410
|
-
|
411
|
-
if op_tuple := synthesized_nodes.get(node._node_id, None):
|
412
|
-
op, op_context = op_tuple
|
413
|
-
|
414
|
-
if isinstance(op, Operation):
|
415
|
-
out.apply_operation_back(op, node.qargs, node.cargs)
|
416
|
-
continue
|
417
|
-
|
418
|
-
if isinstance(op, QuantumCircuit):
|
419
|
-
op = circuit_to_dag(op, copy_operations=False)
|
420
|
-
|
421
|
-
inner_to_global = op_context.to_global_mapping()
|
422
|
-
if isinstance(op, DAGCircuit):
|
423
|
-
qubit_map = {
|
424
|
-
q: index_to_qubit[outer_to_local[inner_to_global[i]]]
|
425
|
-
for (i, q) in enumerate(op.qubits)
|
426
|
-
}
|
427
|
-
clbit_map = dict(zip(op.clbits, node.cargs))
|
428
|
-
|
429
|
-
for sub_node in op.op_nodes():
|
430
|
-
out.apply_operation_back(
|
431
|
-
sub_node.op,
|
432
|
-
tuple(qubit_map[qarg] for qarg in sub_node.qargs),
|
433
|
-
tuple(clbit_map[carg] for carg in sub_node.cargs),
|
434
|
-
)
|
435
|
-
out.global_phase += op.global_phase
|
436
|
-
|
437
|
-
else:
|
438
|
-
raise TranspilerError(f"Unexpected synthesized type: {type(op)}")
|
439
|
-
else:
|
440
|
-
out.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
|
277
|
+
res = run_on_dag(dag, self.data, self.qubits_initially_zero)
|
278
|
+
return res if res is not None else dag
|
279
|
+
|
280
|
+
|
281
|
+
def _methods_to_try(data: HighLevelSynthesisData, name: str):
|
282
|
+
"""Get a sequence of methods to try for a given op name."""
|
283
|
+
if (methods := data.hls_config.methods.get(name)) is not None:
|
284
|
+
# the operation's name appears in the user-provided config,
|
285
|
+
# we use the list of methods provided by the user
|
286
|
+
return methods
|
287
|
+
if (
|
288
|
+
data.hls_config.use_default_on_unspecified
|
289
|
+
and "default" in data.hls_plugin_manager.method_names(name)
|
290
|
+
):
|
291
|
+
# the operation's name does not appear in the user-specified config,
|
292
|
+
# we use the "default" method when instructed to do so and the "default"
|
293
|
+
# method is available
|
294
|
+
return ["default"]
|
295
|
+
return []
|
296
|
+
|
297
|
+
|
298
|
+
def _synthesize_op_using_plugins(
|
299
|
+
operation: Operation,
|
300
|
+
input_qubits: tuple[int],
|
301
|
+
data: HighLevelSynthesisData,
|
302
|
+
tracker: QubitTracker,
|
303
|
+
) -> tuple[QuantumCircuit, tuple[int], QubitTracker] | None:
|
304
|
+
"""
|
305
|
+
Attempts to synthesize an operation using plugin mechanism.
|
441
306
|
|
442
|
-
|
443
|
-
|
307
|
+
Input:
|
308
|
+
operation: the operation to be synthesized.
|
309
|
+
input_qubits: a list of global qubits (qubits in the original circuit) over
|
310
|
+
which the operation is defined.
|
311
|
+
data: high-level-synthesis data and options.
|
312
|
+
tracker: the global tracker, tracking the state of global qubits.
|
313
|
+
hls_methods: the list of synthesis methods to try.
|
444
314
|
|
445
|
-
|
315
|
+
The function is called from within Rust code.
|
446
316
|
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
of
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
#
|
470
|
-
#
|
471
|
-
|
472
|
-
|
473
|
-
# (2) High-level objects: try running the battery of high-level synthesis plugins (e.g.
|
474
|
-
# if the operation is a Clifford). Returns a circuit.
|
475
|
-
# (3) Unrolling custom definitions: try defining the operation if it is not yet
|
476
|
-
# in the set of supported instructions. Returns a circuit.
|
477
|
-
#
|
478
|
-
# If any of the above were triggered, we will recurse and go again through these steps
|
479
|
-
# until no further change occurred. At this point, we convert circuits to DAGs (the final
|
480
|
-
# possible return type). If there was no change, we just return ``None``.
|
481
|
-
num_original_qubits = len(qubits)
|
482
|
-
qubits = list(qubits)
|
483
|
-
|
484
|
-
synthesized = None
|
485
|
-
|
486
|
-
# Try synthesizing via AnnotatedOperation. This is faster than an isinstance check
|
487
|
-
# but a bit less safe since someone could create operations with a ``modifiers`` attribute.
|
488
|
-
if len(modifiers := getattr(operation, "modifiers", [])) > 0:
|
489
|
-
# Note: the base operation must be synthesized without using potential control qubits
|
490
|
-
# used in the modifiers.
|
491
|
-
num_ctrl = sum(
|
492
|
-
mod.num_ctrl_qubits for mod in modifiers if isinstance(mod, ControlModifier)
|
493
|
-
)
|
494
|
-
baseop_qubits = qubits[num_ctrl:] # reminder: control qubits are the first ones
|
495
|
-
|
496
|
-
# get qubits of base operation
|
497
|
-
control_qubits = qubits[0:num_ctrl]
|
498
|
-
|
499
|
-
# Do not allow access to control qubits
|
500
|
-
tracker.disable(context.to_globals(control_qubits))
|
501
|
-
synthesized_base_op, _ = self._synthesize_operation(
|
502
|
-
operation.base_op,
|
503
|
-
baseop_qubits,
|
504
|
-
tracker,
|
505
|
-
context,
|
506
|
-
use_ancillas=use_ancillas,
|
507
|
-
)
|
508
|
-
|
509
|
-
if synthesized_base_op is None:
|
510
|
-
synthesized_base_op = operation.base_op
|
511
|
-
elif isinstance(synthesized_base_op, DAGCircuit):
|
512
|
-
synthesized_base_op = dag_to_circuit(synthesized_base_op)
|
513
|
-
|
514
|
-
# Handle the case that synthesizing the base operation introduced
|
515
|
-
# additional qubits (e.g. the base operation is a circuit that includes
|
516
|
-
# an MCX gate).
|
517
|
-
if synthesized_base_op.num_qubits > len(baseop_qubits):
|
518
|
-
global_aux_qubits = tracker.borrow(
|
519
|
-
synthesized_base_op.num_qubits - len(baseop_qubits),
|
520
|
-
context.to_globals(baseop_qubits),
|
521
|
-
)
|
522
|
-
global_to_local = context.to_local_mapping()
|
523
|
-
for aq in global_aux_qubits:
|
524
|
-
if aq in global_to_local:
|
525
|
-
qubits.append(global_to_local[aq])
|
526
|
-
else:
|
527
|
-
new_local_qubit = context.add_qubit(aq)
|
528
|
-
qubits.append(new_local_qubit)
|
529
|
-
# Restore access to control qubits.
|
530
|
-
tracker.enable(context.to_globals(control_qubits))
|
531
|
-
|
532
|
-
# This step currently does not introduce ancilla qubits.
|
533
|
-
synthesized = self._apply_annotations(synthesized_base_op, operation.modifiers)
|
534
|
-
|
535
|
-
# If it was no AnnotatedOperation, try synthesizing via HLS or by unrolling.
|
317
|
+
Returns either the synthesized circuit or ``None`` (which may occur
|
318
|
+
when no synthesis methods is available or specified, or when there is
|
319
|
+
an insufficient number of auxiliary qubits).
|
320
|
+
"""
|
321
|
+
hls_methods = _methods_to_try(data, operation.name)
|
322
|
+
if len(hls_methods) == 0:
|
323
|
+
return None
|
324
|
+
|
325
|
+
hls_plugin_manager = data.hls_plugin_manager
|
326
|
+
num_clean_ancillas = tracker.num_clean(input_qubits)
|
327
|
+
num_dirty_ancillas = tracker.num_dirty(input_qubits)
|
328
|
+
|
329
|
+
best_decomposition = None
|
330
|
+
best_score = np.inf
|
331
|
+
|
332
|
+
for method in hls_methods:
|
333
|
+
# There are two ways to specify a synthesis method. The more explicit
|
334
|
+
# way is to specify it as a tuple consisting of a synthesis algorithm and a
|
335
|
+
# list of additional arguments, e.g.,
|
336
|
+
# ("kms", {"all_mats": 1, "max_paths": 100, "orig_circuit": 0}), or
|
337
|
+
# ("pmh", {}).
|
338
|
+
# When the list of additional arguments is empty, one can also specify
|
339
|
+
# just the synthesis algorithm, e.g.,
|
340
|
+
# "pmh".
|
341
|
+
if isinstance(method, tuple):
|
342
|
+
plugin_specifier, plugin_args = method
|
536
343
|
else:
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
operation
|
549
|
-
indices,
|
550
|
-
num_clean_available,
|
551
|
-
num_dirty_available,
|
552
|
-
)
|
553
|
-
|
554
|
-
# It may happen that the plugin synthesis method uses clean/dirty ancilla qubits
|
555
|
-
if (synthesized is not None) and (synthesized.num_qubits > len(qubits)):
|
556
|
-
# need to borrow more qubits from tracker
|
557
|
-
global_aux_qubits = tracker.borrow(
|
558
|
-
synthesized.num_qubits - len(qubits), context.to_globals(qubits)
|
559
|
-
)
|
560
|
-
global_to_local = context.to_local_mapping()
|
561
|
-
|
562
|
-
for aq in global_aux_qubits:
|
563
|
-
if aq in global_to_local:
|
564
|
-
qubits.append(global_to_local[aq])
|
565
|
-
else:
|
566
|
-
new_local_qubit = context.add_qubit(aq)
|
567
|
-
qubits.append(new_local_qubit)
|
568
|
-
|
569
|
-
# If HLS did not apply, or was unsuccessful, try unrolling custom definitions.
|
570
|
-
if synthesized is None and not self._top_level_only:
|
571
|
-
synthesized = self._get_custom_definition(operation, indices)
|
572
|
-
|
573
|
-
if synthesized is None:
|
574
|
-
# if we didn't synthesize, there was nothing to unroll
|
575
|
-
# updating the tracker will be handled upstream
|
576
|
-
pass
|
577
|
-
|
578
|
-
# if it has been synthesized, recurse and finally store the decomposition
|
579
|
-
elif isinstance(synthesized, Operation):
|
580
|
-
resynthesized, resynthesized_context = self._synthesize_operation(
|
581
|
-
synthesized, qubits, tracker, context, use_ancillas=use_ancillas
|
582
|
-
)
|
583
|
-
|
584
|
-
if resynthesized is not None:
|
585
|
-
synthesized = resynthesized
|
586
|
-
else:
|
587
|
-
tracker.set_dirty(context.to_globals(qubits))
|
588
|
-
if isinstance(resynthesized, DAGCircuit):
|
589
|
-
synthesized_context = resynthesized_context
|
590
|
-
|
591
|
-
elif isinstance(synthesized, QuantumCircuit):
|
592
|
-
# Synthesized is a quantum circuit which we want to process recursively.
|
593
|
-
# For example, it's the definition circuit of a custom gate
|
594
|
-
# or a circuit obtained by calling a synthesis method on a high-level-object.
|
595
|
-
# In the second case, synthesized may have more qubits than the original node.
|
596
|
-
|
597
|
-
as_dag = circuit_to_dag(synthesized, copy_operations=False)
|
598
|
-
inner_context = context.restrict(qubits)
|
599
|
-
|
600
|
-
if as_dag.num_qubits() != inner_context.num_qubits():
|
601
|
-
raise TranspilerError("HighLevelSynthesis internal error.")
|
602
|
-
|
603
|
-
# We save the current state of the tracker to be able to return the ancilla
|
604
|
-
# qubits to the current positions. Note that at this point we do not know
|
605
|
-
# which ancilla qubits will be allocated.
|
606
|
-
saved_tracker = tracker.copy()
|
607
|
-
synthesized = self._run(
|
608
|
-
as_dag, tracker, inner_context, use_ancillas=use_ancillas, top_level=False
|
609
|
-
)
|
610
|
-
synthesized_context = inner_context
|
611
|
-
|
612
|
-
if (synthesized is not None) and (synthesized.num_qubits() > len(qubits)):
|
613
|
-
# need to borrow more qubits from tracker
|
614
|
-
global_aux_qubits = tracker.borrow(
|
615
|
-
synthesized.num_qubits() - len(qubits), context.to_globals(qubits)
|
616
|
-
)
|
617
|
-
global_to_local = context.to_local_mapping()
|
618
|
-
|
619
|
-
for aq in global_aux_qubits:
|
620
|
-
if aq in global_to_local:
|
621
|
-
qubits.append(global_to_local[aq])
|
622
|
-
else:
|
623
|
-
new_local_qubit = context.add_qubit(aq)
|
624
|
-
qubits.append(new_local_qubit)
|
625
|
-
|
626
|
-
if len(qubits) > num_original_qubits:
|
627
|
-
tracker.replace_state(
|
628
|
-
saved_tracker, context.to_globals(qubits[num_original_qubits:])
|
344
|
+
plugin_specifier = method
|
345
|
+
plugin_args = {}
|
346
|
+
|
347
|
+
# There are two ways to specify a synthesis algorithm being run,
|
348
|
+
# either by name, e.g. "kms" (which then should be specified in entry_points),
|
349
|
+
# or directly as a class inherited from HighLevelSynthesisPlugin (which then
|
350
|
+
# does not need to be specified in entry_points).
|
351
|
+
if isinstance(plugin_specifier, str):
|
352
|
+
if plugin_specifier not in hls_plugin_manager.method_names(operation.name):
|
353
|
+
raise TranspilerError(
|
354
|
+
f"Specified method: {plugin_specifier} not found in available "
|
355
|
+
f"plugins for {operation.name}"
|
629
356
|
)
|
630
|
-
|
357
|
+
plugin_method = hls_plugin_manager.method(operation.name, plugin_specifier)
|
631
358
|
else:
|
632
|
-
|
633
|
-
|
634
|
-
if isinstance(synthesized, DAGCircuit) and synthesized_context is None:
|
635
|
-
raise TranspilerError("HighLevelSynthesis internal error.")
|
636
|
-
|
637
|
-
return synthesized, synthesized_context
|
638
|
-
|
639
|
-
def _get_custom_definition(
|
640
|
-
self, inst: Instruction, qubits: list[int] | None
|
641
|
-
) -> QuantumCircuit | None:
|
642
|
-
# check if the operation is already supported natively
|
643
|
-
if not (isinstance(inst, ControlledGate) and inst._open_ctrl):
|
644
|
-
# include path for when target exists but target.num_qubits is None (BasicSimulator)
|
645
|
-
inst_supported = self._instruction_supported(inst.name, qubits)
|
646
|
-
if inst_supported or (self._equiv_lib is not None and self._equiv_lib.has_entry(inst)):
|
647
|
-
return None # we support this operation already
|
648
|
-
|
649
|
-
# if not, try to get the definition
|
650
|
-
try:
|
651
|
-
definition = inst.definition
|
652
|
-
except (TypeError, AttributeError) as err:
|
653
|
-
raise TranspilerError(f"HighLevelSynthesis was unable to define {inst.name}.") from err
|
654
|
-
|
655
|
-
if definition is None:
|
656
|
-
raise TranspilerError(f"HighLevelSynthesis was unable to synthesize {inst}.")
|
657
|
-
|
658
|
-
return definition
|
659
|
-
|
660
|
-
def _methods_to_try(self, name: str):
|
661
|
-
"""Get a sequence of methods to try for a given op name."""
|
662
|
-
if (methods := self.hls_config.methods.get(name)) is not None:
|
663
|
-
# the operation's name appears in the user-provided config,
|
664
|
-
# we use the list of methods provided by the user
|
665
|
-
return methods
|
666
|
-
if (
|
667
|
-
self.hls_config.use_default_on_unspecified
|
668
|
-
and "default" in self.hls_plugin_manager.method_names(name)
|
669
|
-
):
|
670
|
-
# the operation's name does not appear in the user-specified config,
|
671
|
-
# we use the "default" method when instructed to do so and the "default"
|
672
|
-
# method is available
|
673
|
-
return ["default"]
|
674
|
-
return []
|
675
|
-
|
676
|
-
def _synthesize_op_using_plugins(
|
677
|
-
self,
|
678
|
-
hls_methods: list,
|
679
|
-
op: Operation,
|
680
|
-
qubits: list[int] | None,
|
681
|
-
num_clean_ancillas: int = 0,
|
682
|
-
num_dirty_ancillas: int = 0,
|
683
|
-
) -> QuantumCircuit | None:
|
684
|
-
"""
|
685
|
-
Attempts to synthesize op using plugin mechanism.
|
359
|
+
plugin_method = plugin_specifier
|
686
360
|
|
687
|
-
The arguments
|
688
|
-
|
689
|
-
|
361
|
+
# The additional arguments we pass to every plugin include the list of global
|
362
|
+
# qubits over which the operation is defined, high-level-synthesis data and options,
|
363
|
+
# and the tracker that tracks the state for global qubits.
|
364
|
+
#
|
365
|
+
# Note: the difference between the argument "qubits" passed explicitly to "run"
|
366
|
+
# and "input_qubits" passed via "plugin_args" is that for backwards compatibility
|
367
|
+
# the former should be None if the synthesis is done before layout/routing.
|
368
|
+
# However, plugins may need access to the global qubits over which the operation
|
369
|
+
# is defined, as well as their state, in particular the plugin for AnnotatedOperations
|
370
|
+
# requires these arguments to be able to process the base operation recursively.
|
371
|
+
#
|
372
|
+
# We may want to refactor the inputs and the outputs for the plugins' "run" method,
|
373
|
+
# however this needs to be backwards-compatible.
|
374
|
+
plugin_args["input_qubits"] = input_qubits
|
375
|
+
plugin_args["hls_data"] = data
|
376
|
+
plugin_args["qubit_tracker"] = tracker
|
377
|
+
plugin_args["num_clean_ancillas"] = num_clean_ancillas
|
378
|
+
plugin_args["num_dirty_ancillas"] = num_dirty_ancillas
|
379
|
+
|
380
|
+
qubits = input_qubits if data.use_physical_indices else None
|
381
|
+
|
382
|
+
decomposition = plugin_method.run(
|
383
|
+
operation,
|
384
|
+
coupling_map=data.coupling_map,
|
385
|
+
target=data.target,
|
386
|
+
qubits=qubits,
|
387
|
+
**plugin_args,
|
388
|
+
)
|
690
389
|
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
#
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
# or directly as a class inherited from HighLevelSynthesisPlugin (which then
|
718
|
-
# does not need to be specified in entry_points).
|
719
|
-
if isinstance(plugin_specifier, str):
|
720
|
-
if plugin_specifier not in hls_plugin_manager.method_names(op.name):
|
721
|
-
raise TranspilerError(
|
722
|
-
f"Specified method: {plugin_specifier} not found in available "
|
723
|
-
f"plugins for {op.name}"
|
724
|
-
)
|
725
|
-
plugin_method = hls_plugin_manager.method(op.name, plugin_specifier)
|
726
|
-
else:
|
727
|
-
plugin_method = plugin_specifier
|
728
|
-
|
729
|
-
# Set the number of available clean and dirty auxiliary qubits via plugin args.
|
730
|
-
plugin_args["num_clean_ancillas"] = num_clean_ancillas
|
731
|
-
plugin_args["num_dirty_ancillas"] = num_dirty_ancillas
|
732
|
-
|
733
|
-
decomposition = plugin_method.run(
|
734
|
-
op,
|
735
|
-
coupling_map=self._coupling_map,
|
736
|
-
target=self._target,
|
737
|
-
qubits=qubits,
|
738
|
-
**plugin_args,
|
390
|
+
# The synthesis methods that are not suited for the given higher-level-object
|
391
|
+
# will return None.
|
392
|
+
if decomposition is not None:
|
393
|
+
if data.hls_config.plugin_selection == "sequential":
|
394
|
+
# In the "sequential" mode the first successful decomposition is
|
395
|
+
# returned.
|
396
|
+
best_decomposition = decomposition
|
397
|
+
break
|
398
|
+
|
399
|
+
# In the "run everything" mode we update the best decomposition
|
400
|
+
# discovered
|
401
|
+
current_score = data.hls_config.plugin_evaluation_fn(decomposition)
|
402
|
+
if current_score < best_score:
|
403
|
+
best_decomposition = decomposition
|
404
|
+
best_score = current_score
|
405
|
+
|
406
|
+
# A synthesis method may have potentially used available ancilla qubits.
|
407
|
+
# The following greedily grabs global qubits available. In the additional
|
408
|
+
# refactoring mentioned previously, we want each plugin to actually return
|
409
|
+
# the global qubits used, especially when the synthesis is done on the physical
|
410
|
+
# circuit, and the choice of which ancilla qubits to use really matters.
|
411
|
+
output_qubits = input_qubits
|
412
|
+
if best_decomposition is not None:
|
413
|
+
if best_decomposition.num_qubits > len(input_qubits):
|
414
|
+
global_aux_qubits = tracker.borrow(
|
415
|
+
best_decomposition.num_qubits - len(input_qubits), input_qubits
|
739
416
|
)
|
417
|
+
output_qubits = output_qubits + global_aux_qubits
|
740
418
|
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
# returned.
|
747
|
-
best_decomposition = decomposition
|
748
|
-
break
|
749
|
-
|
750
|
-
# In the "run everything" mode we update the best decomposition
|
751
|
-
# discovered
|
752
|
-
current_score = self.hls_config.plugin_evaluation_fn(decomposition)
|
753
|
-
if current_score < best_score:
|
754
|
-
best_decomposition = decomposition
|
755
|
-
best_score = current_score
|
756
|
-
|
757
|
-
return best_decomposition
|
758
|
-
|
759
|
-
def _apply_annotations(
|
760
|
-
self, synthesized: Operation | QuantumCircuit, modifiers: list[Modifier]
|
761
|
-
) -> QuantumCircuit:
|
762
|
-
"""
|
763
|
-
Recursively synthesizes annotated operations.
|
764
|
-
Returns either the synthesized operation or None (which occurs when the operation
|
765
|
-
is not an annotated operation).
|
766
|
-
"""
|
767
|
-
for modifier in modifiers:
|
768
|
-
if isinstance(modifier, InverseModifier):
|
769
|
-
# Both QuantumCircuit and Gate have inverse method
|
770
|
-
synthesized = synthesized.inverse()
|
771
|
-
|
772
|
-
elif isinstance(modifier, ControlModifier):
|
773
|
-
# Both QuantumCircuit and Gate have control method, however for circuits
|
774
|
-
# it is more efficient to avoid constructing the controlled quantum circuit.
|
775
|
-
if isinstance(synthesized, QuantumCircuit):
|
776
|
-
synthesized = synthesized.to_gate()
|
777
|
-
|
778
|
-
synthesized = synthesized.control(
|
779
|
-
num_ctrl_qubits=modifier.num_ctrl_qubits,
|
780
|
-
label=None,
|
781
|
-
ctrl_state=modifier.ctrl_state,
|
782
|
-
annotated=False,
|
783
|
-
)
|
784
|
-
|
785
|
-
if isinstance(synthesized, AnnotatedOperation):
|
786
|
-
raise TranspilerError(
|
787
|
-
"HighLevelSynthesis failed to synthesize the control modifier."
|
788
|
-
)
|
789
|
-
|
790
|
-
elif isinstance(modifier, PowerModifier):
|
791
|
-
# QuantumCircuit has power method, and Gate needs to be converted
|
792
|
-
# to a quantum circuit.
|
793
|
-
if not isinstance(synthesized, QuantumCircuit):
|
794
|
-
synthesized = _instruction_to_circuit(synthesized)
|
795
|
-
|
796
|
-
synthesized = synthesized.power(modifier.power)
|
797
|
-
|
798
|
-
else:
|
799
|
-
raise TranspilerError(f"Unknown modifier {modifier}.")
|
800
|
-
|
801
|
-
return synthesized
|
802
|
-
|
803
|
-
def _definitely_skip_node(
|
804
|
-
self, node: DAGOpNode, qubits: tuple[int] | None, dag: DAGCircuit
|
805
|
-
) -> bool:
|
806
|
-
"""Fast-path determination of whether a node can certainly be skipped (i.e. nothing will
|
807
|
-
attempt to synthesise it) without accessing its Python-space `Operation`.
|
808
|
-
|
809
|
-
This is tightly coupled to `_recursively_handle_op`; it exists as a temporary measure to
|
810
|
-
avoid Python-space `Operation` creation from a `DAGOpNode` if we wouldn't do anything to the
|
811
|
-
node (which is _most_ nodes)."""
|
812
|
-
|
813
|
-
if (
|
814
|
-
dag._has_calibration_for(node)
|
815
|
-
or len(node.qargs) < self._min_qubits
|
816
|
-
or node.is_directive()
|
817
|
-
or (self._instruction_supported(node.name, qubits) and not node.is_control_flow())
|
818
|
-
):
|
819
|
-
return True
|
820
|
-
|
821
|
-
return (
|
822
|
-
# The fast path is just for Rust-space standard gates (which excludes
|
823
|
-
# `AnnotatedOperation`).
|
824
|
-
node.is_standard_gate()
|
825
|
-
# We don't have the fast-path for controlled gates over 3 or more qubits.
|
826
|
-
# However, we most probably want the fast-path for controlled 2-qubit gates
|
827
|
-
# (such as CX, CZ, CY, CH, CRX, and so on), so "_definitely_skip_node" should
|
828
|
-
# not immediately return False when encountering a controlled gate over 2 qubits.
|
829
|
-
and not (node.is_controlled_gate() and node.num_qubits >= 3)
|
830
|
-
# If there are plugins to try, they need to be tried.
|
831
|
-
and not self._methods_to_try(node.name)
|
832
|
-
# If all the above constraints hold, and it's already supported or the basis translator
|
833
|
-
# can handle it, we'll leave it be.
|
834
|
-
and (
|
835
|
-
# This uses unfortunately private details of `EquivalenceLibrary`, but so does the
|
836
|
-
# `BasisTranslator`, and this is supposed to just be temporary til this is moved
|
837
|
-
# into Rust space.
|
838
|
-
self._equiv_lib is not None
|
839
|
-
and equivalence.Key(name=node.name, num_qubits=node.num_qubits)
|
840
|
-
in self._equiv_lib.keys()
|
419
|
+
# This checks (in particular) that there is indeed a sufficient number
|
420
|
+
# of ancilla qubits to borrow from the tracker.
|
421
|
+
if best_decomposition.num_qubits != len(output_qubits):
|
422
|
+
raise TranspilerError(
|
423
|
+
"HighLevelSynthesis: the result from 'synthesize_op_using_plugin' is incorrect."
|
841
424
|
)
|
842
|
-
)
|
843
|
-
|
844
|
-
def _instruction_supported(self, name: str, qubits: tuple[int] | None) -> bool:
|
845
|
-
# include path for when target exists but target.num_qubits is None (BasicSimulator)
|
846
|
-
if self._target is None or self._target.num_qubits is None:
|
847
|
-
return name in self._device_insts
|
848
|
-
return self._target.instruction_supported(operation_name=name, qargs=qubits)
|
849
425
|
|
426
|
+
if best_decomposition is None:
|
427
|
+
return None
|
850
428
|
|
851
|
-
|
852
|
-
circuit = QuantumCircuit(inst.num_qubits, inst.num_clbits)
|
853
|
-
circuit.append(inst, circuit.qubits, circuit.clbits)
|
854
|
-
return circuit
|
429
|
+
return (best_decomposition, output_qubits)
|