qiskit 1.1.2__cp38-abi3-win32.whl → 1.2.0__cp38-abi3-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qiskit/VERSION.txt +1 -1
- qiskit/__init__.py +27 -24
- qiskit/_accelerate.pyd +0 -0
- qiskit/_numpy_compat.py +1 -1
- qiskit/assembler/assemble_circuits.py +107 -64
- qiskit/assembler/assemble_schedules.py +5 -12
- qiskit/assembler/disassemble.py +10 -1
- qiskit/circuit/__init__.py +6 -3
- qiskit/circuit/_classical_resource_map.py +5 -5
- qiskit/circuit/_utils.py +0 -13
- qiskit/circuit/add_control.py +1 -1
- qiskit/circuit/annotated_operation.py +23 -1
- qiskit/circuit/classical/expr/expr.py +4 -4
- qiskit/circuit/classical/expr/visitors.py +1 -1
- qiskit/circuit/classical/types/__init__.py +1 -1
- qiskit/circuit/classical/types/types.py +2 -2
- qiskit/circuit/classicalfunction/boolean_expression.py +1 -1
- qiskit/circuit/classicalfunction/classical_function_visitor.py +5 -5
- qiskit/circuit/classicalfunction/utils.py +1 -1
- qiskit/circuit/classicalregister.py +1 -1
- qiskit/circuit/commutation_checker.py +83 -35
- qiskit/circuit/controlflow/_builder_utils.py +1 -1
- qiskit/circuit/controlflow/builder.py +10 -6
- qiskit/circuit/controlflow/if_else.py +2 -2
- qiskit/circuit/controlflow/switch_case.py +1 -1
- qiskit/circuit/delay.py +1 -1
- qiskit/circuit/duration.py +2 -2
- qiskit/circuit/equivalence.py +5 -7
- qiskit/circuit/gate.py +11 -8
- qiskit/circuit/instruction.py +31 -13
- qiskit/circuit/instructionset.py +2 -5
- qiskit/circuit/library/__init__.py +2 -1
- qiskit/circuit/library/arithmetic/linear_amplitude_function.py +1 -1
- qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +1 -1
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +1 -1
- qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +1 -1
- qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +3 -3
- qiskit/circuit/library/arithmetic/polynomial_pauli_rotations.py +1 -1
- qiskit/circuit/library/basis_change/__init__.py +1 -1
- qiskit/circuit/library/basis_change/qft.py +40 -6
- qiskit/circuit/library/blueprintcircuit.py +3 -5
- qiskit/circuit/library/data_preparation/__init__.py +9 -2
- qiskit/circuit/library/data_preparation/initializer.py +8 -0
- qiskit/circuit/library/data_preparation/state_preparation.py +98 -178
- qiskit/circuit/library/generalized_gates/isometry.py +8 -8
- qiskit/circuit/library/generalized_gates/linear_function.py +3 -2
- qiskit/circuit/library/generalized_gates/mcg_up_to_diagonal.py +4 -4
- qiskit/circuit/library/generalized_gates/permutation.py +8 -9
- qiskit/circuit/library/generalized_gates/uc.py +3 -3
- qiskit/circuit/library/generalized_gates/uc_pauli_rot.py +2 -2
- qiskit/circuit/library/generalized_gates/unitary.py +13 -11
- qiskit/circuit/library/graph_state.py +1 -1
- qiskit/circuit/library/hamiltonian_gate.py +1 -2
- qiskit/circuit/library/hidden_linear_function.py +1 -1
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +3 -2
- qiskit/circuit/library/n_local/n_local.py +4 -5
- qiskit/circuit/library/n_local/pauli_two_design.py +1 -1
- qiskit/circuit/library/n_local/qaoa_ansatz.py +6 -8
- qiskit/circuit/library/n_local/two_local.py +1 -1
- qiskit/circuit/library/overlap.py +11 -5
- qiskit/circuit/library/pauli_evolution.py +7 -3
- qiskit/circuit/library/standard_gates/dcx.py +3 -0
- qiskit/circuit/library/standard_gates/ecr.py +3 -0
- qiskit/circuit/library/standard_gates/global_phase.py +3 -0
- qiskit/circuit/library/standard_gates/h.py +13 -5
- qiskit/circuit/library/standard_gates/i.py +3 -0
- qiskit/circuit/library/standard_gates/iswap.py +3 -0
- qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +19 -10
- qiskit/circuit/library/standard_gates/p.py +14 -9
- qiskit/circuit/library/standard_gates/r.py +3 -0
- qiskit/circuit/library/standard_gates/rx.py +21 -6
- qiskit/circuit/library/standard_gates/rxx.py +40 -1
- qiskit/circuit/library/standard_gates/ry.py +21 -6
- qiskit/circuit/library/standard_gates/ryy.py +40 -1
- qiskit/circuit/library/standard_gates/rz.py +22 -6
- qiskit/circuit/library/standard_gates/rzx.py +40 -1
- qiskit/circuit/library/standard_gates/rzz.py +41 -2
- qiskit/circuit/library/standard_gates/s.py +77 -0
- qiskit/circuit/library/standard_gates/swap.py +12 -5
- qiskit/circuit/library/standard_gates/sx.py +14 -5
- qiskit/circuit/library/standard_gates/t.py +5 -0
- qiskit/circuit/library/standard_gates/u.py +22 -7
- qiskit/circuit/library/standard_gates/u1.py +8 -3
- qiskit/circuit/library/standard_gates/u2.py +3 -0
- qiskit/circuit/library/standard_gates/u3.py +22 -7
- qiskit/circuit/library/standard_gates/x.py +156 -92
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +40 -1
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +52 -11
- qiskit/circuit/library/standard_gates/y.py +6 -1
- qiskit/circuit/library/standard_gates/z.py +8 -1
- qiskit/circuit/operation.py +1 -1
- qiskit/circuit/parameter.py +9 -10
- qiskit/circuit/parameterexpression.py +16 -13
- qiskit/circuit/parametertable.py +1 -190
- qiskit/circuit/parametervector.py +1 -1
- qiskit/circuit/quantumcircuit.py +395 -387
- qiskit/circuit/quantumcircuitdata.py +3 -5
- qiskit/circuit/quantumregister.py +1 -1
- qiskit/circuit/random/__init__.py +1 -1
- qiskit/circuit/random/utils.py +175 -26
- qiskit/circuit/register.py +5 -7
- qiskit/circuit/singleton.py +3 -3
- qiskit/circuit/tools/pi_check.py +4 -4
- qiskit/compiler/assembler.py +95 -24
- qiskit/compiler/scheduler.py +2 -2
- qiskit/compiler/transpiler.py +42 -128
- qiskit/converters/circuit_to_dag.py +4 -6
- qiskit/converters/circuit_to_gate.py +4 -8
- qiskit/converters/circuit_to_instruction.py +5 -17
- qiskit/converters/dag_to_circuit.py +2 -6
- qiskit/dagcircuit/collect_blocks.py +2 -2
- qiskit/dagcircuit/dagcircuit.py +190 -187
- qiskit/dagcircuit/dagdependency.py +4 -4
- qiskit/dagcircuit/dagdependency_v2.py +4 -4
- qiskit/dagcircuit/dagdepnode.py +1 -1
- qiskit/dagcircuit/dagnode.py +66 -157
- qiskit/passmanager/flow_controllers.py +1 -1
- qiskit/passmanager/passmanager.py +3 -3
- qiskit/primitives/__init__.py +1 -5
- qiskit/primitives/backend_estimator.py +25 -15
- qiskit/primitives/backend_estimator_v2.py +31 -7
- qiskit/primitives/backend_sampler.py +21 -12
- qiskit/primitives/backend_sampler_v2.py +12 -3
- qiskit/primitives/base/base_estimator.py +31 -4
- qiskit/primitives/base/base_primitive.py +2 -2
- qiskit/primitives/base/base_result.py +2 -2
- qiskit/primitives/base/base_sampler.py +26 -2
- qiskit/primitives/base/estimator_result.py +2 -2
- qiskit/primitives/base/sampler_result.py +2 -2
- qiskit/primitives/containers/__init__.py +0 -1
- qiskit/primitives/containers/bindings_array.py +2 -2
- qiskit/primitives/containers/bit_array.py +108 -10
- qiskit/primitives/containers/shape.py +3 -3
- qiskit/primitives/estimator.py +9 -2
- qiskit/primitives/primitive_job.py +1 -1
- qiskit/primitives/sampler.py +10 -3
- qiskit/primitives/statevector_estimator.py +5 -3
- qiskit/primitives/statevector_sampler.py +11 -5
- qiskit/primitives/utils.py +16 -0
- qiskit/providers/backend.py +15 -6
- qiskit/providers/backend_compat.py +7 -4
- qiskit/providers/basic_provider/basic_provider_tools.py +1 -1
- qiskit/providers/basic_provider/basic_simulator.py +33 -25
- qiskit/providers/fake_provider/fake_backend.py +10 -3
- qiskit/providers/fake_provider/fake_openpulse_2q.py +157 -149
- qiskit/providers/fake_provider/fake_openpulse_3q.py +228 -220
- qiskit/providers/fake_provider/fake_pulse_backend.py +2 -1
- qiskit/providers/fake_provider/fake_qasm_backend.py +7 -2
- qiskit/providers/fake_provider/generic_backend_v2.py +514 -68
- qiskit/providers/models/__init__.py +48 -11
- qiskit/providers/models/backendconfiguration.py +50 -4
- qiskit/providers/models/backendproperties.py +13 -2
- qiskit/providers/models/pulsedefaults.py +10 -11
- qiskit/providers/options.py +13 -13
- qiskit/providers/providerutils.py +3 -1
- qiskit/pulse/configuration.py +8 -12
- qiskit/pulse/instruction_schedule_map.py +3 -5
- qiskit/pulse/instructions/acquire.py +7 -8
- qiskit/pulse/instructions/instruction.py +2 -3
- qiskit/pulse/library/samplers/decorators.py +5 -9
- qiskit/pulse/library/symbolic_pulses.py +4 -7
- qiskit/pulse/library/waveform.py +2 -5
- qiskit/pulse/macros.py +11 -6
- qiskit/pulse/parser.py +8 -10
- qiskit/pulse/schedule.py +9 -17
- qiskit/pulse/transforms/alignments.py +1 -3
- qiskit/pulse/utils.py +1 -2
- qiskit/qasm/libs/stdgates.inc +35 -28
- qiskit/qasm2/__init__.py +7 -7
- qiskit/qasm2/export.py +5 -9
- qiskit/qasm2/parse.py +1 -1
- qiskit/qasm3/ast.py +9 -25
- qiskit/qasm3/exporter.py +582 -479
- qiskit/qasm3/printer.py +7 -16
- qiskit/qobj/common.py +10 -0
- qiskit/qobj/converters/lo_config.py +9 -0
- qiskit/qobj/converters/pulse_instruction.py +13 -6
- qiskit/qobj/pulse_qobj.py +69 -15
- qiskit/qobj/qasm_qobj.py +72 -20
- qiskit/qobj/utils.py +9 -0
- qiskit/qpy/__init__.py +1 -1
- qiskit/qpy/binary_io/circuits.py +8 -5
- qiskit/qpy/binary_io/schedules.py +1 -1
- qiskit/qpy/binary_io/value.py +3 -3
- qiskit/qpy/interface.py +3 -2
- qiskit/qpy/type_keys.py +2 -2
- qiskit/quantum_info/operators/channel/quantum_channel.py +3 -6
- qiskit/quantum_info/operators/channel/superop.py +2 -2
- qiskit/quantum_info/operators/channel/transformations.py +1 -1
- qiskit/quantum_info/operators/dihedral/dihedral.py +3 -4
- qiskit/quantum_info/operators/dihedral/dihedral_circuits.py +1 -3
- qiskit/quantum_info/operators/dihedral/random.py +6 -3
- qiskit/quantum_info/operators/measures.py +2 -2
- qiskit/quantum_info/operators/op_shape.py +12 -20
- qiskit/quantum_info/operators/operator.py +14 -21
- qiskit/quantum_info/operators/predicates.py +1 -0
- qiskit/quantum_info/operators/symplectic/base_pauli.py +7 -11
- qiskit/quantum_info/operators/symplectic/clifford.py +1 -1
- qiskit/quantum_info/operators/symplectic/pauli.py +3 -3
- qiskit/quantum_info/operators/symplectic/pauli_list.py +9 -10
- qiskit/quantum_info/operators/symplectic/random.py +1 -1
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +15 -17
- qiskit/quantum_info/quaternion.py +1 -1
- qiskit/quantum_info/states/densitymatrix.py +5 -8
- qiskit/quantum_info/states/stabilizerstate.py +128 -37
- qiskit/quantum_info/states/statevector.py +4 -8
- qiskit/result/counts.py +2 -2
- qiskit/result/mitigation/correlated_readout_mitigator.py +2 -2
- qiskit/result/mitigation/local_readout_mitigator.py +2 -2
- qiskit/result/mitigation/utils.py +1 -3
- qiskit/result/models.py +17 -16
- qiskit/result/result.py +15 -20
- qiskit/scheduler/lowering.py +2 -2
- qiskit/synthesis/__init__.py +2 -1
- qiskit/synthesis/clifford/__init__.py +1 -1
- qiskit/synthesis/clifford/clifford_decompose_ag.py +2 -2
- qiskit/synthesis/clifford/clifford_decompose_bm.py +10 -240
- qiskit/synthesis/clifford/clifford_decompose_greedy.py +9 -303
- qiskit/synthesis/clifford/clifford_decompose_layers.py +25 -23
- qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_full.py +1 -1
- qiskit/synthesis/cnotdihedral/cnotdihedral_decompose_general.py +1 -1
- qiskit/synthesis/discrete_basis/generate_basis_approximations.py +1 -1
- qiskit/synthesis/discrete_basis/solovay_kitaev.py +2 -2
- qiskit/synthesis/evolution/evolution_synthesis.py +4 -2
- qiskit/synthesis/evolution/lie_trotter.py +46 -19
- qiskit/synthesis/evolution/product_formula.py +111 -55
- qiskit/synthesis/evolution/qdrift.py +40 -10
- qiskit/synthesis/evolution/suzuki_trotter.py +43 -33
- qiskit/synthesis/linear/__init__.py +1 -0
- qiskit/synthesis/linear/cnot_synth.py +22 -96
- qiskit/synthesis/linear/linear_depth_lnn.py +8 -8
- qiskit/synthesis/linear/linear_matrix_utils.py +13 -161
- qiskit/synthesis/linear_phase/cnot_phase_synth.py +1 -1
- qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py +3 -3
- qiskit/synthesis/linear_phase/cz_depth_lnn.py +1 -1
- qiskit/synthesis/one_qubit/one_qubit_decompose.py +29 -29
- qiskit/synthesis/permutation/permutation_full.py +5 -29
- qiskit/synthesis/permutation/permutation_lnn.py +2 -24
- qiskit/synthesis/permutation/permutation_utils.py +2 -59
- qiskit/synthesis/qft/__init__.py +1 -0
- qiskit/synthesis/qft/qft_decompose_full.py +79 -0
- qiskit/synthesis/qft/qft_decompose_lnn.py +17 -9
- qiskit/synthesis/stabilizer/stabilizer_circuit.py +6 -6
- qiskit/synthesis/stabilizer/stabilizer_decompose.py +2 -2
- qiskit/synthesis/two_qubit/local_invariance.py +8 -38
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +48 -129
- qiskit/synthesis/unitary/aqc/cnot_structures.py +1 -1
- qiskit/synthesis/unitary/qsd.py +5 -3
- qiskit/transpiler/__init__.py +1 -0
- qiskit/transpiler/basepasses.py +1 -1
- qiskit/transpiler/coupling.py +3 -3
- qiskit/transpiler/instruction_durations.py +1 -2
- qiskit/transpiler/layout.py +3 -3
- qiskit/transpiler/passes/__init__.py +2 -0
- qiskit/transpiler/passes/basis/basis_translator.py +84 -64
- qiskit/transpiler/passes/basis/translate_parameterized.py +3 -5
- qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
- qiskit/transpiler/passes/basis/unroll_custom_definitions.py +10 -10
- qiskit/transpiler/passes/calibration/rx_builder.py +3 -3
- qiskit/transpiler/passes/calibration/rzx_builder.py +3 -3
- qiskit/transpiler/passes/layout/apply_layout.py +13 -3
- qiskit/transpiler/passes/layout/sabre_layout.py +10 -8
- qiskit/transpiler/passes/layout/sabre_pre_layout.py +4 -1
- qiskit/transpiler/passes/layout/set_layout.py +2 -2
- qiskit/transpiler/passes/layout/vf2_layout.py +1 -1
- qiskit/transpiler/passes/layout/vf2_utils.py +3 -3
- qiskit/transpiler/passes/optimization/__init__.py +1 -0
- qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +2 -2
- qiskit/transpiler/passes/optimization/commutation_analysis.py +7 -10
- qiskit/transpiler/passes/optimization/commutative_cancellation.py +35 -19
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +17 -8
- qiskit/transpiler/passes/optimization/inverse_cancellation.py +6 -6
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +64 -41
- qiskit/transpiler/passes/optimization/optimize_1q_gates.py +1 -1
- qiskit/transpiler/passes/optimization/split_2q_unitaries.py +83 -0
- qiskit/transpiler/passes/optimization/template_matching/backward_match.py +1 -1
- qiskit/transpiler/passes/optimization/template_matching/forward_match.py +2 -2
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +1 -1
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +3 -2
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/swap_strategy.py +1 -1
- qiskit/transpiler/passes/routing/layout_transformation.py +2 -1
- qiskit/transpiler/passes/routing/sabre_swap.py +35 -26
- qiskit/transpiler/passes/routing/star_prerouting.py +80 -105
- qiskit/transpiler/passes/routing/stochastic_swap.py +1 -3
- qiskit/transpiler/passes/scheduling/alap.py +1 -2
- qiskit/transpiler/passes/scheduling/alignments/__init__.py +2 -2
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -1
- qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +2 -2
- qiskit/transpiler/passes/scheduling/alignments/reschedule.py +1 -1
- qiskit/transpiler/passes/scheduling/asap.py +1 -2
- qiskit/transpiler/passes/scheduling/base_scheduler.py +5 -5
- qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +3 -3
- qiskit/transpiler/passes/scheduling/padding/base_padding.py +1 -1
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +20 -14
- qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +7 -6
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +4 -3
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +211 -36
- qiskit/transpiler/passes/synthesis/plugin.py +2 -2
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +80 -40
- qiskit/transpiler/passes/utils/__init__.py +0 -1
- qiskit/transpiler/passes/utils/check_gate_direction.py +4 -4
- qiskit/transpiler/passes/utils/check_map.py +3 -6
- qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +3 -4
- qiskit/transpiler/passes/utils/error.py +2 -2
- qiskit/transpiler/passes/utils/fixed_point.py +3 -3
- qiskit/transpiler/passes/utils/gate_direction.py +1 -1
- qiskit/transpiler/passes/utils/gates_basis.py +1 -2
- qiskit/transpiler/passmanager.py +7 -6
- qiskit/transpiler/preset_passmanagers/__init__.py +4 -228
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +73 -18
- qiskit/transpiler/preset_passmanagers/common.py +3 -6
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +518 -0
- qiskit/transpiler/preset_passmanagers/level0.py +1 -1
- qiskit/transpiler/target.py +27 -8
- qiskit/user_config.py +29 -6
- qiskit/utils/classtools.py +3 -3
- qiskit/utils/deprecation.py +3 -2
- qiskit/utils/lazy_tester.py +2 -2
- qiskit/utils/optionals.py +8 -8
- qiskit/visualization/bloch.py +18 -23
- qiskit/visualization/circuit/_utils.py +34 -10
- qiskit/visualization/circuit/circuit_visualization.py +23 -16
- qiskit/visualization/circuit/latex.py +29 -27
- qiskit/visualization/circuit/matplotlib.py +4 -2
- qiskit/visualization/circuit/qcstyle.py +2 -2
- qiskit/visualization/circuit/text.py +9 -15
- qiskit/visualization/dag_visualization.py +2 -2
- qiskit/visualization/pulse_v2/core.py +1 -1
- qiskit/visualization/pulse_v2/events.py +1 -1
- qiskit/visualization/pulse_v2/generators/frame.py +3 -4
- qiskit/visualization/pulse_v2/generators/waveform.py +5 -9
- qiskit/visualization/pulse_v2/layouts.py +1 -5
- qiskit/visualization/pulse_v2/plotters/matplotlib.py +1 -2
- qiskit/visualization/state_visualization.py +5 -6
- qiskit/visualization/timeline/plotters/matplotlib.py +1 -2
- qiskit/visualization/transition_visualization.py +7 -2
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/METADATA +12 -12
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/RECORD +342 -340
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/entry_points.txt +3 -0
- qiskit/transpiler/passes/utils/block_to_matrix.py +0 -47
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/WHEEL +0 -0
- {qiskit-1.1.2.dist-info → qiskit-1.2.0.dist-info}/top_level.txt +0 -0
@@ -131,9 +131,38 @@ Permutation Synthesis
|
|
131
131
|
ACGSynthesisPermutation
|
132
132
|
KMSSynthesisPermutation
|
133
133
|
TokenSwapperSynthesisPermutation
|
134
|
+
|
135
|
+
|
136
|
+
QFT Synthesis
|
137
|
+
'''''''''''''
|
138
|
+
|
139
|
+
.. list-table:: Plugins for :class:`.QFTGate` (key = ``"qft"``)
|
140
|
+
:header-rows: 1
|
141
|
+
|
142
|
+
* - Plugin name
|
143
|
+
- Plugin class
|
144
|
+
- Targeted connectivity
|
145
|
+
* - ``"full"``
|
146
|
+
- :class:`~.QFTSynthesisFull`
|
147
|
+
- all-to-all
|
148
|
+
* - ``"line"``
|
149
|
+
- :class:`~.QFTSynthesisLine`
|
150
|
+
- linear
|
151
|
+
* - ``"default"``
|
152
|
+
- :class:`~.QFTSynthesisFull`
|
153
|
+
- all-to-all
|
154
|
+
|
155
|
+
.. autosummary::
|
156
|
+
:toctree: ../stubs/
|
157
|
+
|
158
|
+
QFTSynthesisFull
|
159
|
+
QFTSynthesisLine
|
134
160
|
"""
|
135
161
|
|
136
|
-
from
|
162
|
+
from __future__ import annotations
|
163
|
+
|
164
|
+
import typing
|
165
|
+
from typing import Optional, Union, List, Tuple, Callable, Sequence
|
137
166
|
|
138
167
|
import numpy as np
|
139
168
|
import rustworkx as rx
|
@@ -142,7 +171,7 @@ from qiskit.circuit.operation import Operation
|
|
142
171
|
from qiskit.converters import circuit_to_dag, dag_to_circuit
|
143
172
|
from qiskit.transpiler.basepasses import TransformationPass
|
144
173
|
from qiskit.circuit.quantumcircuit import QuantumCircuit
|
145
|
-
from qiskit.circuit import
|
174
|
+
from qiskit.circuit import ControlledGate, EquivalenceLibrary, equivalence
|
146
175
|
from qiskit.circuit.library import LinearFunction
|
147
176
|
from qiskit.transpiler.passes.utils import control_flow
|
148
177
|
from qiskit.transpiler.target import Target
|
@@ -157,6 +186,7 @@ from qiskit.circuit.annotated_operation import (
|
|
157
186
|
ControlModifier,
|
158
187
|
PowerModifier,
|
159
188
|
)
|
189
|
+
from qiskit.circuit.library import QFTGate
|
160
190
|
from qiskit.synthesis.clifford import (
|
161
191
|
synth_clifford_full,
|
162
192
|
synth_clifford_layers,
|
@@ -176,9 +206,16 @@ from qiskit.synthesis.permutation import (
|
|
176
206
|
synth_permutation_acg,
|
177
207
|
synth_permutation_depth_lnn_kms,
|
178
208
|
)
|
209
|
+
from qiskit.synthesis.qft import (
|
210
|
+
synth_qft_full,
|
211
|
+
synth_qft_line,
|
212
|
+
)
|
179
213
|
|
180
214
|
from .plugin import HighLevelSynthesisPluginManager, HighLevelSynthesisPlugin
|
181
215
|
|
216
|
+
if typing.TYPE_CHECKING:
|
217
|
+
from qiskit.dagcircuit import DAGOpNode
|
218
|
+
|
182
219
|
|
183
220
|
class HLSConfig:
|
184
221
|
"""The high-level-synthesis config allows to specify a list of "methods" used by
|
@@ -365,6 +402,8 @@ class HighLevelSynthesis(TransformationPass):
|
|
365
402
|
if not self._top_level_only and (self._target is None or self._target.num_qubits is None):
|
366
403
|
basic_insts = {"measure", "reset", "barrier", "snapshot", "delay", "store"}
|
367
404
|
self._device_insts = basic_insts | set(self._basis_gates)
|
405
|
+
else:
|
406
|
+
self._device_insts = set()
|
368
407
|
|
369
408
|
def run(self, dag: DAGCircuit) -> DAGCircuit:
|
370
409
|
"""Run the HighLevelSynthesis pass on `dag`.
|
@@ -384,11 +423,11 @@ class HighLevelSynthesis(TransformationPass):
|
|
384
423
|
dag_op_nodes = dag.op_nodes()
|
385
424
|
|
386
425
|
for node in dag_op_nodes:
|
387
|
-
if
|
426
|
+
if node.is_control_flow():
|
388
427
|
node.op = control_flow.map_blocks(self.run, node.op)
|
389
428
|
continue
|
390
429
|
|
391
|
-
if
|
430
|
+
if node.is_directive():
|
392
431
|
continue
|
393
432
|
|
394
433
|
if dag.has_calibration_for(node) or len(node.qargs) < self._min_qubits:
|
@@ -398,6 +437,9 @@ class HighLevelSynthesis(TransformationPass):
|
|
398
437
|
[dag.find_bit(x).index for x in node.qargs] if self._use_qubit_indices else None
|
399
438
|
)
|
400
439
|
|
440
|
+
if self._definitely_skip_node(node, qubits):
|
441
|
+
continue
|
442
|
+
|
401
443
|
decomposition, modified = self._recursively_handle_op(node.op, qubits)
|
402
444
|
|
403
445
|
if not modified:
|
@@ -414,6 +456,43 @@ class HighLevelSynthesis(TransformationPass):
|
|
414
456
|
|
415
457
|
return dag
|
416
458
|
|
459
|
+
def _definitely_skip_node(self, node: DAGOpNode, qubits: Sequence[int] | None) -> bool:
|
460
|
+
"""Fast-path determination of whether a node can certainly be skipped (i.e. nothing will
|
461
|
+
attempt to synthesise it) without accessing its Python-space `Operation`.
|
462
|
+
|
463
|
+
This is tightly coupled to `_recursively_handle_op`; it exists as a temporary measure to
|
464
|
+
avoid Python-space `Operation` creation from a `DAGOpNode` if we wouldn't do anything to the
|
465
|
+
node (which is _most_ nodes)."""
|
466
|
+
return (
|
467
|
+
# The fast path is just for Rust-space standard gates (which excludes
|
468
|
+
# `AnnotatedOperation`).
|
469
|
+
node.is_standard_gate()
|
470
|
+
# If it's a controlled gate, we might choose to do funny things to it.
|
471
|
+
and not node.is_controlled_gate()
|
472
|
+
# If there are plugins to try, they need to be tried.
|
473
|
+
and not self._methods_to_try(node.name)
|
474
|
+
# If all the above constraints hold, and it's already supported or the basis translator
|
475
|
+
# can handle it, we'll leave it be.
|
476
|
+
and (
|
477
|
+
self._instruction_supported(node.name, qubits)
|
478
|
+
# This uses unfortunately private details of `EquivalenceLibrary`, but so does the
|
479
|
+
# `BasisTranslator`, and this is supposed to just be temporary til this is moved
|
480
|
+
# into Rust space.
|
481
|
+
or (
|
482
|
+
self._equiv_lib is not None
|
483
|
+
and equivalence.Key(name=node.name, num_qubits=node.num_qubits)
|
484
|
+
in self._equiv_lib._key_to_node_index
|
485
|
+
)
|
486
|
+
)
|
487
|
+
)
|
488
|
+
|
489
|
+
def _instruction_supported(self, name: str, qubits: Sequence[int]) -> bool:
|
490
|
+
qubits = tuple(qubits) if qubits is not None else None
|
491
|
+
# include path for when target exists but target.num_qubits is None (BasicSimulator)
|
492
|
+
if self._target is None or self._target.num_qubits is None:
|
493
|
+
return name in self._device_insts
|
494
|
+
return self._target.instruction_supported(operation_name=name, qargs=qubits)
|
495
|
+
|
417
496
|
def _recursively_handle_op(
|
418
497
|
self, op: Operation, qubits: Optional[List] = None
|
419
498
|
) -> Tuple[Union[QuantumCircuit, DAGCircuit, Operation], bool]:
|
@@ -441,6 +520,9 @@ class HighLevelSynthesis(TransformationPass):
|
|
441
520
|
an annotated operation.
|
442
521
|
"""
|
443
522
|
|
523
|
+
# WARNING: if adding new things in here, ensure that `_definitely_skip_node` is also
|
524
|
+
# up-to-date.
|
525
|
+
|
444
526
|
# Try to apply plugin mechanism
|
445
527
|
decomposition = self._synthesize_op_using_plugins(op, qubits)
|
446
528
|
if decomposition is not None:
|
@@ -459,17 +541,9 @@ class HighLevelSynthesis(TransformationPass):
|
|
459
541
|
# or is in equivalence library
|
460
542
|
controlled_gate_open_ctrl = isinstance(op, ControlledGate) and op._open_ctrl
|
461
543
|
if not controlled_gate_open_ctrl:
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
self._target.instruction_supported(
|
466
|
-
operation_name=op.name,
|
467
|
-
qargs=qargs,
|
468
|
-
)
|
469
|
-
if self._target is not None and self._target.num_qubits is not None
|
470
|
-
else op.name in self._device_insts
|
471
|
-
)
|
472
|
-
if inst_supported or (self._equiv_lib is not None and self._equiv_lib.has_entry(op)):
|
544
|
+
if self._instruction_supported(op.name, qubits) or (
|
545
|
+
self._equiv_lib is not None and self._equiv_lib.has_entry(op)
|
546
|
+
):
|
473
547
|
return op, False
|
474
548
|
|
475
549
|
try:
|
@@ -490,6 +564,22 @@ class HighLevelSynthesis(TransformationPass):
|
|
490
564
|
dag = self.run(dag)
|
491
565
|
return dag, True
|
492
566
|
|
567
|
+
def _methods_to_try(self, name: str):
|
568
|
+
"""Get a sequence of methods to try for a given op name."""
|
569
|
+
if (methods := self.hls_config.methods.get(name)) is not None:
|
570
|
+
# the operation's name appears in the user-provided config,
|
571
|
+
# we use the list of methods provided by the user
|
572
|
+
return methods
|
573
|
+
if (
|
574
|
+
self.hls_config.use_default_on_unspecified
|
575
|
+
and "default" in self.hls_plugin_manager.method_names(name)
|
576
|
+
):
|
577
|
+
# the operation's name does not appear in the user-specified config,
|
578
|
+
# we use the "default" method when instructed to do so and the "default"
|
579
|
+
# method is available
|
580
|
+
return ["default"]
|
581
|
+
return []
|
582
|
+
|
493
583
|
def _synthesize_op_using_plugins(
|
494
584
|
self, op: Operation, qubits: List
|
495
585
|
) -> Union[QuantumCircuit, None]:
|
@@ -500,25 +590,10 @@ class HighLevelSynthesis(TransformationPass):
|
|
500
590
|
"""
|
501
591
|
hls_plugin_manager = self.hls_plugin_manager
|
502
592
|
|
503
|
-
if op.name in self.hls_config.methods.keys():
|
504
|
-
# the operation's name appears in the user-provided config,
|
505
|
-
# we use the list of methods provided by the user
|
506
|
-
methods = self.hls_config.methods[op.name]
|
507
|
-
elif (
|
508
|
-
self.hls_config.use_default_on_unspecified
|
509
|
-
and "default" in hls_plugin_manager.method_names(op.name)
|
510
|
-
):
|
511
|
-
# the operation's name does not appear in the user-specified config,
|
512
|
-
# we use the "default" method when instructed to do so and the "default"
|
513
|
-
# method is available
|
514
|
-
methods = ["default"]
|
515
|
-
else:
|
516
|
-
methods = []
|
517
|
-
|
518
593
|
best_decomposition = None
|
519
594
|
best_score = np.inf
|
520
595
|
|
521
|
-
for method in
|
596
|
+
for method in self._methods_to_try(op.name):
|
522
597
|
# There are two ways to specify a synthesis method. The more explicit
|
523
598
|
# way is to specify it as a tuple consisting of a synthesis algorithm and a
|
524
599
|
# list of additional arguments, e.g.,
|
@@ -540,8 +615,8 @@ class HighLevelSynthesis(TransformationPass):
|
|
540
615
|
if isinstance(plugin_specifier, str):
|
541
616
|
if plugin_specifier not in hls_plugin_manager.method_names(op.name):
|
542
617
|
raise TranspilerError(
|
543
|
-
"Specified method:
|
544
|
-
|
618
|
+
f"Specified method: {plugin_specifier} not found in available "
|
619
|
+
f"plugins for {op.name}"
|
545
620
|
)
|
546
621
|
plugin_method = hls_plugin_manager.method(op.name, plugin_specifier)
|
547
622
|
else:
|
@@ -779,7 +854,7 @@ class KMSSynthesisLinearFunction(HighLevelSynthesisPlugin):
|
|
779
854
|
use_inverted = options.get("use_inverted", False)
|
780
855
|
use_transposed = options.get("use_transposed", False)
|
781
856
|
|
782
|
-
mat = high_level_object.linear.astype(
|
857
|
+
mat = high_level_object.linear.astype(bool, copy=False)
|
783
858
|
|
784
859
|
if use_transposed:
|
785
860
|
mat = np.transpose(mat)
|
@@ -831,7 +906,7 @@ class PMHSynthesisLinearFunction(HighLevelSynthesisPlugin):
|
|
831
906
|
use_inverted = options.get("use_inverted", False)
|
832
907
|
use_transposed = options.get("use_transposed", False)
|
833
908
|
|
834
|
-
mat = high_level_object.linear.astype(
|
909
|
+
mat = high_level_object.linear.astype(bool, copy=False)
|
835
910
|
|
836
911
|
if use_transposed:
|
837
912
|
mat = np.transpose(mat)
|
@@ -887,6 +962,107 @@ class ACGSynthesisPermutation(HighLevelSynthesisPlugin):
|
|
887
962
|
return decomposition
|
888
963
|
|
889
964
|
|
965
|
+
class QFTSynthesisFull(HighLevelSynthesisPlugin):
|
966
|
+
"""Synthesis plugin for QFT gates using all-to-all connectivity.
|
967
|
+
|
968
|
+
This plugin name is :``qft.full`` which can be used as the key on
|
969
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
970
|
+
|
971
|
+
The plugin supports the following additional options:
|
972
|
+
|
973
|
+
* reverse_qubits (bool): Whether to synthesize the "QFT" operation (if ``False``,
|
974
|
+
which is the default) or the "QFT-with-reversal" operation (if ``True``).
|
975
|
+
Some implementation of the ``QFTGate`` include a layer of swap gates at the end
|
976
|
+
of the synthesized circuit, which can in principle be dropped if the ``QFTGate``
|
977
|
+
itself is the last gate in the circuit.
|
978
|
+
* approximation_degree (int): The degree of approximation (0 for no approximation).
|
979
|
+
It is possible to implement the QFT approximately by ignoring
|
980
|
+
controlled-phase rotations with the angle beneath a threshold. This is discussed
|
981
|
+
in more detail in [1] or [2].
|
982
|
+
* insert_barriers (bool): If True, barriers are inserted as visualization improvement.
|
983
|
+
* inverse (bool): If True, the inverse Fourier transform is constructed.
|
984
|
+
* name (str): The name of the circuit.
|
985
|
+
|
986
|
+
References:
|
987
|
+
1. Adriano Barenco, Artur Ekert, Kalle-Antti Suominen, and Päivi Törmä,
|
988
|
+
*Approximate Quantum Fourier Transform and Decoherence*,
|
989
|
+
Physical Review A (1996).
|
990
|
+
`arXiv:quant-ph/9601018 [quant-ph] <https://arxiv.org/abs/quant-ph/9601018>`_
|
991
|
+
2. Donny Cheung,
|
992
|
+
*Improved Bounds for the Approximate QFT* (2004),
|
993
|
+
`arXiv:quant-ph/0403071 [quant-ph] <https://https://arxiv.org/abs/quant-ph/0403071>`_
|
994
|
+
"""
|
995
|
+
|
996
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
997
|
+
"""Run synthesis for the given QFTGate."""
|
998
|
+
if not isinstance(high_level_object, QFTGate):
|
999
|
+
raise TranspilerError(
|
1000
|
+
"The synthesis plugin 'qft.full` only applies to objects of type QFTGate."
|
1001
|
+
)
|
1002
|
+
|
1003
|
+
reverse_qubits = options.get("reverse_qubits", False)
|
1004
|
+
approximation_degree = options.get("approximation_degree", 0)
|
1005
|
+
insert_barriers = options.get("insert_barriers", False)
|
1006
|
+
inverse = options.get("inverse", False)
|
1007
|
+
name = options.get("name", None)
|
1008
|
+
|
1009
|
+
decomposition = synth_qft_full(
|
1010
|
+
num_qubits=high_level_object.num_qubits,
|
1011
|
+
do_swaps=not reverse_qubits,
|
1012
|
+
approximation_degree=approximation_degree,
|
1013
|
+
insert_barriers=insert_barriers,
|
1014
|
+
inverse=inverse,
|
1015
|
+
name=name,
|
1016
|
+
)
|
1017
|
+
return decomposition
|
1018
|
+
|
1019
|
+
|
1020
|
+
class QFTSynthesisLine(HighLevelSynthesisPlugin):
|
1021
|
+
"""Synthesis plugin for QFT gates using linear connectivity.
|
1022
|
+
|
1023
|
+
This plugin name is :``qft.line`` which can be used as the key on
|
1024
|
+
an :class:`~.HLSConfig` object to use this method with :class:`~.HighLevelSynthesis`.
|
1025
|
+
|
1026
|
+
The plugin supports the following additional options:
|
1027
|
+
|
1028
|
+
* reverse_qubits (bool): Whether to synthesize the "QFT" operation (if ``False``,
|
1029
|
+
which is the default) or the "QFT-with-reversal" operation (if ``True``).
|
1030
|
+
Some implementation of the ``QFTGate`` include a layer of swap gates at the end
|
1031
|
+
of the synthesized circuit, which can in principle be dropped if the ``QFTGate``
|
1032
|
+
itself is the last gate in the circuit.
|
1033
|
+
* approximation_degree (int): the degree of approximation (0 for no approximation).
|
1034
|
+
It is possible to implement the QFT approximately by ignoring
|
1035
|
+
controlled-phase rotations with the angle beneath a threshold. This is discussed
|
1036
|
+
in more detail in [1] or [2].
|
1037
|
+
|
1038
|
+
References:
|
1039
|
+
1. Adriano Barenco, Artur Ekert, Kalle-Antti Suominen, and Päivi Törmä,
|
1040
|
+
*Approximate Quantum Fourier Transform and Decoherence*,
|
1041
|
+
Physical Review A (1996).
|
1042
|
+
`arXiv:quant-ph/9601018 [quant-ph] <https://arxiv.org/abs/quant-ph/9601018>`_
|
1043
|
+
2. Donny Cheung,
|
1044
|
+
*Improved Bounds for the Approximate QFT* (2004),
|
1045
|
+
`arXiv:quant-ph/0403071 [quant-ph] <https://https://arxiv.org/abs/quant-ph/0403071>`_
|
1046
|
+
"""
|
1047
|
+
|
1048
|
+
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
1049
|
+
"""Run synthesis for the given QFTGate."""
|
1050
|
+
if not isinstance(high_level_object, QFTGate):
|
1051
|
+
raise TranspilerError(
|
1052
|
+
"The synthesis plugin 'qft.line` only applies to objects of type QFTGate."
|
1053
|
+
)
|
1054
|
+
|
1055
|
+
reverse_qubits = options.get("reverse_qubits", False)
|
1056
|
+
approximation_degree = options.get("approximation_degree", 0)
|
1057
|
+
|
1058
|
+
decomposition = synth_qft_line(
|
1059
|
+
num_qubits=high_level_object.num_qubits,
|
1060
|
+
do_swaps=not reverse_qubits,
|
1061
|
+
approximation_degree=approximation_degree,
|
1062
|
+
)
|
1063
|
+
return decomposition
|
1064
|
+
|
1065
|
+
|
890
1066
|
class TokenSwapperSynthesisPermutation(HighLevelSynthesisPlugin):
|
891
1067
|
"""The permutation synthesis plugin based on the token swapper algorithm.
|
892
1068
|
|
@@ -917,7 +1093,6 @@ class TokenSwapperSynthesisPermutation(HighLevelSynthesisPlugin):
|
|
917
1093
|
|
918
1094
|
For more details on the token swapper algorithm, see to the paper:
|
919
1095
|
`arXiv:1902.09102 <https://arxiv.org/abs/1902.09102>`__.
|
920
|
-
|
921
1096
|
"""
|
922
1097
|
|
923
1098
|
def run(self, high_level_object, coupling_map=None, target=None, qubits=None, **options):
|
@@ -698,13 +698,13 @@ class HighLevelSynthesisPluginManager:
|
|
698
698
|
self.plugins_by_op = {}
|
699
699
|
for plugin_name in self.plugins.names():
|
700
700
|
op_name, method_name = plugin_name.split(".")
|
701
|
-
if op_name not in self.plugins_by_op
|
701
|
+
if op_name not in self.plugins_by_op:
|
702
702
|
self.plugins_by_op[op_name] = []
|
703
703
|
self.plugins_by_op[op_name].append(method_name)
|
704
704
|
|
705
705
|
def method_names(self, op_name):
|
706
706
|
"""Returns plugin methods for op_name."""
|
707
|
-
if op_name in self.plugins_by_op
|
707
|
+
if op_name in self.plugins_by_op:
|
708
708
|
return self.plugins_by_op[op_name]
|
709
709
|
else:
|
710
710
|
return []
|
@@ -28,21 +28,9 @@ from itertools import product
|
|
28
28
|
from functools import partial
|
29
29
|
import numpy as np
|
30
30
|
|
31
|
-
from qiskit.
|
32
|
-
from qiskit.
|
33
|
-
from qiskit.
|
34
|
-
from qiskit.transpiler.exceptions import TranspilerError
|
35
|
-
from qiskit.dagcircuit.dagcircuit import DAGCircuit
|
36
|
-
from qiskit.synthesis.one_qubit import one_qubit_decompose
|
37
|
-
from qiskit.transpiler.passes.optimization.optimize_1q_decomposition import _possible_decomposers
|
38
|
-
from qiskit.synthesis.two_qubit.xx_decompose import XXDecomposer, XXEmbodiments
|
39
|
-
from qiskit.synthesis.two_qubit.two_qubit_decompose import (
|
40
|
-
TwoQubitBasisDecomposer,
|
41
|
-
TwoQubitWeylDecomposition,
|
42
|
-
GATE_NAME_MAP,
|
43
|
-
)
|
44
|
-
from qiskit.quantum_info import Operator
|
45
|
-
from qiskit.circuit import ControlFlowOp, Gate, Parameter
|
31
|
+
from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES
|
32
|
+
from qiskit.circuit import Gate, Parameter, CircuitInstruction
|
33
|
+
from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping
|
46
34
|
from qiskit.circuit.library.standard_gates import (
|
47
35
|
iSwapGate,
|
48
36
|
CXGate,
|
@@ -51,14 +39,54 @@ from qiskit.circuit.library.standard_gates import (
|
|
51
39
|
RZXGate,
|
52
40
|
RZZGate,
|
53
41
|
ECRGate,
|
42
|
+
RXGate,
|
43
|
+
SXGate,
|
44
|
+
XGate,
|
45
|
+
RZGate,
|
46
|
+
UGate,
|
47
|
+
PhaseGate,
|
48
|
+
U1Gate,
|
49
|
+
U2Gate,
|
50
|
+
U3Gate,
|
51
|
+
RYGate,
|
52
|
+
RGate,
|
54
53
|
)
|
55
|
-
from qiskit.
|
54
|
+
from qiskit.converters import circuit_to_dag, dag_to_circuit
|
55
|
+
from qiskit.dagcircuit.dagcircuit import DAGCircuit, DAGOpNode
|
56
|
+
from qiskit.exceptions import QiskitError
|
57
|
+
from qiskit.providers.models.backendproperties import BackendProperties
|
58
|
+
from qiskit.quantum_info import Operator
|
59
|
+
from qiskit.synthesis.one_qubit import one_qubit_decompose
|
60
|
+
from qiskit.synthesis.two_qubit.xx_decompose import XXDecomposer, XXEmbodiments
|
61
|
+
from qiskit.synthesis.two_qubit.two_qubit_decompose import (
|
62
|
+
TwoQubitBasisDecomposer,
|
63
|
+
TwoQubitWeylDecomposition,
|
64
|
+
)
|
65
|
+
from qiskit.transpiler.basepasses import TransformationPass
|
66
|
+
from qiskit.transpiler.coupling import CouplingMap
|
67
|
+
from qiskit.transpiler.exceptions import TranspilerError
|
56
68
|
from qiskit.transpiler.passes.optimization.optimize_1q_decomposition import (
|
57
69
|
Optimize1qGatesDecomposition,
|
70
|
+
_possible_decomposers,
|
58
71
|
)
|
59
|
-
from qiskit.
|
60
|
-
from qiskit.
|
61
|
-
|
72
|
+
from qiskit.transpiler.passes.synthesis import plugin
|
73
|
+
from qiskit.transpiler.target import Target
|
74
|
+
|
75
|
+
|
76
|
+
GATE_NAME_MAP = {
|
77
|
+
"cx": CXGate._standard_gate,
|
78
|
+
"rx": RXGate._standard_gate,
|
79
|
+
"sx": SXGate._standard_gate,
|
80
|
+
"x": XGate._standard_gate,
|
81
|
+
"rz": RZGate._standard_gate,
|
82
|
+
"u": UGate._standard_gate,
|
83
|
+
"p": PhaseGate._standard_gate,
|
84
|
+
"u1": U1Gate._standard_gate,
|
85
|
+
"u2": U2Gate._standard_gate,
|
86
|
+
"u3": U3Gate._standard_gate,
|
87
|
+
"ry": RYGate._standard_gate,
|
88
|
+
"r": RGate._standard_gate,
|
89
|
+
}
|
62
90
|
|
63
91
|
|
64
92
|
KAK_GATE_NAMES = {
|
@@ -415,7 +443,7 @@ class UnitarySynthesis(TransformationPass):
|
|
415
443
|
if self.method == "default":
|
416
444
|
# If the method is the default, we only need to evaluate one set of keyword arguments.
|
417
445
|
# To simplify later logic, and avoid cases where static analysis might complain that we
|
418
|
-
# haven't
|
446
|
+
# haven't initialized the "default" handler, we rebind the names so they point to the
|
419
447
|
# same object as the chosen method.
|
420
448
|
default_method = plugin_method
|
421
449
|
default_kwargs = plugin_kwargs
|
@@ -480,7 +508,9 @@ class UnitarySynthesis(TransformationPass):
|
|
480
508
|
self, dag, qubit_indices, plugin_method, plugin_kwargs, default_method, default_kwargs
|
481
509
|
):
|
482
510
|
"""Inner loop for the optimizer, after all DAG-independent set-up has been completed."""
|
483
|
-
for node in dag.op_nodes(
|
511
|
+
for node in dag.op_nodes():
|
512
|
+
if node.name not in CONTROL_FLOW_OP_NAMES:
|
513
|
+
continue
|
484
514
|
node.op = node.op.replace_blocks(
|
485
515
|
[
|
486
516
|
dag_to_circuit(
|
@@ -503,9 +533,9 @@ class UnitarySynthesis(TransformationPass):
|
|
503
533
|
|
504
534
|
out_dag = dag.copy_empty_like()
|
505
535
|
for node in dag.topological_op_nodes():
|
506
|
-
if node.
|
536
|
+
if node.name == "unitary" and len(node.qargs) >= self._min_qubits:
|
507
537
|
synth_dag = None
|
508
|
-
unitary = node.
|
538
|
+
unitary = node.matrix
|
509
539
|
n_qubits = len(node.qargs)
|
510
540
|
if (
|
511
541
|
plugin_method.max_qubits is not None and n_qubits > plugin_method.max_qubits
|
@@ -520,35 +550,42 @@ class UnitarySynthesis(TransformationPass):
|
|
520
550
|
)
|
521
551
|
synth_dag = method.run(unitary, **kwargs)
|
522
552
|
if synth_dag is None:
|
523
|
-
out_dag.
|
553
|
+
out_dag._apply_op_node_back(node)
|
524
554
|
continue
|
525
555
|
if isinstance(synth_dag, DAGCircuit):
|
526
556
|
qubit_map = dict(zip(synth_dag.qubits, node.qargs))
|
527
557
|
for node in synth_dag.topological_op_nodes():
|
528
|
-
|
529
|
-
|
530
|
-
)
|
558
|
+
node.qargs = tuple(qubit_map[x] for x in node.qargs)
|
559
|
+
out_dag._apply_op_node_back(node)
|
531
560
|
out_dag.global_phase += synth_dag.global_phase
|
532
561
|
else:
|
533
562
|
node_list, global_phase, gate = synth_dag
|
534
563
|
qubits = node.qargs
|
564
|
+
user_gate_node = DAGOpNode(gate)
|
535
565
|
for (
|
536
|
-
|
566
|
+
gate,
|
537
567
|
params,
|
538
568
|
qargs,
|
539
569
|
) in node_list:
|
540
|
-
if
|
541
|
-
|
570
|
+
if gate is None:
|
571
|
+
node = DAGOpNode.from_instruction(
|
572
|
+
user_gate_node._to_circuit_instruction().replace(
|
573
|
+
params=user_gate_node.params,
|
574
|
+
qubits=tuple(qubits[x] for x in qargs),
|
575
|
+
),
|
576
|
+
dag=out_dag,
|
577
|
+
)
|
542
578
|
else:
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
579
|
+
node = DAGOpNode.from_instruction(
|
580
|
+
CircuitInstruction.from_standard(
|
581
|
+
gate, tuple(qubits[x] for x in qargs), params
|
582
|
+
),
|
583
|
+
dag=out_dag,
|
584
|
+
)
|
585
|
+
out_dag._apply_op_node_back(node)
|
549
586
|
out_dag.global_phase += global_phase
|
550
587
|
else:
|
551
|
-
out_dag.
|
588
|
+
out_dag._apply_op_node_back(node)
|
552
589
|
return out_dag
|
553
590
|
|
554
591
|
|
@@ -975,8 +1012,8 @@ class DefaultUnitarySynthesis(plugin.UnitarySynthesisPlugin):
|
|
975
1012
|
# if the gates in synthesis are in the opposite direction of the preferred direction
|
976
1013
|
# resynthesize a new operator which is the original conjugated by swaps.
|
977
1014
|
# this new operator is doubly mirrored from the original and is locally equivalent.
|
978
|
-
for
|
979
|
-
if
|
1015
|
+
for gate, _params, qubits in synth_circ:
|
1016
|
+
if gate is None or gate == CXGate._standard_gate:
|
980
1017
|
synth_direction = qubits
|
981
1018
|
if synth_direction is not None and synth_direction != preferred_direction:
|
982
1019
|
# TODO: Avoid using a dag to correct the synthesis direction
|
@@ -1011,5 +1048,8 @@ class DefaultUnitarySynthesis(plugin.UnitarySynthesisPlugin):
|
|
1011
1048
|
flip_bits = out_dag.qubits[::-1]
|
1012
1049
|
for node in synth_circ.topological_op_nodes():
|
1013
1050
|
qubits = tuple(flip_bits[synth_circ.find_bit(x).index] for x in node.qargs)
|
1014
|
-
|
1051
|
+
node = DAGOpNode.from_instruction(
|
1052
|
+
node._to_circuit_instruction().replace(qubits=qubits, params=node.params)
|
1053
|
+
)
|
1054
|
+
out_dag._apply_op_node_back(node)
|
1015
1055
|
return out_dag
|
@@ -12,7 +12,7 @@
|
|
12
12
|
|
13
13
|
"""Check if the gates follow the right direction with respect to the coupling map."""
|
14
14
|
|
15
|
-
from qiskit.circuit import
|
15
|
+
from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES
|
16
16
|
from qiskit.converters import circuit_to_dag
|
17
17
|
from qiskit.transpiler.basepasses import AnalysisPass
|
18
18
|
|
@@ -39,7 +39,7 @@ class CheckGateDirection(AnalysisPass):
|
|
39
39
|
edges = self.coupling_map.get_edges()
|
40
40
|
# Don't include directives to avoid things like barrier, which are assumed always supported.
|
41
41
|
for node in dag.op_nodes(include_directives=False):
|
42
|
-
if
|
42
|
+
if node.name in CONTROL_FLOW_OP_NAMES:
|
43
43
|
for block in node.op.blocks:
|
44
44
|
inner_wire_map = {
|
45
45
|
inner: wire_map[outer] for outer, inner in zip(node.qargs, block.qubits)
|
@@ -57,7 +57,7 @@ class CheckGateDirection(AnalysisPass):
|
|
57
57
|
def _target_visit(self, dag, wire_map):
|
58
58
|
# Don't include directives to avoid things like barrier, which are assumed always supported.
|
59
59
|
for node in dag.op_nodes(include_directives=False):
|
60
|
-
if
|
60
|
+
if node.name in CONTROL_FLOW_OP_NAMES:
|
61
61
|
for block in node.op.blocks:
|
62
62
|
inner_wire_map = {
|
63
63
|
inner: wire_map[outer] for outer, inner in zip(node.qargs, block.qubits)
|
@@ -65,7 +65,7 @@ class CheckGateDirection(AnalysisPass):
|
|
65
65
|
if not self._target_visit(circuit_to_dag(block), inner_wire_map):
|
66
66
|
return False
|
67
67
|
elif len(node.qargs) == 2 and not self.target.instruction_supported(
|
68
|
-
node.
|
68
|
+
node.name, (wire_map[node.qargs[0]], wire_map[node.qargs[1]])
|
69
69
|
):
|
70
70
|
return False
|
71
71
|
return True
|
@@ -14,7 +14,6 @@
|
|
14
14
|
|
15
15
|
from qiskit.transpiler.basepasses import AnalysisPass
|
16
16
|
from qiskit.transpiler.target import Target
|
17
|
-
from qiskit.circuit.controlflow import ControlFlowOp
|
18
17
|
from qiskit.converters import circuit_to_dag
|
19
18
|
|
20
19
|
|
@@ -73,7 +72,7 @@ class CheckMap(AnalysisPass):
|
|
73
72
|
|
74
73
|
def _recurse(self, dag, wire_map) -> bool:
|
75
74
|
for node in dag.op_nodes(include_directives=False):
|
76
|
-
if
|
75
|
+
if node.is_control_flow():
|
77
76
|
for block in node.op.blocks:
|
78
77
|
inner_wire_map = {
|
79
78
|
inner: wire_map[outer] for inner, outer in zip(block.qubits, node.qargs)
|
@@ -85,10 +84,8 @@ class CheckMap(AnalysisPass):
|
|
85
84
|
and not dag.has_calibration_for(node)
|
86
85
|
and (wire_map[node.qargs[0]], wire_map[node.qargs[1]]) not in self.qargs
|
87
86
|
):
|
88
|
-
self.property_set["check_map_msg"] =
|
89
|
-
node.name,
|
90
|
-
wire_map[node.qargs[0]],
|
91
|
-
wire_map[node.qargs[1]],
|
87
|
+
self.property_set["check_map_msg"] = (
|
88
|
+
f"{node.name}({wire_map[node.qargs[0]]}, {wire_map[node.qargs[1]]}) failed"
|
92
89
|
)
|
93
90
|
return False
|
94
91
|
return True
|