qiskit 1.1.2__cp38-abi3-macosx_10_9_universal2.whl → 1.2.0rc1__cp38-abi3-macosx_10_9_universal2.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.abi3.so +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 +1 -1
- 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 +392 -384
- 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 +41 -127
- 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 +32 -24
- qiskit/providers/fake_provider/fake_backend.py +10 -3
- qiskit/providers/fake_provider/fake_openpulse_2q.py +154 -146
- qiskit/providers/fake_provider/fake_openpulse_3q.py +226 -217
- qiskit/providers/fake_provider/fake_qasm_backend.py +5 -1
- qiskit/providers/fake_provider/generic_backend_v2.py +80 -50
- qiskit/providers/models/__init__.py +11 -0
- 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 +578 -481
- 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/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 +14 -16
- 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 +82 -63
- 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 +11 -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 +1 -1
- 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 +11 -11
- 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 +117 -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 +19 -67
- 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 +5 -12
- 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.0rc1.dist-info}/METADATA +26 -26
- {qiskit-1.1.2.dist-info → qiskit-1.2.0rc1.dist-info}/RECORD +340 -338
- {qiskit-1.1.2.dist-info → qiskit-1.2.0rc1.dist-info}/WHEEL +1 -1
- {qiskit-1.1.2.dist-info → qiskit-1.2.0rc1.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.0rc1.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.1.2.dist-info → qiskit-1.2.0rc1.dist-info}/top_level.txt +0 -0
@@ -35,7 +35,7 @@ import logging
|
|
35
35
|
|
36
36
|
import numpy as np
|
37
37
|
|
38
|
-
from qiskit.circuit import QuantumRegister, QuantumCircuit, Gate
|
38
|
+
from qiskit.circuit import QuantumRegister, QuantumCircuit, Gate, CircuitInstruction
|
39
39
|
from qiskit.circuit.library.standard_gates import (
|
40
40
|
CXGate,
|
41
41
|
U3Gate,
|
@@ -60,7 +60,7 @@ from qiskit.utils.deprecation import deprecate_func
|
|
60
60
|
from qiskit._accelerate import two_qubit_decompose
|
61
61
|
|
62
62
|
if TYPE_CHECKING:
|
63
|
-
from qiskit.dagcircuit.dagcircuit import DAGCircuit
|
63
|
+
from qiskit.dagcircuit.dagcircuit import DAGCircuit, DAGOpNode
|
64
64
|
|
65
65
|
logger = logging.getLogger(__name__)
|
66
66
|
|
@@ -116,7 +116,7 @@ def decompose_two_qubit_product_gate(special_unitary_matrix: np.ndarray):
|
|
116
116
|
if deviation > 1.0e-13:
|
117
117
|
raise QiskitError(
|
118
118
|
"decompose_two_qubit_product_gate: decomposition failed: "
|
119
|
-
"deviation too large: {}"
|
119
|
+
f"deviation too large: {deviation}"
|
120
120
|
)
|
121
121
|
|
122
122
|
return L, R, phase
|
@@ -230,13 +230,10 @@ class TwoQubitWeylDecomposition:
|
|
230
230
|
self, *, euler_basis: str | None = None, simplify: bool = False, atol: float = DEFAULT_ATOL
|
231
231
|
) -> QuantumCircuit:
|
232
232
|
"""Returns Weyl decomposition in circuit form."""
|
233
|
-
|
233
|
+
circuit_data = self._inner_decomposition.circuit(
|
234
234
|
euler_basis=euler_basis, simplify=simplify, atol=atol
|
235
235
|
)
|
236
|
-
|
237
|
-
for name, params, qubits in circuit_sequence:
|
238
|
-
getattr(circ, name)(*params, *qubits)
|
239
|
-
return circ
|
236
|
+
return QuantumCircuit._from_circuit_data(circuit_data)
|
240
237
|
|
241
238
|
def actual_fidelity(self, **kwargs) -> float:
|
242
239
|
"""Calculates the actual fidelity of the decomposed circuit to the input unitary."""
|
@@ -641,47 +638,58 @@ class TwoQubitBasisDecomposer:
|
|
641
638
|
QiskitError: if ``pulse_optimize`` is True but we don't know how to do it.
|
642
639
|
"""
|
643
640
|
|
644
|
-
sequence = self._inner_decomposer(
|
645
|
-
np.asarray(unitary, dtype=complex),
|
646
|
-
basis_fidelity,
|
647
|
-
approximate,
|
648
|
-
_num_basis_uses=_num_basis_uses,
|
649
|
-
)
|
650
|
-
q = QuantumRegister(2)
|
651
641
|
if use_dag:
|
652
|
-
from qiskit.dagcircuit.dagcircuit import DAGCircuit
|
642
|
+
from qiskit.dagcircuit.dagcircuit import DAGCircuit, DAGOpNode
|
643
|
+
|
644
|
+
sequence = self._inner_decomposer(
|
645
|
+
np.asarray(unitary, dtype=complex),
|
646
|
+
basis_fidelity,
|
647
|
+
approximate,
|
648
|
+
_num_basis_uses=_num_basis_uses,
|
649
|
+
)
|
650
|
+
q = QuantumRegister(2)
|
653
651
|
|
654
652
|
dag = DAGCircuit()
|
655
653
|
dag.global_phase = sequence.global_phase
|
656
654
|
dag.add_qreg(q)
|
657
|
-
for
|
658
|
-
if
|
655
|
+
for gate, params, qubits in sequence:
|
656
|
+
if gate is None:
|
659
657
|
dag.apply_operation_back(self.gate, tuple(q[x] for x in qubits), check=False)
|
660
658
|
else:
|
661
|
-
|
662
|
-
|
659
|
+
op = CircuitInstruction.from_standard(
|
660
|
+
gate, qubits=tuple(q[x] for x in qubits), params=params
|
661
|
+
)
|
662
|
+
node = DAGOpNode.from_instruction(op, dag=dag)
|
663
|
+
dag._apply_op_node_back(node)
|
663
664
|
return dag
|
664
665
|
else:
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
666
|
+
if getattr(self.gate, "_standard_gate", None):
|
667
|
+
circ_data = self._inner_decomposer.to_circuit(
|
668
|
+
np.asarray(unitary, dtype=complex),
|
669
|
+
self.gate,
|
670
|
+
basis_fidelity,
|
671
|
+
approximate,
|
672
|
+
_num_basis_uses=_num_basis_uses,
|
673
|
+
)
|
674
|
+
return QuantumCircuit._from_circuit_data(circ_data)
|
675
|
+
else:
|
676
|
+
sequence = self._inner_decomposer(
|
677
|
+
np.asarray(unitary, dtype=complex),
|
678
|
+
basis_fidelity,
|
679
|
+
approximate,
|
680
|
+
_num_basis_uses=_num_basis_uses,
|
681
|
+
)
|
682
|
+
q = QuantumRegister(2)
|
683
|
+
circ = QuantumCircuit(q, global_phase=sequence.global_phase)
|
684
|
+
for gate, params, qubits in sequence:
|
685
|
+
if gate is None:
|
686
|
+
circ._append(self.gate, qargs=tuple(q[x] for x in qubits))
|
681
687
|
else:
|
682
|
-
|
683
|
-
|
684
|
-
|
688
|
+
inst = CircuitInstruction.from_standard(
|
689
|
+
gate, qubits=tuple(q[x] for x in qubits), params=params
|
690
|
+
)
|
691
|
+
circ._append(inst)
|
692
|
+
return circ
|
685
693
|
|
686
694
|
def traces(self, target):
|
687
695
|
r"""
|
@@ -691,98 +699,9 @@ class TwoQubitBasisDecomposer:
|
|
691
699
|
return self._inner_decomposer.traces(target._inner_decomposition)
|
692
700
|
|
693
701
|
|
694
|
-
class TwoQubitDecomposeUpToDiagonal:
|
695
|
-
"""
|
696
|
-
Class to decompose two qubit unitaries into the product of a diagonal gate
|
697
|
-
and another unitary gate which can be represented by two CX gates instead of the
|
698
|
-
usual three. This can be used when neighboring gates commute with the diagonal to
|
699
|
-
potentially reduce overall CX count.
|
700
|
-
"""
|
701
|
-
|
702
|
-
def __init__(self):
|
703
|
-
sy = np.array([[0, -1j], [1j, 0]])
|
704
|
-
self.sysy = np.kron(sy, sy)
|
705
|
-
|
706
|
-
def _u4_to_su4(self, u4):
|
707
|
-
phase_factor = np.conj(np.linalg.det(u4) ** (-1 / u4.shape[0]))
|
708
|
-
su4 = u4 / phase_factor
|
709
|
-
return su4, cmath.phase(phase_factor)
|
710
|
-
|
711
|
-
def _gamma(self, mat):
|
712
|
-
"""
|
713
|
-
proposition II.1: this invariant characterizes when two operators in U(4),
|
714
|
-
say u, v, are equivalent up to single qubit gates:
|
715
|
-
|
716
|
-
u ≡ v -> Det(γ(u)) = Det(±(γ(v)))
|
717
|
-
"""
|
718
|
-
sumat, _ = self._u4_to_su4(mat)
|
719
|
-
sysy = self.sysy
|
720
|
-
return sumat @ sysy @ sumat.T @ sysy
|
721
|
-
|
722
|
-
def _cx0_test(self, mat):
|
723
|
-
# proposition III.1: zero cx sufficient
|
724
|
-
gamma = self._gamma(mat)
|
725
|
-
evals = np.linalg.eigvals(gamma)
|
726
|
-
return np.all(np.isclose(evals, np.ones(4)))
|
727
|
-
|
728
|
-
def _cx1_test(self, mat):
|
729
|
-
# proposition III.2: one cx sufficient
|
730
|
-
gamma = self._gamma(mat)
|
731
|
-
evals = np.linalg.eigvals(gamma)
|
732
|
-
uvals, ucnts = np.unique(np.round(evals, 10), return_counts=True)
|
733
|
-
return (
|
734
|
-
len(uvals) == 2
|
735
|
-
and all(ucnts == 2)
|
736
|
-
and all((np.isclose(x, 1j)) or np.isclose(x, -1j) for x in uvals)
|
737
|
-
)
|
738
|
-
|
739
|
-
def _cx2_test(self, mat):
|
740
|
-
# proposition III.3: two cx sufficient
|
741
|
-
gamma = self._gamma(mat)
|
742
|
-
return np.isclose(np.trace(gamma).imag, 0)
|
743
|
-
|
744
|
-
def _real_trace_transform(self, mat):
|
745
|
-
"""
|
746
|
-
Determine diagonal gate such that
|
747
|
-
|
748
|
-
U3 = D U2
|
749
|
-
|
750
|
-
Where U3 is a general two-qubit gate which takes 3 cnots, D is a
|
751
|
-
diagonal gate, and U2 is a gate which takes 2 cnots.
|
752
|
-
"""
|
753
|
-
a1 = (
|
754
|
-
-mat[1, 3] * mat[2, 0]
|
755
|
-
+ mat[1, 2] * mat[2, 1]
|
756
|
-
+ mat[1, 1] * mat[2, 2]
|
757
|
-
- mat[1, 0] * mat[2, 3]
|
758
|
-
)
|
759
|
-
a2 = (
|
760
|
-
mat[0, 3] * mat[3, 0]
|
761
|
-
- mat[0, 2] * mat[3, 1]
|
762
|
-
- mat[0, 1] * mat[3, 2]
|
763
|
-
+ mat[0, 0] * mat[3, 3]
|
764
|
-
)
|
765
|
-
theta = 0 # arbitrary
|
766
|
-
phi = 0 # arbitrary
|
767
|
-
psi = np.arctan2(a1.imag + a2.imag, a1.real - a2.real) - phi
|
768
|
-
diag = np.diag(np.exp(-1j * np.array([theta, phi, psi, -(theta + phi + psi)])))
|
769
|
-
return diag
|
770
|
-
|
771
|
-
def __call__(self, mat):
|
772
|
-
"""do the decomposition"""
|
773
|
-
su4, phase = self._u4_to_su4(mat)
|
774
|
-
real_map = self._real_trace_transform(su4)
|
775
|
-
mapped_su4 = real_map @ su4
|
776
|
-
if not self._cx2_test(mapped_su4):
|
777
|
-
warnings.warn("Unitary decomposition up to diagonal may use an additionl CX gate.")
|
778
|
-
circ = two_qubit_cnot_decompose(mapped_su4)
|
779
|
-
circ.global_phase += phase
|
780
|
-
return real_map.conj(), circ
|
781
|
-
|
782
|
-
|
783
702
|
# This weird duplicated lazy structure is for backwards compatibility; Qiskit has historically
|
784
703
|
# always made ``two_qubit_cnot_decompose`` available publicly immediately on import, but it's quite
|
785
|
-
# expensive to construct, and we want to defer the
|
704
|
+
# expensive to construct, and we want to defer the object's creation until it's actually used. We
|
786
705
|
# only need to pass through the public methods that take `self` as a parameter. Using `__getattr__`
|
787
706
|
# doesn't work because it is only called if the normal resolution methods fail. Using
|
788
707
|
# `__getattribute__` is too messy for a simple one-off use object.
|
@@ -133,7 +133,7 @@ def _get_connectivity(num_qubits: int, connectivity: str) -> dict:
|
|
133
133
|
links = {i: list(range(num_qubits)) for i in range(num_qubits)}
|
134
134
|
|
135
135
|
elif connectivity == "line":
|
136
|
-
# Every qubit is connected to its immediate
|
136
|
+
# Every qubit is connected to its immediate neighbors only.
|
137
137
|
links = {i: [i - 1, i, i + 1] for i in range(1, num_qubits - 1)}
|
138
138
|
|
139
139
|
# first qubit
|
qiskit/synthesis/unitary/qsd.py
CHANGED
@@ -30,6 +30,7 @@ from qiskit.circuit.library.standard_gates import CXGate
|
|
30
30
|
from qiskit.circuit.library.generalized_gates.uc_pauli_rot import UCPauliRotGate, _EPS
|
31
31
|
from qiskit.circuit.library.generalized_gates.ucry import UCRYGate
|
32
32
|
from qiskit.circuit.library.generalized_gates.ucrz import UCRZGate
|
33
|
+
from qiskit._accelerate.two_qubit_decompose import two_qubit_decompose_up_to_diagonal
|
33
34
|
|
34
35
|
|
35
36
|
def qs_decomposition(
|
@@ -253,7 +254,7 @@ def _apply_a2(circ):
|
|
253
254
|
from qiskit.quantum_info import Operator
|
254
255
|
from qiskit.circuit.library.generalized_gates.unitary import UnitaryGate
|
255
256
|
|
256
|
-
decomposer =
|
257
|
+
decomposer = two_qubit_decompose_up_to_diagonal
|
257
258
|
ccirc = transpile(circ, basis_gates=["u", "cx", "qsd2q"], optimization_level=0)
|
258
259
|
ind2q = []
|
259
260
|
# collect 2q instrs
|
@@ -269,13 +270,14 @@ def _apply_a2(circ):
|
|
269
270
|
# rolling over diagonals
|
270
271
|
ind2 = None # lint
|
271
272
|
for ind1, ind2 in zip(ind2q[0:-1:], ind2q[1::]):
|
272
|
-
# get
|
273
|
+
# get neighboring 2q gates separated by controls
|
273
274
|
instr1 = ccirc.data[ind1]
|
274
275
|
mat1 = Operator(instr1.operation).data
|
275
276
|
instr2 = ccirc.data[ind2]
|
276
277
|
mat2 = Operator(instr2.operation).data
|
277
278
|
# rollover
|
278
|
-
dmat,
|
279
|
+
dmat, qc2cx_data = decomposer(mat1)
|
280
|
+
qc2cx = QuantumCircuit._from_circuit_data(qc2cx_data)
|
279
281
|
ccirc.data[ind1] = instr1.replace(operation=qc2cx.to_gate())
|
280
282
|
mat2 = mat2 @ dmat
|
281
283
|
ccirc.data[ind2] = instr2.replace(UnitaryGate(mat2))
|
qiskit/transpiler/__init__.py
CHANGED
@@ -1277,6 +1277,7 @@ from .basepasses import AnalysisPass, TransformationPass
|
|
1277
1277
|
from .coupling import CouplingMap
|
1278
1278
|
from .layout import Layout, TranspileLayout
|
1279
1279
|
from .instruction_durations import InstructionDurations
|
1280
|
+
from .preset_passmanagers import generate_preset_pass_manager
|
1280
1281
|
from .target import Target
|
1281
1282
|
from .target import InstructionProperties
|
1282
1283
|
from .target import QubitProperties
|
qiskit/transpiler/basepasses.py
CHANGED
@@ -87,7 +87,7 @@ class BasePass(GenericPass, metaclass=MetaPass):
|
|
87
87
|
return hash(self) == hash(other)
|
88
88
|
|
89
89
|
@abstractmethod
|
90
|
-
def run(self, dag: DAGCircuit): # pylint:
|
90
|
+
def run(self, dag: DAGCircuit): # pylint:disable=arguments-renamed
|
91
91
|
"""Run a pass on the DAGCircuit. This is implemented by the pass developer.
|
92
92
|
|
93
93
|
Args:
|
qiskit/transpiler/coupling.py
CHANGED
@@ -101,7 +101,7 @@ class CouplingMap:
|
|
101
101
|
raise CouplingError("Physical qubits should be integers.")
|
102
102
|
if physical_qubit in self.physical_qubits:
|
103
103
|
raise CouplingError(
|
104
|
-
"The physical qubit
|
104
|
+
f"The physical qubit {physical_qubit} is already in the coupling graph"
|
105
105
|
)
|
106
106
|
self.graph.add_node(physical_qubit)
|
107
107
|
self._dist_matrix = None # invalidate
|
@@ -188,9 +188,9 @@ class CouplingMap:
|
|
188
188
|
CouplingError: if the qubits do not exist in the CouplingMap
|
189
189
|
"""
|
190
190
|
if physical_qubit1 >= self.size():
|
191
|
-
raise CouplingError("
|
191
|
+
raise CouplingError(f"{physical_qubit1} not in coupling graph")
|
192
192
|
if physical_qubit2 >= self.size():
|
193
|
-
raise CouplingError("
|
193
|
+
raise CouplingError(f"{physical_qubit2} not in coupling graph")
|
194
194
|
self.compute_distance_matrix()
|
195
195
|
res = self._dist_matrix[physical_qubit1, physical_qubit2]
|
196
196
|
if res == math.inf:
|
@@ -15,8 +15,7 @@ from __future__ import annotations
|
|
15
15
|
from typing import Optional, List, Tuple, Union, Iterable
|
16
16
|
|
17
17
|
import qiskit.circuit
|
18
|
-
from qiskit.circuit import Barrier, Delay
|
19
|
-
from qiskit.circuit import Instruction, ParameterExpression
|
18
|
+
from qiskit.circuit import Barrier, Delay, Instruction, ParameterExpression
|
20
19
|
from qiskit.circuit.duration import duration_in_dt
|
21
20
|
from qiskit.providers import Backend
|
22
21
|
from qiskit.transpiler.exceptions import TranspilerError
|
qiskit/transpiler/layout.py
CHANGED
@@ -98,8 +98,8 @@ class Layout:
|
|
98
98
|
virtual = value1
|
99
99
|
else:
|
100
100
|
raise LayoutError(
|
101
|
-
"The map (
|
102
|
-
" or the other way around."
|
101
|
+
f"The map ({type(value1)} -> {type(value2)}) has to be a (Bit -> integer)"
|
102
|
+
" or the other way around."
|
103
103
|
)
|
104
104
|
return virtual, physical
|
105
105
|
|
@@ -137,7 +137,7 @@ class Layout:
|
|
137
137
|
else:
|
138
138
|
raise LayoutError(
|
139
139
|
"The key to remove should be of the form"
|
140
|
-
" Qubit or integer) and
|
140
|
+
f" Qubit or integer) and {type(key)} was provided"
|
141
141
|
)
|
142
142
|
|
143
143
|
def __len__(self):
|
@@ -91,6 +91,7 @@ Optimizations
|
|
91
91
|
ElidePermutations
|
92
92
|
NormalizeRXAngle
|
93
93
|
OptimizeAnnotated
|
94
|
+
Split2QUnitaries
|
94
95
|
|
95
96
|
Calibration
|
96
97
|
=============
|
@@ -244,6 +245,7 @@ from .optimization import OptimizeCliffords
|
|
244
245
|
from .optimization import ElidePermutations
|
245
246
|
from .optimization import NormalizeRXAngle
|
246
247
|
from .optimization import OptimizeAnnotated
|
248
|
+
from .optimization import Split2QUnitaries
|
247
249
|
|
248
250
|
# circuit analysis
|
249
251
|
from .analysis import ResourceEstimation
|
@@ -30,11 +30,12 @@ from qiskit.circuit import (
|
|
30
30
|
QuantumCircuit,
|
31
31
|
ParameterExpression,
|
32
32
|
)
|
33
|
-
from qiskit.dagcircuit import DAGCircuit
|
33
|
+
from qiskit.dagcircuit import DAGCircuit, DAGOpNode
|
34
34
|
from qiskit.converters import circuit_to_dag, dag_to_circuit
|
35
35
|
from qiskit.circuit.equivalence import Key, NodeData
|
36
36
|
from qiskit.transpiler.basepasses import TransformationPass
|
37
37
|
from qiskit.transpiler.exceptions import TranspilerError
|
38
|
+
from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES
|
38
39
|
|
39
40
|
logger = logging.getLogger(__name__)
|
40
41
|
|
@@ -207,7 +208,7 @@ class BasisTranslator(TransformationPass):
|
|
207
208
|
"target basis is not universal or there are additional equivalence rules "
|
208
209
|
"needed in the EquivalenceLibrary being used. For more details on this "
|
209
210
|
"error see: "
|
210
|
-
"https://docs.quantum.ibm.com/api/qiskit/
|
211
|
+
"https://docs.quantum.ibm.com/api/qiskit/qiskit.transpiler.passes."
|
211
212
|
"BasisTranslator#translation-errors"
|
212
213
|
)
|
213
214
|
|
@@ -225,7 +226,7 @@ class BasisTranslator(TransformationPass):
|
|
225
226
|
f"basis: {list(target_basis)}. This likely means the target basis is not universal "
|
226
227
|
"or there are additional equivalence rules needed in the EquivalenceLibrary being "
|
227
228
|
"used. For more details on this error see: "
|
228
|
-
"https://docs.quantum.ibm.com/api/qiskit/
|
229
|
+
"https://docs.quantum.ibm.com/api/qiskit/qiskit.transpiler.passes."
|
229
230
|
"BasisTranslator#translation-errors"
|
230
231
|
)
|
231
232
|
|
@@ -248,72 +249,85 @@ class BasisTranslator(TransformationPass):
|
|
248
249
|
replace_start_time = time.time()
|
249
250
|
|
250
251
|
def apply_translation(dag, wire_map):
|
251
|
-
|
252
|
-
|
252
|
+
is_updated = False
|
253
|
+
out_dag = dag.copy_empty_like()
|
254
|
+
for node in dag.topological_op_nodes():
|
253
255
|
node_qargs = tuple(wire_map[bit] for bit in node.qargs)
|
254
256
|
qubit_set = frozenset(node_qargs)
|
255
257
|
if node.name in target_basis or len(node.qargs) < self._min_qubits:
|
256
|
-
if
|
258
|
+
if node.name in CONTROL_FLOW_OP_NAMES:
|
257
259
|
flow_blocks = []
|
258
260
|
for block in node.op.blocks:
|
259
261
|
dag_block = circuit_to_dag(block)
|
260
|
-
|
262
|
+
updated_dag, is_updated = apply_translation(
|
261
263
|
dag_block,
|
262
264
|
{
|
263
265
|
inner: wire_map[outer]
|
264
266
|
for inner, outer in zip(block.qubits, node.qargs)
|
265
267
|
},
|
266
268
|
)
|
267
|
-
if
|
268
|
-
flow_circ_block = dag_to_circuit(
|
269
|
+
if is_updated:
|
270
|
+
flow_circ_block = dag_to_circuit(updated_dag)
|
269
271
|
else:
|
270
272
|
flow_circ_block = block
|
271
273
|
flow_blocks.append(flow_circ_block)
|
272
274
|
node.op = node.op.replace_blocks(flow_blocks)
|
275
|
+
out_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
|
273
276
|
continue
|
274
277
|
if (
|
275
278
|
node_qargs in self._qargs_with_non_global_operation
|
276
279
|
and node.name in self._qargs_with_non_global_operation[node_qargs]
|
277
280
|
):
|
281
|
+
out_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
|
278
282
|
continue
|
279
283
|
|
280
284
|
if dag.has_calibration_for(node):
|
285
|
+
out_dag.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
|
281
286
|
continue
|
282
287
|
if qubit_set in extra_instr_map:
|
283
|
-
self._replace_node(
|
284
|
-
elif (node.
|
285
|
-
self._replace_node(
|
288
|
+
self._replace_node(out_dag, node, extra_instr_map[qubit_set])
|
289
|
+
elif (node.name, node.num_qubits) in instr_map:
|
290
|
+
self._replace_node(out_dag, node, instr_map)
|
286
291
|
else:
|
287
292
|
raise TranspilerError(f"BasisTranslator did not map {node.name}.")
|
288
|
-
|
289
|
-
return
|
293
|
+
is_updated = True
|
294
|
+
return out_dag, is_updated
|
290
295
|
|
291
|
-
apply_translation(dag, qarg_indices)
|
296
|
+
out_dag, _ = apply_translation(dag, qarg_indices)
|
292
297
|
replace_end_time = time.time()
|
293
298
|
logger.info(
|
294
299
|
"Basis translation instructions replaced in %.3fs.",
|
295
300
|
replace_end_time - replace_start_time,
|
296
301
|
)
|
297
302
|
|
298
|
-
return
|
303
|
+
return out_dag
|
299
304
|
|
300
305
|
def _replace_node(self, dag, node, instr_map):
|
301
|
-
target_params, target_dag = instr_map[node.
|
302
|
-
if len(node.
|
306
|
+
target_params, target_dag = instr_map[node.name, node.num_qubits]
|
307
|
+
if len(node.params) != len(target_params):
|
303
308
|
raise TranspilerError(
|
304
309
|
"Translation num_params not equal to op num_params."
|
305
|
-
"Op: {} {} Translation: {}\n{}"
|
306
|
-
node.op.params, node.op.name, target_params, target_dag
|
307
|
-
)
|
310
|
+
f"Op: {node.params} {node.name} Translation: {target_params}\n{target_dag}"
|
308
311
|
)
|
309
|
-
if node.
|
310
|
-
parameter_map = dict(zip(target_params, node.
|
311
|
-
bound_target_dag = target_dag.copy_empty_like()
|
312
|
+
if node.params:
|
313
|
+
parameter_map = dict(zip(target_params, node.params))
|
312
314
|
for inner_node in target_dag.topological_op_nodes():
|
313
|
-
|
314
|
-
|
315
|
+
new_node = DAGOpNode.from_instruction(
|
316
|
+
inner_node._to_circuit_instruction(),
|
317
|
+
dag=target_dag,
|
318
|
+
)
|
319
|
+
new_node.qargs = tuple(
|
320
|
+
node.qargs[target_dag.find_bit(x).index] for x in inner_node.qargs
|
321
|
+
)
|
322
|
+
new_node.cargs = tuple(
|
323
|
+
node.cargs[target_dag.find_bit(x).index] for x in inner_node.cargs
|
324
|
+
)
|
325
|
+
|
326
|
+
if not new_node.is_standard_gate():
|
327
|
+
new_node.op = new_node.op.copy()
|
328
|
+
if any(isinstance(x, ParameterExpression) for x in inner_node.params):
|
315
329
|
new_params = []
|
316
|
-
for param in
|
330
|
+
for param in new_node.params:
|
317
331
|
if not isinstance(param, ParameterExpression):
|
318
332
|
new_params.append(param)
|
319
333
|
else:
|
@@ -327,10 +341,11 @@ class BasisTranslator(TransformationPass):
|
|
327
341
|
if not new_value.parameters:
|
328
342
|
new_value = new_value.numeric()
|
329
343
|
new_params.append(new_value)
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
344
|
+
new_node.params = new_params
|
345
|
+
if not new_node.is_standard_gate():
|
346
|
+
new_node.op.params = new_params
|
347
|
+
dag._apply_op_node_back(new_node)
|
348
|
+
|
334
349
|
if isinstance(target_dag.global_phase, ParameterExpression):
|
335
350
|
old_phase = target_dag.global_phase
|
336
351
|
bind_dict = {x: parameter_map[x] for x in old_phase.parameters}
|
@@ -338,31 +353,37 @@ class BasisTranslator(TransformationPass):
|
|
338
353
|
new_phase = old_phase
|
339
354
|
for x in bind_dict.items():
|
340
355
|
new_phase = new_phase.assign(*x)
|
341
|
-
|
342
356
|
else:
|
343
357
|
new_phase = old_phase.bind(bind_dict)
|
344
358
|
if not new_phase.parameters:
|
345
359
|
new_phase = new_phase.numeric()
|
346
360
|
if isinstance(new_phase, complex):
|
347
361
|
raise TranspilerError(f"Global phase must be real, but got '{new_phase}'")
|
348
|
-
|
349
|
-
|
350
|
-
bound_target_dag = target_dag
|
351
|
-
|
352
|
-
if len(bound_target_dag.op_nodes()) == 1 and len(
|
353
|
-
bound_target_dag.op_nodes()[0].qargs
|
354
|
-
) == len(node.qargs):
|
355
|
-
dag_op = bound_target_dag.op_nodes()[0].op
|
356
|
-
# dag_op may be the same instance as other ops in the dag,
|
357
|
-
# so if there is a condition, need to copy
|
358
|
-
if getattr(node.op, "condition", None):
|
359
|
-
dag_op = dag_op.copy()
|
360
|
-
dag.substitute_node(node, dag_op, inplace=True)
|
361
|
-
|
362
|
-
if bound_target_dag.global_phase:
|
363
|
-
dag.global_phase += bound_target_dag.global_phase
|
362
|
+
dag.global_phase += new_phase
|
363
|
+
|
364
364
|
else:
|
365
|
-
|
365
|
+
for inner_node in target_dag.topological_op_nodes():
|
366
|
+
new_node = DAGOpNode.from_instruction(
|
367
|
+
inner_node._to_circuit_instruction(),
|
368
|
+
dag=target_dag,
|
369
|
+
)
|
370
|
+
new_node.qargs = tuple(
|
371
|
+
node.qargs[target_dag.find_bit(x).index] for x in inner_node.qargs
|
372
|
+
)
|
373
|
+
new_node.cargs = tuple(
|
374
|
+
node.cargs[target_dag.find_bit(x).index] for x in inner_node.cargs
|
375
|
+
)
|
376
|
+
if not new_node.is_standard_gate:
|
377
|
+
new_node.op = new_node.op.copy()
|
378
|
+
# dag_op may be the same instance as other ops in the dag,
|
379
|
+
# so if there is a condition, need to copy
|
380
|
+
if getattr(node.op, "condition", None):
|
381
|
+
new_node_op = new_node.op.to_mutable()
|
382
|
+
new_node_op.condition = node.op.condition
|
383
|
+
new_node.op = new_node_op
|
384
|
+
dag._apply_op_node_back(new_node)
|
385
|
+
if target_dag.global_phase:
|
386
|
+
dag.global_phase += target_dag.global_phase
|
366
387
|
|
367
388
|
@singledispatchmethod
|
368
389
|
def _extract_basis(self, circuit):
|
@@ -372,8 +393,8 @@ class BasisTranslator(TransformationPass):
|
|
372
393
|
def _(self, dag: DAGCircuit):
|
373
394
|
for node in dag.op_nodes():
|
374
395
|
if not dag.has_calibration_for(node) and len(node.qargs) >= self._min_qubits:
|
375
|
-
yield (node.name, node.
|
376
|
-
if
|
396
|
+
yield (node.name, node.num_qubits)
|
397
|
+
if node.name in CONTROL_FLOW_OP_NAMES:
|
377
398
|
for block in node.op.blocks:
|
378
399
|
yield from self._extract_basis(block)
|
379
400
|
|
@@ -414,10 +435,10 @@ class BasisTranslator(TransformationPass):
|
|
414
435
|
frozenset(qargs).issuperset(incomplete_qargs)
|
415
436
|
for incomplete_qargs in self._qargs_with_non_global_operation
|
416
437
|
):
|
417
|
-
qargs_local_source_basis[frozenset(qargs)].add((node.name, node.
|
438
|
+
qargs_local_source_basis[frozenset(qargs)].add((node.name, node.num_qubits))
|
418
439
|
else:
|
419
|
-
source_basis.add((node.name, node.
|
420
|
-
if
|
440
|
+
source_basis.add((node.name, node.num_qubits))
|
441
|
+
if node.name in CONTROL_FLOW_OP_NAMES:
|
421
442
|
for block in node.op.blocks:
|
422
443
|
block_dag = circuit_to_dag(block)
|
423
444
|
source_basis, qargs_local_source_basis = self._extract_basis_target(
|
@@ -468,7 +489,7 @@ class BasisSearchVisitor(rustworkx.visit.DijkstraVisitor):
|
|
468
489
|
score,
|
469
490
|
)
|
470
491
|
self._basis_transforms.append((gate.name, gate.num_qubits, rule.params, rule.circuit))
|
471
|
-
# we can stop the search if we have found all gates in the original
|
492
|
+
# we can stop the search if we have found all gates in the original circuit.
|
472
493
|
if not self._source_gates_remain:
|
473
494
|
# if we start from source gates and apply `basis_transforms` in reverse order, we'll end
|
474
495
|
# up with gates in the target basis. Note though that `basis_transforms` may include
|
@@ -512,7 +533,7 @@ class BasisSearchVisitor(rustworkx.visit.DijkstraVisitor):
|
|
512
533
|
|
513
534
|
cost_tot = 0
|
514
535
|
for instruction in edge_data.rule.circuit:
|
515
|
-
key = Key(name=instruction.
|
536
|
+
key = Key(name=instruction.name, num_qubits=len(instruction.qubits))
|
516
537
|
cost_tot += self._opt_cost_map[key]
|
517
538
|
|
518
539
|
return cost_tot - self._opt_cost_map[edge_data.source]
|
@@ -550,7 +571,7 @@ def _basis_search(equiv_lib, source_basis, target_basis):
|
|
550
571
|
if not source_basis:
|
551
572
|
return []
|
552
573
|
|
553
|
-
# This is only
|
574
|
+
# This is only necessary since gates in target basis are currently reported by
|
554
575
|
# their names and we need to have in addition the number of qubits they act on.
|
555
576
|
target_basis_keys = [key for key in equiv_lib.keys() if key.name in target_basis]
|
556
577
|
|
@@ -630,7 +651,7 @@ def _compose_transforms(basis_transforms, source_basis, source_dag):
|
|
630
651
|
doomed_nodes = [
|
631
652
|
node
|
632
653
|
for node in dag.op_nodes()
|
633
|
-
if (node.
|
654
|
+
if (node.name, node.num_qubits) == (gate_name, gate_num_qubits)
|
634
655
|
]
|
635
656
|
|
636
657
|
if doomed_nodes and logger.isEnabledFor(logging.DEBUG):
|
@@ -644,9 +665,7 @@ def _compose_transforms(basis_transforms, source_basis, source_dag):
|
|
644
665
|
|
645
666
|
for node in doomed_nodes:
|
646
667
|
|
647
|
-
replacement = equiv.assign_parameters(
|
648
|
-
dict(zip_longest(equiv_params, node.op.params))
|
649
|
-
)
|
668
|
+
replacement = equiv.assign_parameters(dict(zip_longest(equiv_params, node.params)))
|
650
669
|
|
651
670
|
replacement_dag = circuit_to_dag(replacement)
|
652
671
|
|
@@ -668,8 +687,8 @@ def _get_example_gates(source_dag):
|
|
668
687
|
def recurse(dag, example_gates=None):
|
669
688
|
example_gates = example_gates or {}
|
670
689
|
for node in dag.op_nodes():
|
671
|
-
example_gates[(node.
|
672
|
-
if
|
690
|
+
example_gates[(node.name, node.num_qubits)] = node
|
691
|
+
if node.name in CONTROL_FLOW_OP_NAMES:
|
673
692
|
for block in node.op.blocks:
|
674
693
|
example_gates = recurse(circuit_to_dag(block), example_gates)
|
675
694
|
return example_gates
|