qiskit 1.4.1__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 +11 -0
- 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/circuit/tools/pi_check.py +3 -0
- 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 +96 -116
- qiskit/qpy/binary_io/parse_sympy_repr.py +121 -0
- qiskit/qpy/binary_io/schedules.py +61 -388
- qiskit/qpy/binary_io/value.py +159 -33
- qiskit/qpy/common.py +10 -7
- qiskit/qpy/formats.py +41 -0
- qiskit/qpy/interface.py +29 -62
- 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/discrete_basis/generate_basis_approximations.py +2 -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 +3 -2
- 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.1.dist-info → qiskit-2.0.0.dist-info}/METADATA +4 -3
- {qiskit-1.4.1.dist-info → qiskit-2.0.0.dist-info}/RECORD +303 -449
- {qiskit-1.4.1.dist-info → qiskit-2.0.0.dist-info}/WHEEL +2 -1
- {qiskit-1.4.1.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.1.dist-info → qiskit-2.0.0.dist-info/licenses}/LICENSE.txt +0 -0
- {qiskit-1.4.1.dist-info → qiskit-2.0.0.dist-info}/top_level.txt +0 -0
@@ -11,126 +11,30 @@
|
|
11
11
|
# that they have been altered from the originals.
|
12
12
|
|
13
13
|
"""
|
14
|
-
|
15
|
-
Unitary Synthesis Plugin (in :mod:`qiskit.transpiler.passes.synthesis.unitary_synthesis`)
|
16
|
-
=========================================================================================
|
17
|
-
|
18
|
-
.. autosummary::
|
19
|
-
:toctree: ../stubs/
|
20
|
-
|
21
|
-
DefaultUnitarySynthesis
|
14
|
+
Unitary Synthesis Transpiler Pass
|
22
15
|
"""
|
23
16
|
|
24
17
|
from __future__ import annotations
|
25
|
-
from math import pi, inf, isclose
|
26
18
|
from typing import Any
|
27
|
-
from itertools import product
|
28
|
-
from functools import partial
|
29
|
-
import numpy as np
|
30
19
|
|
31
20
|
from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES
|
32
|
-
from qiskit.circuit import
|
33
|
-
from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping
|
34
|
-
from qiskit.circuit.library.standard_gates import (
|
35
|
-
iSwapGate,
|
36
|
-
CXGate,
|
37
|
-
CZGate,
|
38
|
-
RXXGate,
|
39
|
-
RZXGate,
|
40
|
-
RZZGate,
|
41
|
-
ECRGate,
|
42
|
-
RXGate,
|
43
|
-
SXGate,
|
44
|
-
XGate,
|
45
|
-
RZGate,
|
46
|
-
UGate,
|
47
|
-
PhaseGate,
|
48
|
-
U1Gate,
|
49
|
-
U2Gate,
|
50
|
-
U3Gate,
|
51
|
-
RYGate,
|
52
|
-
RGate,
|
53
|
-
)
|
21
|
+
from qiskit.circuit import CircuitInstruction
|
54
22
|
from qiskit.converters import circuit_to_dag, dag_to_circuit
|
55
23
|
from qiskit.dagcircuit.dagcircuit import DAGCircuit
|
56
24
|
from qiskit.dagcircuit.dagnode import DAGOpNode
|
57
|
-
from qiskit.exceptions import QiskitError
|
58
|
-
from qiskit.providers.models.backendproperties import BackendProperties
|
59
|
-
from qiskit.quantum_info import Operator
|
60
25
|
from qiskit.synthesis.one_qubit import one_qubit_decompose
|
61
|
-
|
62
|
-
from qiskit.synthesis.two_qubit.two_qubit_decompose import (
|
63
|
-
TwoQubitBasisDecomposer,
|
64
|
-
TwoQubitWeylDecomposition,
|
65
|
-
)
|
26
|
+
|
66
27
|
from qiskit.transpiler.basepasses import TransformationPass
|
67
28
|
from qiskit.transpiler.coupling import CouplingMap
|
68
29
|
from qiskit.transpiler.exceptions import TranspilerError
|
69
|
-
from qiskit.transpiler.passes.optimization.optimize_1q_decomposition import (
|
70
|
-
Optimize1qGatesDecomposition,
|
71
|
-
_possible_decomposers,
|
72
|
-
)
|
73
30
|
from qiskit.transpiler.passes.synthesis import plugin
|
74
31
|
from qiskit.transpiler.target import Target
|
75
32
|
|
76
|
-
from qiskit.
|
77
|
-
from qiskit._accelerate.unitary_synthesis import run_default_main_loop
|
78
|
-
|
79
|
-
GATE_NAME_MAP = {
|
80
|
-
"cx": CXGate._standard_gate,
|
81
|
-
"rx": RXGate._standard_gate,
|
82
|
-
"sx": SXGate._standard_gate,
|
83
|
-
"x": XGate._standard_gate,
|
84
|
-
"rz": RZGate._standard_gate,
|
85
|
-
"u": UGate._standard_gate,
|
86
|
-
"p": PhaseGate._standard_gate,
|
87
|
-
"u1": U1Gate._standard_gate,
|
88
|
-
"u2": U2Gate._standard_gate,
|
89
|
-
"u3": U3Gate._standard_gate,
|
90
|
-
"ry": RYGate._standard_gate,
|
91
|
-
"r": RGate._standard_gate,
|
92
|
-
}
|
93
|
-
|
94
|
-
|
95
|
-
KAK_GATE_NAMES = {
|
96
|
-
"cx": CXGate(),
|
97
|
-
"cz": CZGate(),
|
98
|
-
"iswap": iSwapGate(),
|
99
|
-
"rxx": RXXGate(pi / 2),
|
100
|
-
"ecr": ECRGate(),
|
101
|
-
"rzx": RZXGate(pi / 4), # typically pi/6 is also available
|
102
|
-
}
|
103
|
-
|
104
|
-
GateNameToGate = get_standard_gate_name_mapping()
|
105
|
-
|
106
|
-
|
107
|
-
def _choose_kak_gate(basis_gates):
|
108
|
-
"""Choose the first available 2q gate to use in the KAK decomposition."""
|
109
|
-
kak_gate = None
|
110
|
-
kak_gates = set(basis_gates or []).intersection(KAK_GATE_NAMES.keys())
|
111
|
-
if kak_gates:
|
112
|
-
kak_gate = KAK_GATE_NAMES[kak_gates.pop()]
|
113
|
-
|
114
|
-
return kak_gate
|
115
|
-
|
116
|
-
|
117
|
-
def _choose_euler_basis(basis_gates):
|
118
|
-
"""Choose the first available 1q basis to use in the Euler decomposition."""
|
119
|
-
basis_set = set(basis_gates or [])
|
120
|
-
decomposers = _possible_decomposers(basis_set)
|
121
|
-
if decomposers:
|
122
|
-
return decomposers[0]
|
123
|
-
return "U"
|
124
|
-
|
125
|
-
|
126
|
-
def _find_matching_euler_bases(target, qubit):
|
127
|
-
"""Find matching available 1q basis to use in the Euler decomposition."""
|
128
|
-
basis_set = target.operation_names_for_qargs((qubit,))
|
129
|
-
return _possible_decomposers(basis_set)
|
33
|
+
from qiskit._accelerate.unitary_synthesis import run_main_loop
|
130
34
|
|
131
35
|
|
132
36
|
def _choose_bases(basis_gates, basis_dict=None):
|
133
|
-
"""Find the matching basis string keys from the list of basis gates from the
|
37
|
+
"""Find the matching basis string keys from the list of basis gates from the target."""
|
134
38
|
if basis_gates is None:
|
135
39
|
basis_set = set()
|
136
40
|
else:
|
@@ -147,191 +51,14 @@ def _choose_bases(basis_gates, basis_dict=None):
|
|
147
51
|
return out_basis
|
148
52
|
|
149
53
|
|
150
|
-
def _decomposer_2q_from_basis_gates(basis_gates, pulse_optimize=None, approximation_degree=None):
|
151
|
-
decomposer2q = None
|
152
|
-
kak_gate = _choose_kak_gate(basis_gates)
|
153
|
-
euler_basis = _choose_euler_basis(basis_gates)
|
154
|
-
basis_fidelity = approximation_degree or 1.0
|
155
|
-
if isinstance(kak_gate, RZXGate):
|
156
|
-
backup_optimizer = TwoQubitBasisDecomposer(
|
157
|
-
CXGate(),
|
158
|
-
basis_fidelity=basis_fidelity,
|
159
|
-
euler_basis=euler_basis,
|
160
|
-
pulse_optimize=pulse_optimize,
|
161
|
-
)
|
162
|
-
decomposer2q = XXDecomposer(euler_basis=euler_basis, backup_optimizer=backup_optimizer)
|
163
|
-
elif kak_gate is not None:
|
164
|
-
decomposer2q = TwoQubitBasisDecomposer(
|
165
|
-
kak_gate,
|
166
|
-
basis_fidelity=basis_fidelity,
|
167
|
-
euler_basis=euler_basis,
|
168
|
-
pulse_optimize=pulse_optimize,
|
169
|
-
)
|
170
|
-
return decomposer2q
|
171
|
-
|
172
|
-
|
173
|
-
def _error(circuit, target=None, qubits=None):
|
174
|
-
"""
|
175
|
-
Calculate a rough error for a `circuit` that runs on specific
|
176
|
-
`qubits` of `target`.
|
177
|
-
|
178
|
-
Use basis errors from target if available, otherwise use length
|
179
|
-
of circuit as a weak proxy for error.
|
180
|
-
"""
|
181
|
-
if target is None:
|
182
|
-
if isinstance(circuit, DAGCircuit):
|
183
|
-
return len(circuit.op_nodes())
|
184
|
-
else:
|
185
|
-
return len(circuit)
|
186
|
-
gate_fidelities = []
|
187
|
-
gate_durations = []
|
188
|
-
|
189
|
-
def score_instruction(inst, inst_qubits):
|
190
|
-
try:
|
191
|
-
keys = target.operation_names_for_qargs(inst_qubits)
|
192
|
-
for key in keys:
|
193
|
-
target_op = target.operation_from_name(key)
|
194
|
-
if isinstance(circuit, DAGCircuit):
|
195
|
-
op = inst.op
|
196
|
-
else:
|
197
|
-
op = inst.operation
|
198
|
-
if isinstance(target_op, op.base_class) and (
|
199
|
-
target_op.is_parameterized()
|
200
|
-
or all(
|
201
|
-
isclose(float(p1), float(p2)) for p1, p2 in zip(target_op.params, op.params)
|
202
|
-
)
|
203
|
-
):
|
204
|
-
inst_props = target[key].get(inst_qubits, None)
|
205
|
-
if inst_props is not None:
|
206
|
-
error = getattr(inst_props, "error", 0.0) or 0.0
|
207
|
-
duration = getattr(inst_props, "duration", 0.0) or 0.0
|
208
|
-
gate_fidelities.append(1 - error)
|
209
|
-
gate_durations.append(duration)
|
210
|
-
else:
|
211
|
-
gate_fidelities.append(1.0)
|
212
|
-
gate_durations.append(0.0)
|
213
|
-
|
214
|
-
break
|
215
|
-
else:
|
216
|
-
raise KeyError
|
217
|
-
except KeyError as error:
|
218
|
-
if isinstance(circuit, DAGCircuit):
|
219
|
-
op = inst.op
|
220
|
-
else:
|
221
|
-
op = inst.operation
|
222
|
-
raise TranspilerError(
|
223
|
-
f"Encountered a bad synthesis. " f"Target has no {op} on qubits {qubits}."
|
224
|
-
) from error
|
225
|
-
|
226
|
-
if isinstance(circuit, DAGCircuit):
|
227
|
-
for inst in circuit.topological_op_nodes():
|
228
|
-
inst_qubits = tuple(qubits[circuit.find_bit(q).index] for q in inst.qargs)
|
229
|
-
score_instruction(inst, inst_qubits)
|
230
|
-
else:
|
231
|
-
for inst in circuit:
|
232
|
-
inst_qubits = tuple(qubits[circuit.find_bit(q).index] for q in inst.qubits)
|
233
|
-
score_instruction(inst, inst_qubits)
|
234
|
-
# TODO:return np.sum(gate_durations)
|
235
|
-
return 1 - np.prod(gate_fidelities)
|
236
|
-
|
237
|
-
|
238
|
-
def _preferred_direction(
|
239
|
-
decomposer2q, qubits, natural_direction, coupling_map=None, gate_lengths=None, gate_errors=None
|
240
|
-
):
|
241
|
-
"""
|
242
|
-
`decomposer2q` decomposes an SU(4) over `qubits`. A user sets `natural_direction`
|
243
|
-
to indicate whether they prefer synthesis in a hardware-native direction.
|
244
|
-
If yes, we return the `preferred_direction` here. If no hardware direction is
|
245
|
-
preferred, we raise an error (unless natural_direction is None).
|
246
|
-
We infer this from `coupling_map`, `gate_lengths`, `gate_errors`.
|
247
|
-
|
248
|
-
Returns [0, 1] if qubits are correct in the hardware-native direction.
|
249
|
-
Returns [1, 0] if qubits must be flipped to match hardware-native direction.
|
250
|
-
"""
|
251
|
-
qubits_tuple = tuple(qubits)
|
252
|
-
reverse_tuple = qubits_tuple[::-1]
|
253
|
-
|
254
|
-
preferred_direction = None
|
255
|
-
if natural_direction in {None, True}:
|
256
|
-
# find native gate directions from a (non-bidirectional) coupling map
|
257
|
-
if coupling_map is not None:
|
258
|
-
neighbors0 = coupling_map.neighbors(qubits[0])
|
259
|
-
zero_one = qubits[1] in neighbors0
|
260
|
-
neighbors1 = coupling_map.neighbors(qubits[1])
|
261
|
-
one_zero = qubits[0] in neighbors1
|
262
|
-
if zero_one and not one_zero:
|
263
|
-
preferred_direction = [0, 1]
|
264
|
-
if one_zero and not zero_one:
|
265
|
-
preferred_direction = [1, 0]
|
266
|
-
# otherwise infer natural directions from gate durations or gate errors
|
267
|
-
if preferred_direction is None and (gate_lengths or gate_errors):
|
268
|
-
cost_0_1 = inf
|
269
|
-
cost_1_0 = inf
|
270
|
-
try:
|
271
|
-
cost_0_1 = next(
|
272
|
-
duration
|
273
|
-
for gate, duration in gate_lengths.get(qubits_tuple, [])
|
274
|
-
if gate == decomposer2q.gate
|
275
|
-
)
|
276
|
-
except StopIteration:
|
277
|
-
pass
|
278
|
-
try:
|
279
|
-
cost_1_0 = next(
|
280
|
-
duration
|
281
|
-
for gate, duration in gate_lengths.get(reverse_tuple, [])
|
282
|
-
if gate == decomposer2q.gate
|
283
|
-
)
|
284
|
-
except StopIteration:
|
285
|
-
pass
|
286
|
-
if not (cost_0_1 < inf or cost_1_0 < inf):
|
287
|
-
try:
|
288
|
-
cost_0_1 = next(
|
289
|
-
error
|
290
|
-
for gate, error in gate_errors.get(qubits_tuple, [])
|
291
|
-
if gate == decomposer2q.gate
|
292
|
-
)
|
293
|
-
except StopIteration:
|
294
|
-
pass
|
295
|
-
try:
|
296
|
-
cost_1_0 = next(
|
297
|
-
error
|
298
|
-
for gate, error in gate_errors.get(reverse_tuple, [])
|
299
|
-
if gate == decomposer2q.gate
|
300
|
-
)
|
301
|
-
except StopIteration:
|
302
|
-
pass
|
303
|
-
if cost_0_1 < cost_1_0:
|
304
|
-
preferred_direction = [0, 1]
|
305
|
-
elif cost_1_0 < cost_0_1:
|
306
|
-
preferred_direction = [1, 0]
|
307
|
-
if natural_direction is True and preferred_direction is None:
|
308
|
-
raise TranspilerError(
|
309
|
-
f"No preferred direction of gate on qubits {qubits} "
|
310
|
-
"could be determined from coupling map or "
|
311
|
-
"gate lengths / gate errors."
|
312
|
-
)
|
313
|
-
return preferred_direction
|
314
|
-
|
315
|
-
|
316
54
|
class UnitarySynthesis(TransformationPass):
|
317
55
|
"""Synthesize gates according to their basis gates."""
|
318
56
|
|
319
|
-
@deprecate_arg(
|
320
|
-
name="backend_props",
|
321
|
-
since="1.4",
|
322
|
-
package_name="Qiskit",
|
323
|
-
removal_timeline="in Qiskit 2.0",
|
324
|
-
additional_msg="The BackendProperties data structure has been deprecated and will be "
|
325
|
-
"removed in Qiskit 2.0. The `target` input argument should be used instead. "
|
326
|
-
"You can use Target.from_configuration() to build the target from the properties "
|
327
|
-
"object, but in 2.0 you will need to generate a target directly.",
|
328
|
-
)
|
329
57
|
def __init__(
|
330
58
|
self,
|
331
59
|
basis_gates: list[str] = None,
|
332
60
|
approximation_degree: float | None = 1.0,
|
333
61
|
coupling_map: CouplingMap = None,
|
334
|
-
backend_props: BackendProperties = None,
|
335
62
|
pulse_optimize: bool | None = None,
|
336
63
|
natural_direction: bool | None = None,
|
337
64
|
synth_gates: list[str] | None = None,
|
@@ -343,7 +70,7 @@ class UnitarySynthesis(TransformationPass):
|
|
343
70
|
"""Synthesize unitaries over some basis gates.
|
344
71
|
|
345
72
|
This pass can approximate 2-qubit unitaries given some
|
346
|
-
gate fidelities (
|
73
|
+
gate fidelities (via ``target``).
|
347
74
|
More approximation can be forced by setting a heuristic dial
|
348
75
|
``approximation_degree``.
|
349
76
|
|
@@ -356,13 +83,11 @@ class UnitarySynthesis(TransformationPass):
|
|
356
83
|
(1.0=no approximation, 0.0=maximal approximation). Approximation can
|
357
84
|
make the synthesized circuit cheaper at the cost of straying from
|
358
85
|
the original unitary. If None, approximation is done based on gate fidelities.
|
359
|
-
coupling_map (CouplingMap): the coupling map of the
|
86
|
+
coupling_map (CouplingMap): the coupling map of the target
|
360
87
|
in case synthesis is done on a physical circuit. The
|
361
88
|
directionality of the coupling_map will be taken into
|
362
89
|
account if ``pulse_optimize`` is ``True``/``None`` and ``natural_direction``
|
363
90
|
is ``True``/``None``.
|
364
|
-
backend_props (BackendProperties): Properties of a backend to
|
365
|
-
synthesize for (e.g. gate fidelities).
|
366
91
|
pulse_optimize (bool): Whether to optimize pulses during
|
367
92
|
synthesis. A value of ``None`` will attempt it but fall
|
368
93
|
back if it does not succeed. A value of ``True`` will raise
|
@@ -374,7 +99,7 @@ class UnitarySynthesis(TransformationPass):
|
|
374
99
|
coupling map is unidirectional. If there is no
|
375
100
|
coupling map or the coupling map is bidirectional,
|
376
101
|
the gate direction with the shorter
|
377
|
-
duration from the
|
102
|
+
duration from the target properties will be used. If
|
378
103
|
set to True, and a natural direction can not be
|
379
104
|
determined, raises :class:`.TranspilerError`. If set to None, no
|
380
105
|
exception will be raised if a natural direction can
|
@@ -394,7 +119,7 @@ class UnitarySynthesis(TransformationPass):
|
|
394
119
|
your unitary synthesis plugin on how to use this.
|
395
120
|
target: The optional :class:`~.Target` for the target device the pass
|
396
121
|
is compiling for. If specified this will supersede the values
|
397
|
-
set for ``basis_gates
|
122
|
+
set for ``basis_gates`` and ``coupling_map``.
|
398
123
|
|
399
124
|
Raises:
|
400
125
|
TranspilerError: if ``method`` was specified but is not found in the
|
@@ -410,13 +135,14 @@ class UnitarySynthesis(TransformationPass):
|
|
410
135
|
if method != "default":
|
411
136
|
self.plugins = plugin.UnitarySynthesisPluginManager()
|
412
137
|
self._coupling_map = coupling_map
|
413
|
-
self._backend_props = backend_props
|
414
138
|
self._pulse_optimize = pulse_optimize
|
415
139
|
self._natural_direction = natural_direction
|
416
140
|
self._plugin_config = plugin_config
|
417
|
-
|
141
|
+
# Bypass target if it doesn't contain any basis gates (i.e it's _FakeTarget), as this
|
142
|
+
# not part of the official target model.
|
143
|
+
self._target = target if target is not None and len(target.operation_names) > 0 else None
|
418
144
|
if target is not None:
|
419
|
-
self._coupling_map =
|
145
|
+
self._coupling_map = target.build_coupling_map()
|
420
146
|
if synth_gates:
|
421
147
|
self._synth_gates = synth_gates
|
422
148
|
else:
|
@@ -448,6 +174,10 @@ class UnitarySynthesis(TransformationPass):
|
|
448
174
|
if self.plugins:
|
449
175
|
plugin_method = self.plugins.ext_plugins[self.method].obj
|
450
176
|
else:
|
177
|
+
from qiskit.transpiler.passes.synthesis.default_unitary_synth_plugin import (
|
178
|
+
DefaultUnitarySynthesis,
|
179
|
+
)
|
180
|
+
|
451
181
|
plugin_method = DefaultUnitarySynthesis()
|
452
182
|
plugin_kwargs: dict[str, Any] = {"config": self._plugin_config}
|
453
183
|
_gate_lengths = _gate_errors = None
|
@@ -483,19 +213,20 @@ class UnitarySynthesis(TransformationPass):
|
|
483
213
|
else {}
|
484
214
|
)
|
485
215
|
|
486
|
-
if self.method == "default"
|
216
|
+
if self.method == "default":
|
487
217
|
_coupling_edges = (
|
488
218
|
set(self._coupling_map.get_edges()) if self._coupling_map is not None else set()
|
489
219
|
)
|
490
|
-
|
491
|
-
out = run_default_main_loop(
|
220
|
+
out = run_main_loop(
|
492
221
|
dag,
|
493
222
|
list(qubit_indices.values()),
|
494
223
|
self._min_qubits,
|
495
224
|
self._target,
|
225
|
+
self._basis_gates,
|
496
226
|
_coupling_edges,
|
497
227
|
self._approximation_degree,
|
498
228
|
self._natural_direction,
|
229
|
+
self._pulse_optimize,
|
499
230
|
)
|
500
231
|
return out
|
501
232
|
else:
|
@@ -507,23 +238,19 @@ class UnitarySynthesis(TransformationPass):
|
|
507
238
|
if method.supports_pulse_optimize:
|
508
239
|
kwargs["pulse_optimize"] = self._pulse_optimize
|
509
240
|
if method.supports_gate_lengths:
|
510
|
-
_gate_lengths = _gate_lengths or _build_gate_lengths(
|
511
|
-
self._backend_props, self._target
|
512
|
-
)
|
241
|
+
_gate_lengths = _gate_lengths or _build_gate_lengths(self._target)
|
513
242
|
kwargs["gate_lengths"] = _gate_lengths
|
514
243
|
if method.supports_gate_errors:
|
515
|
-
_gate_errors = _gate_errors or _build_gate_errors(
|
516
|
-
self._backend_props, self._target
|
517
|
-
)
|
244
|
+
_gate_errors = _gate_errors or _build_gate_errors(self._target)
|
518
245
|
kwargs["gate_errors"] = _gate_errors
|
519
246
|
if method.supports_gate_lengths_by_qubit:
|
520
247
|
_gate_lengths_by_qubit = _gate_lengths_by_qubit or _build_gate_lengths_by_qubit(
|
521
|
-
self.
|
248
|
+
self._target
|
522
249
|
)
|
523
250
|
kwargs["gate_lengths_by_qubit"] = _gate_lengths_by_qubit
|
524
251
|
if method.supports_gate_errors_by_qubit:
|
525
252
|
_gate_errors_by_qubit = _gate_errors_by_qubit or _build_gate_errors_by_qubit(
|
526
|
-
self.
|
253
|
+
self._target
|
527
254
|
)
|
528
255
|
kwargs["gate_errors_by_qubit"] = _gate_errors_by_qubit
|
529
256
|
supported_bases = method.supported_bases
|
@@ -563,7 +290,7 @@ class UnitarySynthesis(TransformationPass):
|
|
563
290
|
for block in node.op.blocks
|
564
291
|
]
|
565
292
|
)
|
566
|
-
dag.substitute_node(node, new_op
|
293
|
+
dag.substitute_node(node, new_op)
|
567
294
|
|
568
295
|
out_dag = dag.copy_empty_like()
|
569
296
|
for node in dag.topological_op_nodes():
|
@@ -621,9 +348,8 @@ class UnitarySynthesis(TransformationPass):
|
|
621
348
|
return out_dag
|
622
349
|
|
623
350
|
|
624
|
-
def _build_gate_lengths(
|
625
|
-
"""Builds a ``gate_lengths`` dictionary from
|
626
|
-
or ``target`` (BackendV2).
|
351
|
+
def _build_gate_lengths(target=None):
|
352
|
+
"""Builds a ``gate_lengths`` dictionary from ``target`` (BackendV2).
|
627
353
|
|
628
354
|
The dictionary has the form:
|
629
355
|
{gate_name: {(qubits,): duration}}
|
@@ -635,21 +361,11 @@ def _build_gate_lengths(props=None, target=None):
|
|
635
361
|
for qubit, gate_props in prop_dict.items():
|
636
362
|
if gate_props is not None and gate_props.duration is not None:
|
637
363
|
gate_lengths[gate][qubit] = gate_props.duration
|
638
|
-
elif props is not None:
|
639
|
-
for gate in props._gates:
|
640
|
-
gate_lengths[gate] = {}
|
641
|
-
for k, v in props._gates[gate].items():
|
642
|
-
length = v.get("gate_length")
|
643
|
-
if length:
|
644
|
-
gate_lengths[gate][k] = length[0]
|
645
|
-
if not gate_lengths[gate]:
|
646
|
-
del gate_lengths[gate]
|
647
364
|
return gate_lengths
|
648
365
|
|
649
366
|
|
650
|
-
def _build_gate_errors(
|
651
|
-
"""Builds a ``gate_error`` dictionary from
|
652
|
-
or ``target`` (BackendV2).
|
367
|
+
def _build_gate_errors(target=None):
|
368
|
+
"""Builds a ``gate_error`` dictionary from ``target`` (BackendV2).
|
653
369
|
|
654
370
|
The dictionary has the form:
|
655
371
|
{gate_name: {(qubits,): error_rate}}
|
@@ -661,22 +377,12 @@ def _build_gate_errors(props=None, target=None):
|
|
661
377
|
for qubit, gate_props in prop_dict.items():
|
662
378
|
if gate_props is not None and gate_props.error is not None:
|
663
379
|
gate_errors[gate][qubit] = gate_props.error
|
664
|
-
if props is not None:
|
665
|
-
for gate in props._gates:
|
666
|
-
gate_errors[gate] = {}
|
667
|
-
for k, v in props._gates[gate].items():
|
668
|
-
error = v.get("gate_error")
|
669
|
-
if error:
|
670
|
-
gate_errors[gate][k] = error[0]
|
671
|
-
if not gate_errors[gate]:
|
672
|
-
del gate_errors[gate]
|
673
380
|
return gate_errors
|
674
381
|
|
675
382
|
|
676
|
-
def _build_gate_lengths_by_qubit(
|
383
|
+
def _build_gate_lengths_by_qubit(target=None):
|
677
384
|
"""
|
678
|
-
Builds a `gate_lengths` dictionary from
|
679
|
-
or `target (BackendV2)`.
|
385
|
+
Builds a `gate_lengths` dictionary from `target (BackendV2)`.
|
680
386
|
|
681
387
|
The dictionary has the form:
|
682
388
|
{(qubits): [Gate, duration]}
|
@@ -693,23 +399,12 @@ def _build_gate_lengths_by_qubit(props=None, target=None):
|
|
693
399
|
operation_and_durations.append((operation, duration))
|
694
400
|
if operation_and_durations:
|
695
401
|
gate_lengths[qubits] = operation_and_durations
|
696
|
-
elif props is not None:
|
697
|
-
for gate_name, gate_props in props._gates.items():
|
698
|
-
gate = GateNameToGate[gate_name]
|
699
|
-
for qubits, properties in gate_props.items():
|
700
|
-
duration = properties.get("gate_length", [0.0])[0]
|
701
|
-
operation_and_durations = (gate, duration)
|
702
|
-
if qubits in gate_lengths:
|
703
|
-
gate_lengths[qubits].append(operation_and_durations)
|
704
|
-
else:
|
705
|
-
gate_lengths[qubits] = [operation_and_durations]
|
706
402
|
return gate_lengths
|
707
403
|
|
708
404
|
|
709
|
-
def _build_gate_errors_by_qubit(
|
405
|
+
def _build_gate_errors_by_qubit(target=None):
|
710
406
|
"""
|
711
|
-
Builds a `gate_error` dictionary from
|
712
|
-
or `target (BackendV2)`.
|
407
|
+
Builds a `gate_error` dictionary from `target (BackendV2)`.
|
713
408
|
|
714
409
|
The dictionary has the form:
|
715
410
|
{(qubits): [Gate, error]}
|
@@ -726,362 +421,4 @@ def _build_gate_errors_by_qubit(props=None, target=None):
|
|
726
421
|
operation_and_errors.append((operation, error))
|
727
422
|
if operation_and_errors:
|
728
423
|
gate_errors[qubits] = operation_and_errors
|
729
|
-
elif props is not None:
|
730
|
-
for gate_name, gate_props in props._gates.items():
|
731
|
-
gate = GateNameToGate[gate_name]
|
732
|
-
for qubits, properties in gate_props.items():
|
733
|
-
error = properties.get("gate_error", [0.0])[0]
|
734
|
-
operation_and_errors = (gate, error)
|
735
|
-
if qubits in gate_errors:
|
736
|
-
gate_errors[qubits].append(operation_and_errors)
|
737
|
-
else:
|
738
|
-
gate_errors[qubits] = [operation_and_errors]
|
739
424
|
return gate_errors
|
740
|
-
|
741
|
-
|
742
|
-
class DefaultUnitarySynthesis(plugin.UnitarySynthesisPlugin):
|
743
|
-
"""The default unitary synthesis plugin."""
|
744
|
-
|
745
|
-
@property
|
746
|
-
def supports_basis_gates(self):
|
747
|
-
return True
|
748
|
-
|
749
|
-
@property
|
750
|
-
def supports_coupling_map(self):
|
751
|
-
return True
|
752
|
-
|
753
|
-
@property
|
754
|
-
def supports_natural_direction(self):
|
755
|
-
return True
|
756
|
-
|
757
|
-
@property
|
758
|
-
def supports_pulse_optimize(self):
|
759
|
-
return True
|
760
|
-
|
761
|
-
@property
|
762
|
-
def supports_gate_lengths(self):
|
763
|
-
return False
|
764
|
-
|
765
|
-
@property
|
766
|
-
def supports_gate_errors(self):
|
767
|
-
return False
|
768
|
-
|
769
|
-
@property
|
770
|
-
def supports_gate_lengths_by_qubit(self):
|
771
|
-
return True
|
772
|
-
|
773
|
-
@property
|
774
|
-
def supports_gate_errors_by_qubit(self):
|
775
|
-
return True
|
776
|
-
|
777
|
-
@property
|
778
|
-
def max_qubits(self):
|
779
|
-
return None
|
780
|
-
|
781
|
-
@property
|
782
|
-
def min_qubits(self):
|
783
|
-
return None
|
784
|
-
|
785
|
-
@property
|
786
|
-
def supported_bases(self):
|
787
|
-
return None
|
788
|
-
|
789
|
-
@property
|
790
|
-
def supports_target(self):
|
791
|
-
return True
|
792
|
-
|
793
|
-
def __init__(self):
|
794
|
-
super().__init__()
|
795
|
-
self._decomposer_cache = {}
|
796
|
-
|
797
|
-
def _decomposer_2q_from_target(self, target, qubits, approximation_degree):
|
798
|
-
# we just need 2-qubit decomposers, in any direction.
|
799
|
-
# we'll fix the synthesis direction later.
|
800
|
-
qubits_tuple = tuple(sorted(qubits))
|
801
|
-
reverse_tuple = qubits_tuple[::-1]
|
802
|
-
if qubits_tuple in self._decomposer_cache:
|
803
|
-
return self._decomposer_cache[qubits_tuple]
|
804
|
-
|
805
|
-
# available instructions on this qubit pair, and their associated property.
|
806
|
-
available_2q_basis = {}
|
807
|
-
available_2q_props = {}
|
808
|
-
|
809
|
-
# 2q gates sent to 2q decomposers must not have any symbolic parameters. The
|
810
|
-
# gates must be convertable to a numeric matrix. If a basis gate supports an arbitrary
|
811
|
-
# angle, we have to choose one angle (or more.)
|
812
|
-
def _replace_parameterized_gate(op):
|
813
|
-
if isinstance(op, RXXGate) and isinstance(op.params[0], Parameter):
|
814
|
-
op = RXXGate(pi / 2)
|
815
|
-
elif isinstance(op, RZXGate) and isinstance(op.params[0], Parameter):
|
816
|
-
op = RZXGate(pi / 4)
|
817
|
-
elif isinstance(op, RZZGate) and isinstance(op.params[0], Parameter):
|
818
|
-
op = RZZGate(pi / 2)
|
819
|
-
return op
|
820
|
-
|
821
|
-
try:
|
822
|
-
keys = target.operation_names_for_qargs(qubits_tuple)
|
823
|
-
for key in keys:
|
824
|
-
op = target.operation_from_name(key)
|
825
|
-
if not isinstance(op, Gate):
|
826
|
-
continue
|
827
|
-
available_2q_basis[key] = _replace_parameterized_gate(op)
|
828
|
-
available_2q_props[key] = target[key][qubits_tuple]
|
829
|
-
except KeyError:
|
830
|
-
pass
|
831
|
-
try:
|
832
|
-
keys = target.operation_names_for_qargs(reverse_tuple)
|
833
|
-
for key in keys:
|
834
|
-
if key not in available_2q_basis:
|
835
|
-
op = target.operation_from_name(key)
|
836
|
-
if not isinstance(op, Gate):
|
837
|
-
continue
|
838
|
-
available_2q_basis[key] = _replace_parameterized_gate(op)
|
839
|
-
available_2q_props[key] = target[key][reverse_tuple]
|
840
|
-
except KeyError:
|
841
|
-
pass
|
842
|
-
if not available_2q_basis:
|
843
|
-
raise TranspilerError(
|
844
|
-
f"Target has no gates available on qubits {qubits} to synthesize over."
|
845
|
-
)
|
846
|
-
# available decomposition basis on each of the qubits of the pair
|
847
|
-
# NOTE: assumes both qubits have the same single-qubit gates
|
848
|
-
available_1q_basis = _find_matching_euler_bases(target, qubits_tuple[0])
|
849
|
-
|
850
|
-
# find all decomposers
|
851
|
-
# TODO: reduce number of decomposers here somehow
|
852
|
-
decomposers = []
|
853
|
-
|
854
|
-
def is_supercontrolled(gate):
|
855
|
-
try:
|
856
|
-
operator = Operator(gate)
|
857
|
-
except QiskitError:
|
858
|
-
return False
|
859
|
-
kak = TwoQubitWeylDecomposition(operator.data)
|
860
|
-
return isclose(kak.a, pi / 4) and isclose(kak.c, 0.0)
|
861
|
-
|
862
|
-
def is_controlled(gate):
|
863
|
-
try:
|
864
|
-
operator = Operator(gate)
|
865
|
-
except QiskitError:
|
866
|
-
return False
|
867
|
-
kak = TwoQubitWeylDecomposition(operator.data)
|
868
|
-
return isclose(kak.b, 0.0) and isclose(kak.c, 0.0)
|
869
|
-
|
870
|
-
# possible supercontrolled decomposers (i.e. TwoQubitBasisDecomposer)
|
871
|
-
supercontrolled_basis = {
|
872
|
-
k: v for k, v in available_2q_basis.items() if is_supercontrolled(v)
|
873
|
-
}
|
874
|
-
for basis_1q, basis_2q in product(available_1q_basis, supercontrolled_basis.keys()):
|
875
|
-
props = available_2q_props.get(basis_2q)
|
876
|
-
if props is None:
|
877
|
-
basis_2q_fidelity = 1.0
|
878
|
-
else:
|
879
|
-
error = getattr(props, "error", 0.0)
|
880
|
-
if error is None:
|
881
|
-
error = 0.0
|
882
|
-
basis_2q_fidelity = 1 - error
|
883
|
-
if approximation_degree is not None:
|
884
|
-
basis_2q_fidelity *= approximation_degree
|
885
|
-
decomposer = TwoQubitBasisDecomposer(
|
886
|
-
supercontrolled_basis[basis_2q],
|
887
|
-
euler_basis=basis_1q,
|
888
|
-
basis_fidelity=basis_2q_fidelity,
|
889
|
-
)
|
890
|
-
decomposers.append(decomposer)
|
891
|
-
|
892
|
-
# If our 2q basis gates are a subset of cx, ecr, or cz then we know TwoQubitBasisDecomposer
|
893
|
-
# is an ideal decomposition and there is no need to bother calculating the XX embodiments
|
894
|
-
# or try the XX decomposer
|
895
|
-
if {"cx", "cz", "ecr"}.issuperset(available_2q_basis):
|
896
|
-
self._decomposer_cache[qubits_tuple] = decomposers
|
897
|
-
return decomposers
|
898
|
-
|
899
|
-
# possible controlled decomposers (i.e. XXDecomposer)
|
900
|
-
controlled_basis = {k: v for k, v in available_2q_basis.items() if is_controlled(v)}
|
901
|
-
basis_2q_fidelity = {}
|
902
|
-
embodiments = {}
|
903
|
-
pi2_basis = None
|
904
|
-
for k, v in controlled_basis.items():
|
905
|
-
strength = 2 * TwoQubitWeylDecomposition(Operator(v).data).a # pi/2: fully entangling
|
906
|
-
# each strength has its own fidelity
|
907
|
-
props = available_2q_props.get(k)
|
908
|
-
if props is None:
|
909
|
-
basis_2q_fidelity[strength] = 1.0
|
910
|
-
else:
|
911
|
-
error = getattr(props, "error", 0.0)
|
912
|
-
if error is None:
|
913
|
-
error = 0.0
|
914
|
-
basis_2q_fidelity[strength] = 1 - error
|
915
|
-
# rewrite XX of the same strength in terms of it
|
916
|
-
embodiment = XXEmbodiments[v.base_class]
|
917
|
-
if len(embodiment.parameters) == 1:
|
918
|
-
embodiments[strength] = embodiment.assign_parameters([strength])
|
919
|
-
else:
|
920
|
-
embodiments[strength] = embodiment
|
921
|
-
# basis equivalent to CX are well optimized so use for the pi/2 angle if available
|
922
|
-
if isclose(strength, pi / 2) and k in supercontrolled_basis:
|
923
|
-
pi2_basis = v
|
924
|
-
# if we are using the approximation_degree knob, use it to scale already-given fidelities
|
925
|
-
if approximation_degree is not None:
|
926
|
-
basis_2q_fidelity = {k: v * approximation_degree for k, v in basis_2q_fidelity.items()}
|
927
|
-
if basis_2q_fidelity:
|
928
|
-
for basis_1q in available_1q_basis:
|
929
|
-
if isinstance(pi2_basis, CXGate) and basis_1q == "ZSX":
|
930
|
-
# If we're going to use the pulse optimal decomposition
|
931
|
-
# in TwoQubitBasisDecomposer we need to compute the basis
|
932
|
-
# fidelity to use for the decomposition. Either use the
|
933
|
-
# cx error rate if approximation degree is None, or
|
934
|
-
# the approximation degree value if it's a float
|
935
|
-
if approximation_degree is None:
|
936
|
-
props = target["cx"].get(qubits_tuple)
|
937
|
-
if props is not None:
|
938
|
-
fidelity = 1.0 - getattr(props, "error", 0.0)
|
939
|
-
else:
|
940
|
-
fidelity = 1.0
|
941
|
-
else:
|
942
|
-
fidelity = approximation_degree
|
943
|
-
pi2_decomposer = TwoQubitBasisDecomposer(
|
944
|
-
pi2_basis,
|
945
|
-
euler_basis=basis_1q,
|
946
|
-
basis_fidelity=fidelity,
|
947
|
-
pulse_optimize=True,
|
948
|
-
)
|
949
|
-
embodiments.update({pi / 2: XXEmbodiments[pi2_decomposer.gate.base_class]})
|
950
|
-
else:
|
951
|
-
pi2_decomposer = None
|
952
|
-
decomposer = XXDecomposer(
|
953
|
-
basis_fidelity=basis_2q_fidelity,
|
954
|
-
euler_basis=basis_1q,
|
955
|
-
embodiments=embodiments,
|
956
|
-
backup_optimizer=pi2_decomposer,
|
957
|
-
)
|
958
|
-
decomposers.append(decomposer)
|
959
|
-
|
960
|
-
self._decomposer_cache[qubits_tuple] = decomposers
|
961
|
-
return decomposers
|
962
|
-
|
963
|
-
def run(self, unitary, **options):
|
964
|
-
# Approximation degree is set directly as an attribute on the
|
965
|
-
# instance by the UnitarySynthesis pass here as it's not part of
|
966
|
-
# plugin interface. However if for some reason it's not set assume
|
967
|
-
# it's 1.
|
968
|
-
approximation_degree = getattr(self, "_approximation_degree", 1.0)
|
969
|
-
basis_gates = options["basis_gates"]
|
970
|
-
coupling_map = options["coupling_map"][0]
|
971
|
-
natural_direction = options["natural_direction"]
|
972
|
-
pulse_optimize = options["pulse_optimize"]
|
973
|
-
gate_lengths = options["gate_lengths_by_qubit"]
|
974
|
-
gate_errors = options["gate_errors_by_qubit"]
|
975
|
-
qubits = options["coupling_map"][1]
|
976
|
-
target = options["target"]
|
977
|
-
|
978
|
-
if unitary.shape == (2, 2):
|
979
|
-
_decomposer1q = Optimize1qGatesDecomposition(basis_gates, target)
|
980
|
-
sequence = _decomposer1q._resynthesize_run(unitary, qubits[0])
|
981
|
-
if sequence is None:
|
982
|
-
return None
|
983
|
-
return _decomposer1q._gate_sequence_to_dag(sequence)
|
984
|
-
elif unitary.shape == (4, 4):
|
985
|
-
# select synthesizers that can lower to the target
|
986
|
-
if target is not None:
|
987
|
-
decomposers2q = self._decomposer_2q_from_target(
|
988
|
-
target, qubits, approximation_degree
|
989
|
-
)
|
990
|
-
else:
|
991
|
-
decomposer2q = _decomposer_2q_from_basis_gates(
|
992
|
-
basis_gates, pulse_optimize, approximation_degree
|
993
|
-
)
|
994
|
-
decomposers2q = [decomposer2q] if decomposer2q is not None else []
|
995
|
-
# choose the cheapest output among synthesized circuits
|
996
|
-
synth_circuits = []
|
997
|
-
# If we have a single TwoQubitBasisDecomposer skip dag creation as we don't need to
|
998
|
-
# store and can instead manually create the synthesized gates directly in the output dag
|
999
|
-
if len(decomposers2q) == 1 and isinstance(decomposers2q[0], TwoQubitBasisDecomposer):
|
1000
|
-
preferred_direction = _preferred_direction(
|
1001
|
-
decomposers2q[0],
|
1002
|
-
qubits,
|
1003
|
-
natural_direction,
|
1004
|
-
coupling_map,
|
1005
|
-
gate_lengths,
|
1006
|
-
gate_errors,
|
1007
|
-
)
|
1008
|
-
return self._synth_su4_no_dag(
|
1009
|
-
unitary, decomposers2q[0], preferred_direction, approximation_degree
|
1010
|
-
)
|
1011
|
-
for decomposer2q in decomposers2q:
|
1012
|
-
preferred_direction = _preferred_direction(
|
1013
|
-
decomposer2q, qubits, natural_direction, coupling_map, gate_lengths, gate_errors
|
1014
|
-
)
|
1015
|
-
synth_circuit = self._synth_su4(
|
1016
|
-
unitary, decomposer2q, preferred_direction, approximation_degree
|
1017
|
-
)
|
1018
|
-
synth_circuits.append(synth_circuit)
|
1019
|
-
synth_circuit = min(
|
1020
|
-
synth_circuits,
|
1021
|
-
key=partial(_error, target=target, qubits=tuple(qubits)),
|
1022
|
-
default=None,
|
1023
|
-
)
|
1024
|
-
else:
|
1025
|
-
from qiskit.synthesis.unitary.qsd import ( # pylint: disable=cyclic-import
|
1026
|
-
qs_decomposition,
|
1027
|
-
)
|
1028
|
-
|
1029
|
-
# only decompose if needed. TODO: handle basis better
|
1030
|
-
synth_circuit = qs_decomposition(unitary) if (basis_gates or target) else None
|
1031
|
-
if synth_circuit is None:
|
1032
|
-
return None
|
1033
|
-
if isinstance(synth_circuit, DAGCircuit):
|
1034
|
-
return synth_circuit
|
1035
|
-
return circuit_to_dag(synth_circuit)
|
1036
|
-
|
1037
|
-
def _synth_su4_no_dag(self, unitary, decomposer2q, preferred_direction, approximation_degree):
|
1038
|
-
approximate = not approximation_degree == 1.0
|
1039
|
-
synth_circ = decomposer2q._inner_decomposer(unitary, approximate=approximate)
|
1040
|
-
if not preferred_direction:
|
1041
|
-
return (synth_circ, synth_circ.global_phase, decomposer2q.gate)
|
1042
|
-
|
1043
|
-
synth_direction = None
|
1044
|
-
# if the gates in synthesis are in the opposite direction of the preferred direction
|
1045
|
-
# resynthesize a new operator which is the original conjugated by swaps.
|
1046
|
-
# this new operator is doubly mirrored from the original and is locally equivalent.
|
1047
|
-
for gate, _params, qubits in synth_circ:
|
1048
|
-
if gate is None or gate == CXGate._standard_gate:
|
1049
|
-
synth_direction = qubits
|
1050
|
-
if synth_direction is not None and synth_direction != preferred_direction:
|
1051
|
-
# TODO: Avoid using a dag to correct the synthesis direction
|
1052
|
-
return self._reversed_synth_su4(unitary, decomposer2q, approximation_degree)
|
1053
|
-
return (synth_circ, synth_circ.global_phase, decomposer2q.gate)
|
1054
|
-
|
1055
|
-
def _synth_su4(self, su4_mat, decomposer2q, preferred_direction, approximation_degree):
|
1056
|
-
approximate = not approximation_degree == 1.0
|
1057
|
-
synth_circ = decomposer2q(su4_mat, approximate=approximate, use_dag=True)
|
1058
|
-
if not preferred_direction:
|
1059
|
-
return synth_circ
|
1060
|
-
synth_direction = None
|
1061
|
-
# if the gates in synthesis are in the opposite direction of the preferred direction
|
1062
|
-
# resynthesize a new operator which is the original conjugated by swaps.
|
1063
|
-
# this new operator is doubly mirrored from the original and is locally equivalent.
|
1064
|
-
for inst in synth_circ.topological_op_nodes():
|
1065
|
-
if inst.op.num_qubits == 2:
|
1066
|
-
synth_direction = [synth_circ.find_bit(q).index for q in inst.qargs]
|
1067
|
-
if synth_direction is not None and synth_direction != preferred_direction:
|
1068
|
-
return self._reversed_synth_su4(su4_mat, decomposer2q, approximation_degree)
|
1069
|
-
return synth_circ
|
1070
|
-
|
1071
|
-
def _reversed_synth_su4(self, su4_mat, decomposer2q, approximation_degree):
|
1072
|
-
approximate = not approximation_degree == 1.0
|
1073
|
-
su4_mat_mm = su4_mat.copy()
|
1074
|
-
su4_mat_mm[[1, 2]] = su4_mat_mm[[2, 1]]
|
1075
|
-
su4_mat_mm[:, [1, 2]] = su4_mat_mm[:, [2, 1]]
|
1076
|
-
synth_circ = decomposer2q(su4_mat_mm, approximate=approximate, use_dag=True)
|
1077
|
-
out_dag = DAGCircuit()
|
1078
|
-
out_dag.global_phase = synth_circ.global_phase
|
1079
|
-
out_dag.add_qubits(list(reversed(synth_circ.qubits)))
|
1080
|
-
flip_bits = out_dag.qubits[::-1]
|
1081
|
-
for node in synth_circ.topological_op_nodes():
|
1082
|
-
qubits = tuple(flip_bits[synth_circ.find_bit(x).index] for x in node.qargs)
|
1083
|
-
node = DAGOpNode.from_instruction(
|
1084
|
-
node._to_circuit_instruction().replace(qubits=qubits, params=node.params)
|
1085
|
-
)
|
1086
|
-
out_dag._apply_op_node_back(node)
|
1087
|
-
return out_dag
|