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
qiskit/dagcircuit/dagcircuit.py
CHANGED
@@ -54,6 +54,8 @@ from qiskit.dagcircuit.exceptions import DAGCircuitError
|
|
54
54
|
from qiskit.dagcircuit.dagnode import DAGNode, DAGOpNode, DAGInNode, DAGOutNode
|
55
55
|
from qiskit.circuit.bit import Bit
|
56
56
|
from qiskit.pulse import Schedule
|
57
|
+
from qiskit._accelerate.euler_one_qubit_decomposer import collect_1q_runs_filter
|
58
|
+
from qiskit._accelerate.convert_2q_block_matrix import collect_2q_blocks_filter
|
57
59
|
|
58
60
|
BitLocations = namedtuple("BitLocations", ("index", "registers"))
|
59
61
|
# The allowable arguments to :meth:`DAGCircuit.copy_empty_like`'s ``vars_mode``.
|
@@ -271,7 +273,7 @@ class DAGCircuit:
|
|
271
273
|
|
272
274
|
duplicate_qubits = set(self.qubits).intersection(qubits)
|
273
275
|
if duplicate_qubits:
|
274
|
-
raise DAGCircuitError("duplicate qubits
|
276
|
+
raise DAGCircuitError(f"duplicate qubits {duplicate_qubits}")
|
275
277
|
|
276
278
|
for qubit in qubits:
|
277
279
|
self.qubits.append(qubit)
|
@@ -285,7 +287,7 @@ class DAGCircuit:
|
|
285
287
|
|
286
288
|
duplicate_clbits = set(self.clbits).intersection(clbits)
|
287
289
|
if duplicate_clbits:
|
288
|
-
raise DAGCircuitError("duplicate clbits
|
290
|
+
raise DAGCircuitError(f"duplicate clbits {duplicate_clbits}")
|
289
291
|
|
290
292
|
for clbit in clbits:
|
291
293
|
self.clbits.append(clbit)
|
@@ -297,7 +299,7 @@ class DAGCircuit:
|
|
297
299
|
if not isinstance(qreg, QuantumRegister):
|
298
300
|
raise DAGCircuitError("not a QuantumRegister instance.")
|
299
301
|
if qreg.name in self.qregs:
|
300
|
-
raise DAGCircuitError("duplicate register
|
302
|
+
raise DAGCircuitError(f"duplicate register {qreg.name}")
|
301
303
|
self.qregs[qreg.name] = qreg
|
302
304
|
existing_qubits = set(self.qubits)
|
303
305
|
for j in range(qreg.size):
|
@@ -315,7 +317,7 @@ class DAGCircuit:
|
|
315
317
|
if not isinstance(creg, ClassicalRegister):
|
316
318
|
raise DAGCircuitError("not a ClassicalRegister instance.")
|
317
319
|
if creg.name in self.cregs:
|
318
|
-
raise DAGCircuitError("duplicate register
|
320
|
+
raise DAGCircuitError(f"duplicate register {creg.name}")
|
319
321
|
self.cregs[creg.name] = creg
|
320
322
|
existing_clbits = set(self.clbits)
|
321
323
|
for j in range(creg.size):
|
@@ -451,17 +453,17 @@ class DAGCircuit:
|
|
451
453
|
"""
|
452
454
|
if any(not isinstance(clbit, Clbit) for clbit in clbits):
|
453
455
|
raise DAGCircuitError(
|
454
|
-
"clbits not of type Clbit:
|
456
|
+
f"clbits not of type Clbit: {[b for b in clbits if not isinstance(b, Clbit)]}"
|
455
457
|
)
|
456
458
|
|
457
459
|
clbits = set(clbits)
|
458
460
|
unknown_clbits = clbits.difference(self.clbits)
|
459
461
|
if unknown_clbits:
|
460
|
-
raise DAGCircuitError("clbits not in circuit:
|
462
|
+
raise DAGCircuitError(f"clbits not in circuit: {unknown_clbits}")
|
461
463
|
|
462
464
|
busy_clbits = {bit for bit in clbits if not self._is_wire_idle(bit)}
|
463
465
|
if busy_clbits:
|
464
|
-
raise DAGCircuitError("clbits not idle:
|
466
|
+
raise DAGCircuitError(f"clbits not idle: {busy_clbits}")
|
465
467
|
|
466
468
|
# remove any references to bits
|
467
469
|
cregs_to_remove = {creg for creg in self.cregs.values() if not clbits.isdisjoint(creg)}
|
@@ -487,13 +489,13 @@ class DAGCircuit:
|
|
487
489
|
"""
|
488
490
|
if any(not isinstance(creg, ClassicalRegister) for creg in cregs):
|
489
491
|
raise DAGCircuitError(
|
490
|
-
"cregs not of type ClassicalRegister:
|
491
|
-
|
492
|
+
"cregs not of type ClassicalRegister: "
|
493
|
+
f"{[r for r in cregs if not isinstance(r, ClassicalRegister)]}"
|
492
494
|
)
|
493
495
|
|
494
496
|
unknown_cregs = set(cregs).difference(self.cregs.values())
|
495
497
|
if unknown_cregs:
|
496
|
-
raise DAGCircuitError("cregs not in circuit:
|
498
|
+
raise DAGCircuitError(f"cregs not in circuit: {unknown_cregs}")
|
497
499
|
|
498
500
|
for creg in cregs:
|
499
501
|
del self.cregs[creg.name]
|
@@ -517,17 +519,17 @@ class DAGCircuit:
|
|
517
519
|
"""
|
518
520
|
if any(not isinstance(qubit, Qubit) for qubit in qubits):
|
519
521
|
raise DAGCircuitError(
|
520
|
-
"qubits not of type Qubit:
|
522
|
+
f"qubits not of type Qubit: {[b for b in qubits if not isinstance(b, Qubit)]}"
|
521
523
|
)
|
522
524
|
|
523
525
|
qubits = set(qubits)
|
524
526
|
unknown_qubits = qubits.difference(self.qubits)
|
525
527
|
if unknown_qubits:
|
526
|
-
raise DAGCircuitError("qubits not in circuit:
|
528
|
+
raise DAGCircuitError(f"qubits not in circuit: {unknown_qubits}")
|
527
529
|
|
528
530
|
busy_qubits = {bit for bit in qubits if not self._is_wire_idle(bit)}
|
529
531
|
if busy_qubits:
|
530
|
-
raise DAGCircuitError("qubits not idle:
|
532
|
+
raise DAGCircuitError(f"qubits not idle: {busy_qubits}")
|
531
533
|
|
532
534
|
# remove any references to bits
|
533
535
|
qregs_to_remove = {qreg for qreg in self.qregs.values() if not qubits.isdisjoint(qreg)}
|
@@ -553,13 +555,13 @@ class DAGCircuit:
|
|
553
555
|
"""
|
554
556
|
if any(not isinstance(qreg, QuantumRegister) for qreg in qregs):
|
555
557
|
raise DAGCircuitError(
|
556
|
-
"qregs not of type QuantumRegister:
|
557
|
-
|
558
|
+
f"qregs not of type QuantumRegister: "
|
559
|
+
f"{[r for r in qregs if not isinstance(r, QuantumRegister)]}"
|
558
560
|
)
|
559
561
|
|
560
562
|
unknown_qregs = set(qregs).difference(self.qregs.values())
|
561
563
|
if unknown_qregs:
|
562
|
-
raise DAGCircuitError("qregs not in circuit:
|
564
|
+
raise DAGCircuitError(f"qregs not in circuit: {unknown_qregs}")
|
563
565
|
|
564
566
|
for qreg in qregs:
|
565
567
|
del self.qregs[qreg.name]
|
@@ -581,13 +583,13 @@ class DAGCircuit:
|
|
581
583
|
DAGCircuitError: the wire is not in the circuit.
|
582
584
|
"""
|
583
585
|
if wire not in self._wires:
|
584
|
-
raise DAGCircuitError("wire
|
586
|
+
raise DAGCircuitError(f"wire {wire} not in circuit")
|
585
587
|
|
586
588
|
try:
|
587
589
|
child = next(self.successors(self.input_map[wire]))
|
588
590
|
except StopIteration as e:
|
589
591
|
raise DAGCircuitError(
|
590
|
-
"Invalid dagcircuit input node
|
592
|
+
f"Invalid dagcircuit input node {self.input_map[wire]} has no output"
|
591
593
|
) from e
|
592
594
|
return child is self.output_map[wire]
|
593
595
|
|
@@ -642,17 +644,17 @@ class DAGCircuit:
|
|
642
644
|
if wire not in amap:
|
643
645
|
raise DAGCircuitError(f"wire {wire} not found in {amap}")
|
644
646
|
|
645
|
-
def _increment_op(self,
|
646
|
-
if
|
647
|
-
self._op_names[
|
647
|
+
def _increment_op(self, op_name):
|
648
|
+
if op_name in self._op_names:
|
649
|
+
self._op_names[op_name] += 1
|
648
650
|
else:
|
649
|
-
self._op_names[
|
651
|
+
self._op_names[op_name] = 1
|
650
652
|
|
651
|
-
def _decrement_op(self,
|
652
|
-
if self._op_names[
|
653
|
-
del self._op_names[
|
653
|
+
def _decrement_op(self, op_name):
|
654
|
+
if self._op_names[op_name] == 1:
|
655
|
+
del self._op_names[op_name]
|
654
656
|
else:
|
655
|
-
self._op_names[
|
657
|
+
self._op_names[op_name] -= 1
|
656
658
|
|
657
659
|
def copy_empty_like(self, *, vars_mode: _VarsMode = "alike"):
|
658
660
|
"""Return a copy of self with the same structure but empty.
|
@@ -717,6 +719,34 @@ class DAGCircuit:
|
|
717
719
|
|
718
720
|
return target_dag
|
719
721
|
|
722
|
+
def _apply_op_node_back(self, node: DAGOpNode, *, check: bool = False):
|
723
|
+
additional = ()
|
724
|
+
if _may_have_additional_wires(node):
|
725
|
+
# This is the slow path; most of the time, this won't happen.
|
726
|
+
additional = set(_additional_wires(node.op)).difference(node.cargs)
|
727
|
+
|
728
|
+
if check:
|
729
|
+
self._check_condition(node.name, node.condition)
|
730
|
+
self._check_wires(node.qargs, self.output_map)
|
731
|
+
self._check_wires(node.cargs, self.output_map)
|
732
|
+
self._check_wires(additional, self.output_map)
|
733
|
+
|
734
|
+
node._node_id = self._multi_graph.add_node(node)
|
735
|
+
self._increment_op(node.name)
|
736
|
+
|
737
|
+
# Add new in-edges from predecessors of the output nodes to the
|
738
|
+
# operation node while deleting the old in-edges of the output nodes
|
739
|
+
# and adding new edges from the operation node to each output node
|
740
|
+
self._multi_graph.insert_node_on_in_edges_multiple(
|
741
|
+
node._node_id,
|
742
|
+
[
|
743
|
+
self.output_map[bit]._node_id
|
744
|
+
for bits in (node.qargs, node.cargs, additional)
|
745
|
+
for bit in bits
|
746
|
+
],
|
747
|
+
)
|
748
|
+
return node
|
749
|
+
|
720
750
|
def apply_operation_back(
|
721
751
|
self,
|
722
752
|
op: Operation,
|
@@ -743,32 +773,9 @@ class DAGCircuit:
|
|
743
773
|
DAGCircuitError: if a leaf node is connected to multiple outputs
|
744
774
|
|
745
775
|
"""
|
746
|
-
|
747
|
-
|
748
|
-
additional = ()
|
749
|
-
|
750
|
-
if _may_have_additional_wires(op):
|
751
|
-
# This is the slow path; most of the time, this won't happen.
|
752
|
-
additional = set(_additional_wires(op)).difference(cargs)
|
753
|
-
|
754
|
-
if check:
|
755
|
-
self._check_condition(op.name, getattr(op, "condition", None))
|
756
|
-
self._check_wires(qargs, self.output_map)
|
757
|
-
self._check_wires(cargs, self.output_map)
|
758
|
-
self._check_wires(additional, self.output_map)
|
759
|
-
|
760
|
-
node = DAGOpNode(op=op, qargs=qargs, cargs=cargs, dag=self)
|
761
|
-
node._node_id = self._multi_graph.add_node(node)
|
762
|
-
self._increment_op(op)
|
763
|
-
|
764
|
-
# Add new in-edges from predecessors of the output nodes to the
|
765
|
-
# operation node while deleting the old in-edges of the output nodes
|
766
|
-
# and adding new edges from the operation node to each output node
|
767
|
-
self._multi_graph.insert_node_on_in_edges_multiple(
|
768
|
-
node._node_id,
|
769
|
-
[self.output_map[bit]._node_id for bits in (qargs, cargs, additional) for bit in bits],
|
776
|
+
return self._apply_op_node_back(
|
777
|
+
DAGOpNode(op=op, qargs=tuple(qargs), cargs=tuple(cargs), dag=self), check=check
|
770
778
|
)
|
771
|
-
return node
|
772
779
|
|
773
780
|
def apply_operation_front(
|
774
781
|
self,
|
@@ -799,26 +806,30 @@ class DAGCircuit:
|
|
799
806
|
cargs = tuple(cargs)
|
800
807
|
additional = ()
|
801
808
|
|
802
|
-
|
809
|
+
node = DAGOpNode(op=op, qargs=qargs, cargs=cargs, dag=self)
|
810
|
+
if _may_have_additional_wires(node):
|
803
811
|
# This is the slow path; most of the time, this won't happen.
|
804
|
-
additional = set(_additional_wires(op)).difference(cargs)
|
812
|
+
additional = set(_additional_wires(node.op)).difference(cargs)
|
805
813
|
|
806
814
|
if check:
|
807
|
-
self._check_condition(
|
808
|
-
self._check_wires(qargs, self.output_map)
|
809
|
-
self._check_wires(cargs, self.output_map)
|
815
|
+
self._check_condition(node.name, node.condition)
|
816
|
+
self._check_wires(node.qargs, self.output_map)
|
817
|
+
self._check_wires(node.cargs, self.output_map)
|
810
818
|
self._check_wires(additional, self.output_map)
|
811
819
|
|
812
|
-
node = DAGOpNode(op=op, qargs=qargs, cargs=cargs, dag=self)
|
813
820
|
node._node_id = self._multi_graph.add_node(node)
|
814
|
-
self._increment_op(
|
821
|
+
self._increment_op(node.name)
|
815
822
|
|
816
823
|
# Add new out-edges to successors of the input nodes from the
|
817
824
|
# operation node while deleting the old out-edges of the input nodes
|
818
825
|
# and adding new edges to the operation node from each input node
|
819
826
|
self._multi_graph.insert_node_on_out_edges_multiple(
|
820
827
|
node._node_id,
|
821
|
-
[
|
828
|
+
[
|
829
|
+
self.input_map[bit]._node_id
|
830
|
+
for bits in (node.qargs, node.cargs, additional)
|
831
|
+
for bit in bits
|
832
|
+
],
|
822
833
|
)
|
823
834
|
return node
|
824
835
|
|
@@ -950,12 +961,11 @@ class DAGCircuit:
|
|
950
961
|
# the mapped wire should already exist
|
951
962
|
if m_wire not in dag.output_map:
|
952
963
|
raise DAGCircuitError(
|
953
|
-
"wire
|
964
|
+
f"wire {m_wire.register.name}[{m_wire.index}] not in self"
|
954
965
|
)
|
955
966
|
if nd.wire not in other._wires:
|
956
967
|
raise DAGCircuitError(
|
957
|
-
"inconsistent wire type for
|
958
|
-
% (nd.register.name, nd.wire.index)
|
968
|
+
f"inconsistent wire type for {nd.register.name}[{nd.wire.index}] in other"
|
959
969
|
)
|
960
970
|
# If it's a Var wire, we already checked that it exists in the destination.
|
961
971
|
elif isinstance(nd, DAGOutNode):
|
@@ -964,17 +974,28 @@ class DAGCircuit:
|
|
964
974
|
elif isinstance(nd, DAGOpNode):
|
965
975
|
m_qargs = [edge_map.get(x, x) for x in nd.qargs]
|
966
976
|
m_cargs = [edge_map.get(x, x) for x in nd.cargs]
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
977
|
+
inst = nd._to_circuit_instruction(deepcopy=True)
|
978
|
+
m_op = None
|
979
|
+
if inst.condition is not None:
|
980
|
+
if inst.is_control_flow():
|
981
|
+
m_op = inst.operation
|
982
|
+
m_op.condition = variable_mapper.map_condition(
|
983
|
+
inst.condition, allow_reorder=True
|
984
|
+
)
|
971
985
|
else:
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
986
|
+
m_op = inst.operation.c_if(
|
987
|
+
*variable_mapper.map_condition(inst.condition, allow_reorder=True)
|
988
|
+
)
|
989
|
+
elif inst.is_control_flow() and isinstance(inst.operation, SwitchCaseOp):
|
990
|
+
m_op = inst.operation
|
991
|
+
m_op.target = variable_mapper.map_target(m_op.target)
|
992
|
+
if m_op is None:
|
993
|
+
inst = inst.replace(qubits=m_qargs, clbits=m_cargs)
|
994
|
+
else:
|
995
|
+
inst = inst.replace(operation=m_op, qubits=m_qargs, clbits=m_cargs)
|
996
|
+
dag._apply_op_node_back(DAGOpNode.from_instruction(inst), check=False)
|
976
997
|
else:
|
977
|
-
raise DAGCircuitError("bad node type
|
998
|
+
raise DAGCircuitError(f"bad node type {type(nd)}")
|
978
999
|
|
979
1000
|
if not inplace:
|
980
1001
|
return dag
|
@@ -1327,9 +1348,9 @@ class DAGCircuit:
|
|
1327
1348
|
for nd in node_block:
|
1328
1349
|
block_qargs |= set(nd.qargs)
|
1329
1350
|
block_cargs |= set(nd.cargs)
|
1330
|
-
if (condition := getattr(nd
|
1351
|
+
if (condition := getattr(nd, "condition", None)) is not None:
|
1331
1352
|
block_cargs.update(condition_resources(condition).clbits)
|
1332
|
-
elif isinstance(nd.op, SwitchCaseOp):
|
1353
|
+
elif nd.name in CONTROL_FLOW_OP_NAMES and isinstance(nd.op, SwitchCaseOp):
|
1333
1354
|
if isinstance(nd.op.target, Clbit):
|
1334
1355
|
block_cargs.add(nd.op.target)
|
1335
1356
|
elif isinstance(nd.op.target, ClassicalRegister):
|
@@ -1359,10 +1380,10 @@ class DAGCircuit:
|
|
1359
1380
|
"Replacing the specified node block would introduce a cycle"
|
1360
1381
|
) from ex
|
1361
1382
|
|
1362
|
-
self._increment_op(op)
|
1383
|
+
self._increment_op(op.name)
|
1363
1384
|
|
1364
1385
|
for nd in node_block:
|
1365
|
-
self._decrement_op(nd.
|
1386
|
+
self._decrement_op(nd.name)
|
1366
1387
|
|
1367
1388
|
return new_node
|
1368
1389
|
|
@@ -1411,7 +1432,7 @@ class DAGCircuit:
|
|
1411
1432
|
node_wire_order = list(node.qargs) + list(node.cargs)
|
1412
1433
|
# If we're not propagating it, the number of wires in the input DAG should include the
|
1413
1434
|
# condition as well.
|
1414
|
-
if not propagate_condition and _may_have_additional_wires(node
|
1435
|
+
if not propagate_condition and _may_have_additional_wires(node):
|
1415
1436
|
node_wire_order += [
|
1416
1437
|
wire for wire in _additional_wires(node.op) if wire not in node_cargs
|
1417
1438
|
]
|
@@ -1433,7 +1454,7 @@ class DAGCircuit:
|
|
1433
1454
|
raise DAGCircuitError(
|
1434
1455
|
f"bit mapping invalid: {input_dag_wire} and {our_wire} are different bit types"
|
1435
1456
|
)
|
1436
|
-
if _may_have_additional_wires(node
|
1457
|
+
if _may_have_additional_wires(node):
|
1437
1458
|
node_vars = {var for var in _additional_wires(node.op) if isinstance(var, expr.Var)}
|
1438
1459
|
else:
|
1439
1460
|
node_vars = set()
|
@@ -1450,11 +1471,7 @@ class DAGCircuit:
|
|
1450
1471
|
reverse_wire_map = {b: a for a, b in wire_map.items()}
|
1451
1472
|
# It doesn't make sense to try and propagate a condition from a control-flow op; a
|
1452
1473
|
# replacement for the control-flow op should implement the operation completely.
|
1453
|
-
if (
|
1454
|
-
propagate_condition
|
1455
|
-
and not isinstance(node.op, ControlFlowOp)
|
1456
|
-
and (op_condition := getattr(node.op, "condition", None)) is not None
|
1457
|
-
):
|
1474
|
+
if propagate_condition and not node.is_control_flow() and node.condition is not None:
|
1458
1475
|
in_dag = input_dag.copy_empty_like()
|
1459
1476
|
# The remapping of `condition` below is still using the old code that assumes a 2-tuple.
|
1460
1477
|
# This is because this remapping code only makes sense in the case of non-control-flow
|
@@ -1463,7 +1480,7 @@ class DAGCircuit:
|
|
1463
1480
|
# in favour of the new-style conditional blocks. The extra logic in here to add
|
1464
1481
|
# additional wires into the map as necessary would hugely complicate matters if we tried
|
1465
1482
|
# to abstract it out into the `VariableMapper` used elsewhere.
|
1466
|
-
target, value =
|
1483
|
+
target, value = node.condition
|
1467
1484
|
if isinstance(target, Clbit):
|
1468
1485
|
new_target = reverse_wire_map.get(target, Clbit())
|
1469
1486
|
if new_target not in wire_map:
|
@@ -1533,7 +1550,7 @@ class DAGCircuit:
|
|
1533
1550
|
)[0]
|
1534
1551
|
self._multi_graph.add_edge(pred._node_id, succ._node_id, contracted_var)
|
1535
1552
|
|
1536
|
-
#
|
1553
|
+
# Exclude any nodes from in_dag that are not a DAGOpNode or are on
|
1537
1554
|
# wires outside the set specified by the wires kwarg
|
1538
1555
|
def filter_fn(node):
|
1539
1556
|
if not isinstance(node, DAGOpNode):
|
@@ -1573,7 +1590,7 @@ class DAGCircuit:
|
|
1573
1590
|
node_map = self._multi_graph.substitute_node_with_subgraph(
|
1574
1591
|
node._node_id, in_dag._multi_graph, edge_map_fn, filter_fn, edge_weight_map
|
1575
1592
|
)
|
1576
|
-
self._decrement_op(node.
|
1593
|
+
self._decrement_op(node.name)
|
1577
1594
|
|
1578
1595
|
variable_mapper = _classical_resource_map.VariableMapper(
|
1579
1596
|
self.cregs.values(), wire_map, add_register=self.add_creg
|
@@ -1583,28 +1600,34 @@ class DAGCircuit:
|
|
1583
1600
|
for old_node_index, new_node_index in node_map.items():
|
1584
1601
|
# update node attributes
|
1585
1602
|
old_node = in_dag._multi_graph[old_node_index]
|
1586
|
-
|
1603
|
+
m_op = None
|
1604
|
+
if not old_node.is_standard_gate() and isinstance(old_node.op, SwitchCaseOp):
|
1587
1605
|
m_op = SwitchCaseOp(
|
1588
1606
|
variable_mapper.map_target(old_node.op.target),
|
1589
1607
|
old_node.op.cases_specifier(),
|
1590
1608
|
label=old_node.op.label,
|
1591
1609
|
)
|
1592
|
-
elif
|
1610
|
+
elif old_node.condition is not None:
|
1593
1611
|
m_op = old_node.op
|
1594
|
-
if
|
1612
|
+
if old_node.is_control_flow():
|
1613
|
+
m_op.condition = variable_mapper.map_condition(m_op.condition)
|
1614
|
+
else:
|
1595
1615
|
new_condition = variable_mapper.map_condition(m_op.condition)
|
1596
1616
|
if new_condition is not None:
|
1597
1617
|
m_op = m_op.c_if(*new_condition)
|
1598
|
-
else:
|
1599
|
-
m_op.condition = variable_mapper.map_condition(m_op.condition)
|
1600
|
-
else:
|
1601
|
-
m_op = old_node.op
|
1602
1618
|
m_qargs = [wire_map[x] for x in old_node.qargs]
|
1603
1619
|
m_cargs = [wire_map[x] for x in old_node.cargs]
|
1604
|
-
|
1620
|
+
old_instruction = old_node._to_circuit_instruction()
|
1621
|
+
if m_op is None:
|
1622
|
+
new_instruction = old_instruction.replace(qubits=m_qargs, clbits=m_cargs)
|
1623
|
+
else:
|
1624
|
+
new_instruction = old_instruction.replace(
|
1625
|
+
operation=m_op, qubits=m_qargs, clbits=m_cargs
|
1626
|
+
)
|
1627
|
+
new_node = DAGOpNode.from_instruction(new_instruction)
|
1605
1628
|
new_node._node_id = new_node_index
|
1606
1629
|
self._multi_graph[new_node_index] = new_node
|
1607
|
-
self._increment_op(new_node.
|
1630
|
+
self._increment_op(new_node.name)
|
1608
1631
|
|
1609
1632
|
return {k: self._multi_graph[v] for k, v in node_map.items()}
|
1610
1633
|
|
@@ -1623,7 +1646,7 @@ class DAGCircuit:
|
|
1623
1646
|
be used.
|
1624
1647
|
propagate_condition (bool): Optional, default True. If True, a condition on the
|
1625
1648
|
``node`` to be replaced will be applied to the new ``op``. This is the legacy
|
1626
|
-
|
1649
|
+
behavior. If either node is a control-flow operation, this will be ignored. If
|
1627
1650
|
the ``op`` already has a condition, :exc:`.DAGCircuitError` is raised.
|
1628
1651
|
|
1629
1652
|
Returns:
|
@@ -1639,10 +1662,10 @@ class DAGCircuit:
|
|
1639
1662
|
|
1640
1663
|
if node.op.num_qubits != op.num_qubits or node.op.num_clbits != op.num_clbits:
|
1641
1664
|
raise DAGCircuitError(
|
1642
|
-
"Cannot replace node of width ({} qubits,
|
1643
|
-
"
|
1644
|
-
|
1645
|
-
)
|
1665
|
+
f"Cannot replace node of width ({node.op.num_qubits} qubits, "
|
1666
|
+
f"{node.op.num_clbits} clbits) with "
|
1667
|
+
f"operation of mismatched width ({op.num_qubits} qubits, "
|
1668
|
+
f"{op.num_clbits} clbits)."
|
1646
1669
|
)
|
1647
1670
|
|
1648
1671
|
# This might include wires that are inherent to the node, like in its `condition` or
|
@@ -1676,17 +1699,17 @@ class DAGCircuit:
|
|
1676
1699
|
|
1677
1700
|
if inplace:
|
1678
1701
|
if op.name != node.op.name:
|
1679
|
-
self._increment_op(op)
|
1680
|
-
self._decrement_op(node.
|
1702
|
+
self._increment_op(op.name)
|
1703
|
+
self._decrement_op(node.name)
|
1681
1704
|
node.op = op
|
1682
1705
|
return node
|
1683
1706
|
|
1684
1707
|
new_node = copy.copy(node)
|
1685
1708
|
new_node.op = op
|
1686
1709
|
self._multi_graph[node._node_id] = new_node
|
1687
|
-
if op.name != node.
|
1688
|
-
self._increment_op(op)
|
1689
|
-
self._decrement_op(node.
|
1710
|
+
if op.name != node.name:
|
1711
|
+
self._increment_op(op.name)
|
1712
|
+
self._decrement_op(node.name)
|
1690
1713
|
return new_node
|
1691
1714
|
|
1692
1715
|
def separable_circuits(
|
@@ -1830,11 +1853,18 @@ class DAGCircuit:
|
|
1830
1853
|
list[DAGOpNode]: the list of node ids containing the given op.
|
1831
1854
|
"""
|
1832
1855
|
nodes = []
|
1856
|
+
filter_is_nonstandard = getattr(op, "_standard_gate", None) is None
|
1833
1857
|
for node in self._multi_graph.nodes():
|
1834
1858
|
if isinstance(node, DAGOpNode):
|
1835
|
-
if not include_directives and
|
1859
|
+
if not include_directives and node.is_directive():
|
1836
1860
|
continue
|
1837
|
-
if op is None or
|
1861
|
+
if op is None or (
|
1862
|
+
# This middle catch is to avoid Python-space operation creation for most uses of
|
1863
|
+
# `op`; we're usually just looking for control-flow ops, and standard gates
|
1864
|
+
# aren't control-flow ops.
|
1865
|
+
not (filter_is_nonstandard and node.is_standard_gate())
|
1866
|
+
and isinstance(node.op, op)
|
1867
|
+
):
|
1838
1868
|
nodes.append(node)
|
1839
1869
|
return nodes
|
1840
1870
|
|
@@ -1854,7 +1884,7 @@ class DAGCircuit:
|
|
1854
1884
|
"""Get the set of "op" nodes with the given name."""
|
1855
1885
|
named_nodes = []
|
1856
1886
|
for node in self._multi_graph.nodes():
|
1857
|
-
if isinstance(node, DAGOpNode) and node.
|
1887
|
+
if isinstance(node, DAGOpNode) and node.name in names:
|
1858
1888
|
named_nodes.append(node)
|
1859
1889
|
return named_nodes
|
1860
1890
|
|
@@ -1960,14 +1990,12 @@ class DAGCircuit:
|
|
1960
1990
|
"""
|
1961
1991
|
if not isinstance(node, DAGOpNode):
|
1962
1992
|
raise DAGCircuitError(
|
1963
|
-
'The method remove_op_node only works on DAGOpNodes. A "
|
1964
|
-
"node type was wrongly provided."
|
1993
|
+
f'The method remove_op_node only works on DAGOpNodes. A "{type(node)}" '
|
1994
|
+
"node type was wrongly provided."
|
1965
1995
|
)
|
1966
1996
|
|
1967
|
-
self._multi_graph.
|
1968
|
-
|
1969
|
-
)
|
1970
|
-
self._decrement_op(node.op)
|
1997
|
+
self._multi_graph.remove_node_retain_edges_by_id(node._node_id)
|
1998
|
+
self._decrement_op(node.name)
|
1971
1999
|
|
1972
2000
|
def remove_ancestors_of(self, node):
|
1973
2001
|
"""Remove all of the ancestor operation nodes of node."""
|
@@ -2062,14 +2090,11 @@ class DAGCircuit:
|
|
2062
2090
|
new_layer = self.copy_empty_like(vars_mode=vars_mode)
|
2063
2091
|
|
2064
2092
|
for node in op_nodes:
|
2065
|
-
|
2066
|
-
new_layer.apply_operation_back(node.op, node.qargs, node.cargs, check=False)
|
2093
|
+
new_layer._apply_op_node_back(node, check=False)
|
2067
2094
|
|
2068
2095
|
# The quantum registers that have an operation in this layer.
|
2069
2096
|
support_list = [
|
2070
|
-
op_node.qargs
|
2071
|
-
for op_node in new_layer.op_nodes()
|
2072
|
-
if not getattr(op_node.op, "_directive", False)
|
2097
|
+
op_node.qargs for op_node in new_layer.op_nodes() if not op_node.is_directive()
|
2073
2098
|
]
|
2074
2099
|
|
2075
2100
|
yield {"graph": new_layer, "partition": support_list}
|
@@ -2121,56 +2146,25 @@ class DAGCircuit:
|
|
2121
2146
|
"""
|
2122
2147
|
|
2123
2148
|
def filter_fn(node):
|
2124
|
-
return (
|
2125
|
-
isinstance(node, DAGOpNode)
|
2126
|
-
and node.op.name in namelist
|
2127
|
-
and getattr(node.op, "condition", None) is None
|
2128
|
-
)
|
2149
|
+
return isinstance(node, DAGOpNode) and node.name in namelist and node.condition is None
|
2129
2150
|
|
2130
2151
|
group_list = rx.collect_runs(self._multi_graph, filter_fn)
|
2131
2152
|
return {tuple(x) for x in group_list}
|
2132
2153
|
|
2133
2154
|
def collect_1q_runs(self) -> list[list[DAGOpNode]]:
|
2134
2155
|
"""Return a set of non-conditional runs of 1q "op" nodes."""
|
2135
|
-
|
2136
|
-
def filter_fn(node):
|
2137
|
-
return (
|
2138
|
-
isinstance(node, DAGOpNode)
|
2139
|
-
and len(node.qargs) == 1
|
2140
|
-
and len(node.cargs) == 0
|
2141
|
-
and isinstance(node.op, Gate)
|
2142
|
-
and hasattr(node.op, "__array__")
|
2143
|
-
and getattr(node.op, "condition", None) is None
|
2144
|
-
and not node.op.is_parameterized()
|
2145
|
-
)
|
2146
|
-
|
2147
|
-
return rx.collect_runs(self._multi_graph, filter_fn)
|
2156
|
+
return rx.collect_runs(self._multi_graph, collect_1q_runs_filter)
|
2148
2157
|
|
2149
2158
|
def collect_2q_runs(self):
|
2150
2159
|
"""Return a set of non-conditional runs of 2q "op" nodes."""
|
2151
2160
|
|
2152
|
-
to_qid = {}
|
2153
|
-
for i, qubit in enumerate(self.qubits):
|
2154
|
-
to_qid[qubit] = i
|
2155
|
-
|
2156
|
-
def filter_fn(node):
|
2157
|
-
if isinstance(node, DAGOpNode):
|
2158
|
-
return (
|
2159
|
-
isinstance(node.op, Gate)
|
2160
|
-
and len(node.qargs) <= 2
|
2161
|
-
and not getattr(node.op, "condition", None)
|
2162
|
-
and not node.op.is_parameterized()
|
2163
|
-
)
|
2164
|
-
else:
|
2165
|
-
return None
|
2166
|
-
|
2167
2161
|
def color_fn(edge):
|
2168
2162
|
if isinstance(edge, Qubit):
|
2169
|
-
return
|
2163
|
+
return self.find_bit(edge).index
|
2170
2164
|
else:
|
2171
2165
|
return None
|
2172
2166
|
|
2173
|
-
return rx.collect_bicolor_runs(self._multi_graph,
|
2167
|
+
return rx.collect_bicolor_runs(self._multi_graph, collect_2q_blocks_filter, color_fn)
|
2174
2168
|
|
2175
2169
|
def nodes_on_wire(self, wire, only_ops=False):
|
2176
2170
|
"""
|
@@ -2189,7 +2183,7 @@ class DAGCircuit:
|
|
2189
2183
|
current_node = self.input_map.get(wire, None)
|
2190
2184
|
|
2191
2185
|
if not current_node:
|
2192
|
-
raise DAGCircuitError("The given wire
|
2186
|
+
raise DAGCircuitError(f"The given wire {str(wire)} is not present in the circuit")
|
2193
2187
|
|
2194
2188
|
more_nodes = True
|
2195
2189
|
while more_nodes:
|
@@ -2272,36 +2266,44 @@ class DAGCircuit:
|
|
2272
2266
|
output_node = self.output_map.get(qubit, None)
|
2273
2267
|
if not output_node:
|
2274
2268
|
raise DAGCircuitError(f"Qubit {qubit} is not part of this circuit.")
|
2275
|
-
# Add the qubit to the causal cone.
|
2276
|
-
qubits_to_check = {qubit}
|
2277
|
-
# Add predecessors of output node to the queue.
|
2278
|
-
queue = deque(self.predecessors(output_node))
|
2279
2269
|
|
2280
|
-
|
2270
|
+
qubits_in_cone = {qubit}
|
2271
|
+
queue = deque(self.quantum_predecessors(output_node))
|
2272
|
+
|
2273
|
+
# The processed_non_directive_nodes stores the set of processed non-directive nodes.
|
2274
|
+
# This is an optimization to avoid considering the same non-directive node multiple
|
2275
|
+
# times when reached from different paths.
|
2276
|
+
# The directive nodes (such as barriers or measures) are trickier since when processing
|
2277
|
+
# them we only add their predecessors that intersect qubits_in_cone. Hence, directive
|
2278
|
+
# nodes have to be considered multiple times.
|
2279
|
+
processed_non_directive_nodes = set()
|
2280
|
+
|
2281
2281
|
while queue:
|
2282
|
-
# Pop first element.
|
2283
2282
|
node_to_check = queue.popleft()
|
2284
|
-
|
2283
|
+
|
2285
2284
|
if isinstance(node_to_check, DAGOpNode):
|
2286
|
-
#
|
2287
|
-
|
2288
|
-
#
|
2289
|
-
if (
|
2290
|
-
|
2291
|
-
|
2292
|
-
|
2293
|
-
|
2294
|
-
|
2295
|
-
|
2296
|
-
|
2297
|
-
|
2298
|
-
|
2299
|
-
|
2300
|
-
|
2301
|
-
|
2302
|
-
|
2303
|
-
|
2304
|
-
|
2285
|
+
# If the operation is not a directive (in particular not a barrier nor a measure),
|
2286
|
+
# we do not do anything if it was already processed. Otherwise, we add its qubits
|
2287
|
+
# to qubits_in_cone, and append its predecessors to queue.
|
2288
|
+
if not getattr(node_to_check.op, "_directive"):
|
2289
|
+
if node_to_check in processed_non_directive_nodes:
|
2290
|
+
continue
|
2291
|
+
qubits_in_cone = qubits_in_cone.union(set(node_to_check.qargs))
|
2292
|
+
processed_non_directive_nodes.add(node_to_check)
|
2293
|
+
for pred in self.quantum_predecessors(node_to_check):
|
2294
|
+
if isinstance(pred, DAGOpNode):
|
2295
|
+
queue.append(pred)
|
2296
|
+
else:
|
2297
|
+
# Directives (such as barriers and measures) may be defined over all the qubits,
|
2298
|
+
# yet not all of these qubits should be considered in the causal cone. So we
|
2299
|
+
# only add those predecessors that have qubits in common with qubits_in_cone.
|
2300
|
+
for pred in self.quantum_predecessors(node_to_check):
|
2301
|
+
if isinstance(pred, DAGOpNode) and not qubits_in_cone.isdisjoint(
|
2302
|
+
set(pred.qargs)
|
2303
|
+
):
|
2304
|
+
queue.append(pred)
|
2305
|
+
|
2306
|
+
return qubits_in_cone
|
2305
2307
|
|
2306
2308
|
def properties(self):
|
2307
2309
|
"""Return a dictionary of circuit properties."""
|
@@ -2359,24 +2361,25 @@ class _DAGVarInfo:
|
|
2359
2361
|
self.out_node = out_node
|
2360
2362
|
|
2361
2363
|
|
2362
|
-
def _may_have_additional_wires(
|
2363
|
-
"""Return whether a given :class:`.
|
2364
|
-
locations within
|
2365
|
-
_will_ access memory inherently, but a ``
|
2364
|
+
def _may_have_additional_wires(node) -> bool:
|
2365
|
+
"""Return whether a given :class:`.DAGOpNode` may contain references to additional wires
|
2366
|
+
locations within its :class:`.Operation`. If this is ``True``, it doesn't necessarily mean
|
2367
|
+
that the operation _will_ access memory inherently, but a ``False`` return guarantees that it
|
2368
|
+
won't.
|
2366
2369
|
|
2367
2370
|
The memory might be classical bits or classical variables, such as a control-flow operation or a
|
2368
2371
|
store.
|
2369
2372
|
|
2370
2373
|
Args:
|
2371
|
-
operation (qiskit.
|
2374
|
+
operation (qiskit.dagcircuit.DAGOpNode): the operation to check.
|
2372
2375
|
"""
|
2373
2376
|
# This is separate to `_additional_wires` because most of the time there won't be any extra
|
2374
2377
|
# wires beyond the explicit `qargs` and `cargs` so we want a fast path to be able to skip
|
2375
2378
|
# creating and testing a generator for emptiness.
|
2376
2379
|
#
|
2377
2380
|
# If updating this, you most likely also need to update `_additional_wires`.
|
2378
|
-
return
|
2379
|
-
|
2381
|
+
return node.condition is not None or (
|
2382
|
+
not node.is_standard_gate() and isinstance(node.op, (ControlFlowOp, Store))
|
2380
2383
|
)
|
2381
2384
|
|
2382
2385
|
|