qiskit 1.4.2__cp39-abi3-macosx_11_0_arm64.whl → 2.0.0__cp39-abi3-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qiskit/VERSION.txt +1 -1
- qiskit/__init__.py +3 -9
- qiskit/_accelerate.abi3.so +0 -0
- qiskit/circuit/__init__.py +35 -10
- qiskit/circuit/{add_control.py → _add_control.py} +32 -12
- qiskit/circuit/_classical_resource_map.py +5 -3
- qiskit/circuit/barrier.py +3 -7
- qiskit/circuit/classical/expr/__init__.py +31 -3
- qiskit/circuit/classical/expr/constructors.py +236 -28
- qiskit/circuit/classical/expr/expr.py +104 -3
- qiskit/circuit/classical/expr/visitors.py +75 -0
- qiskit/circuit/classical/types/__init__.py +12 -8
- qiskit/circuit/classical/types/ordering.py +14 -7
- qiskit/circuit/classical/types/types.py +36 -0
- qiskit/circuit/commutation_checker.py +34 -7
- qiskit/circuit/controlflow/__init__.py +32 -1
- qiskit/circuit/controlflow/_builder_utils.py +9 -5
- qiskit/circuit/controlflow/box.py +163 -0
- qiskit/circuit/controlflow/break_loop.py +1 -1
- qiskit/circuit/controlflow/builder.py +139 -39
- qiskit/circuit/controlflow/continue_loop.py +1 -3
- qiskit/circuit/controlflow/control_flow.py +10 -0
- qiskit/circuit/controlflow/for_loop.py +2 -1
- qiskit/circuit/controlflow/if_else.py +3 -16
- qiskit/circuit/controlflow/switch_case.py +2 -8
- qiskit/circuit/controlflow/while_loop.py +2 -7
- qiskit/circuit/controlledgate.py +2 -4
- qiskit/circuit/delay.py +40 -11
- qiskit/circuit/duration.py +0 -15
- qiskit/circuit/gate.py +2 -4
- qiskit/circuit/instruction.py +2 -141
- qiskit/circuit/instructionset.py +7 -54
- qiskit/circuit/library/__init__.py +469 -154
- qiskit/circuit/library/arithmetic/__init__.py +16 -10
- qiskit/circuit/library/arithmetic/adders/cdkm_ripple_carry_adder.py +1 -1
- qiskit/circuit/library/arithmetic/adders/draper_qft_adder.py +2 -2
- qiskit/circuit/library/arithmetic/adders/vbe_ripple_carry_adder.py +1 -1
- qiskit/circuit/library/arithmetic/exact_reciprocal.py +64 -21
- qiskit/circuit/library/arithmetic/integer_comparator.py +37 -80
- qiskit/circuit/library/arithmetic/linear_amplitude_function.py +169 -2
- qiskit/circuit/library/arithmetic/linear_pauli_rotations.py +59 -5
- qiskit/circuit/library/arithmetic/piecewise_chebyshev.py +154 -6
- qiskit/circuit/library/arithmetic/piecewise_linear_pauli_rotations.py +114 -4
- qiskit/circuit/library/arithmetic/piecewise_polynomial_pauli_rotations.py +191 -15
- qiskit/circuit/library/arithmetic/polynomial_pauli_rotations.py +93 -39
- qiskit/circuit/library/arithmetic/quadratic_form.py +168 -2
- qiskit/circuit/library/arithmetic/weighted_adder.py +73 -1
- qiskit/circuit/library/bit_flip_oracle.py +130 -0
- qiskit/circuit/library/blueprintcircuit.py +52 -16
- qiskit/circuit/library/data_preparation/initializer.py +1 -1
- qiskit/circuit/library/data_preparation/pauli_feature_map.py +4 -4
- qiskit/circuit/library/data_preparation/state_preparation.py +1 -1
- qiskit/circuit/library/generalized_gates/gms.py +1 -1
- qiskit/circuit/library/generalized_gates/isometry.py +1 -1
- qiskit/circuit/library/generalized_gates/pauli.py +1 -2
- qiskit/circuit/library/generalized_gates/uc.py +97 -7
- qiskit/circuit/library/generalized_gates/uc_pauli_rot.py +1 -1
- qiskit/circuit/library/generalized_gates/unitary.py +4 -2
- qiskit/circuit/library/graph_state.py +1 -0
- qiskit/circuit/library/hamiltonian_gate.py +1 -1
- qiskit/circuit/library/n_local/evolved_operator_ansatz.py +1 -1
- qiskit/circuit/library/n_local/n_local.py +1 -1
- qiskit/circuit/library/n_local/qaoa_ansatz.py +1 -1
- qiskit/circuit/library/overlap.py +2 -2
- qiskit/circuit/library/pauli_evolution.py +39 -24
- qiskit/circuit/library/phase_oracle.py +130 -51
- qiskit/circuit/library/standard_gates/__init__.py +0 -1
- qiskit/circuit/library/standard_gates/dcx.py +3 -4
- qiskit/circuit/library/standard_gates/ecr.py +3 -4
- qiskit/circuit/library/standard_gates/global_phase.py +5 -6
- qiskit/circuit/library/standard_gates/h.py +4 -9
- qiskit/circuit/library/standard_gates/i.py +2 -2
- qiskit/circuit/library/standard_gates/iswap.py +3 -4
- qiskit/circuit/library/standard_gates/p.py +15 -34
- qiskit/circuit/library/standard_gates/r.py +7 -10
- qiskit/circuit/library/standard_gates/rx.py +5 -15
- qiskit/circuit/library/standard_gates/rxx.py +3 -6
- qiskit/circuit/library/standard_gates/ry.py +5 -17
- qiskit/circuit/library/standard_gates/ryy.py +3 -6
- qiskit/circuit/library/standard_gates/rz.py +5 -17
- qiskit/circuit/library/standard_gates/rzx.py +3 -6
- qiskit/circuit/library/standard_gates/rzz.py +3 -6
- qiskit/circuit/library/standard_gates/s.py +6 -15
- qiskit/circuit/library/standard_gates/swap.py +4 -11
- qiskit/circuit/library/standard_gates/sx.py +7 -12
- qiskit/circuit/library/standard_gates/t.py +6 -7
- qiskit/circuit/library/standard_gates/u.py +2 -10
- qiskit/circuit/library/standard_gates/u1.py +5 -16
- qiskit/circuit/library/standard_gates/u2.py +2 -6
- qiskit/circuit/library/standard_gates/u3.py +3 -11
- qiskit/circuit/library/standard_gates/x.py +14 -62
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +2 -5
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +2 -5
- qiskit/circuit/library/standard_gates/y.py +4 -9
- qiskit/circuit/library/standard_gates/z.py +5 -15
- qiskit/circuit/measure.py +11 -2
- qiskit/circuit/parameterexpression.py +7 -1
- qiskit/circuit/quantumcircuit.py +890 -564
- qiskit/circuit/random/utils.py +12 -6
- qiskit/circuit/reset.py +5 -2
- qiskit/circuit/singleton.py +5 -11
- qiskit/circuit/store.py +0 -8
- qiskit/compiler/__init__.py +1 -7
- qiskit/compiler/transpiler.py +38 -196
- qiskit/converters/circuit_to_dag.py +6 -4
- qiskit/converters/circuit_to_dagdependency.py +0 -2
- qiskit/converters/circuit_to_dagdependency_v2.py +0 -1
- qiskit/converters/circuit_to_gate.py +1 -1
- qiskit/converters/circuit_to_instruction.py +16 -29
- qiskit/converters/dag_to_circuit.py +7 -8
- qiskit/converters/dag_to_dagdependency.py +0 -1
- qiskit/converters/dag_to_dagdependency_v2.py +0 -1
- qiskit/converters/dagdependency_to_circuit.py +0 -6
- qiskit/converters/dagdependency_to_dag.py +0 -6
- qiskit/dagcircuit/collect_blocks.py +32 -20
- qiskit/dagcircuit/dagdependency.py +3 -37
- qiskit/dagcircuit/dagdependency_v2.py +5 -82
- qiskit/dagcircuit/dagnode.py +14 -2
- qiskit/passmanager/__init__.py +24 -6
- qiskit/passmanager/passmanager.py +26 -24
- qiskit/primitives/__init__.py +44 -35
- qiskit/primitives/backend_estimator_v2.py +102 -23
- qiskit/primitives/backend_sampler_v2.py +5 -20
- qiskit/primitives/base/__init__.py +4 -4
- qiskit/primitives/base/base_estimator.py +77 -82
- qiskit/primitives/base/base_primitive_job.py +2 -2
- qiskit/primitives/base/{base_primitive.py → base_primitive_v1.py} +1 -1
- qiskit/primitives/base/{base_result.py → base_result_v1.py} +1 -1
- qiskit/primitives/base/base_sampler.py +52 -60
- qiskit/primitives/base/{estimator_result.py → estimator_result_v1.py} +2 -2
- qiskit/primitives/base/{sampler_result.py → sampler_result_v1.py} +2 -2
- qiskit/primitives/base/{validation.py → validation_v1.py} +34 -15
- qiskit/primitives/containers/bindings_array.py +3 -1
- qiskit/primitives/containers/bit_array.py +23 -0
- qiskit/primitives/containers/data_bin.py +3 -1
- qiskit/primitives/containers/observables_array.py +19 -2
- qiskit/primitives/statevector_sampler.py +6 -8
- qiskit/primitives/utils.py +14 -189
- qiskit/providers/__init__.py +4 -130
- qiskit/providers/backend.py +11 -314
- qiskit/providers/basic_provider/__init__.py +3 -1
- qiskit/providers/basic_provider/basic_provider.py +29 -9
- qiskit/providers/basic_provider/basic_simulator.py +158 -298
- qiskit/providers/exceptions.py +0 -33
- qiskit/providers/fake_provider/__init__.py +0 -37
- qiskit/providers/fake_provider/generic_backend_v2.py +32 -693
- qiskit/qasm2/__init__.py +21 -6
- qiskit/qasm2/export.py +2 -10
- qiskit/qasm2/parse.py +11 -25
- qiskit/qasm3/__init__.py +5 -1
- qiskit/qasm3/ast.py +44 -0
- qiskit/qasm3/exporter.py +65 -27
- qiskit/qasm3/printer.py +35 -4
- qiskit/qpy/__init__.py +162 -19
- qiskit/qpy/binary_io/__init__.py +0 -1
- qiskit/qpy/binary_io/circuits.py +98 -130
- qiskit/qpy/binary_io/schedules.py +69 -439
- qiskit/qpy/binary_io/value.py +154 -31
- qiskit/qpy/common.py +10 -7
- qiskit/qpy/formats.py +41 -0
- qiskit/qpy/interface.py +34 -81
- qiskit/qpy/type_keys.py +58 -221
- qiskit/quantum_info/analysis/distance.py +3 -1
- qiskit/quantum_info/operators/dihedral/dihedral.py +3 -1
- qiskit/quantum_info/operators/operator.py +6 -2
- qiskit/quantum_info/operators/symplectic/clifford.py +3 -1
- qiskit/quantum_info/operators/symplectic/pauli.py +4 -2
- qiskit/quantum_info/operators/symplectic/pauli_list.py +17 -5
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +40 -6
- qiskit/quantum_info/states/densitymatrix.py +16 -6
- qiskit/quantum_info/states/stabilizerstate.py +35 -4
- qiskit/quantum_info/states/statevector.py +16 -6
- qiskit/result/__init__.py +5 -17
- qiskit/result/models.py +18 -11
- qiskit/result/result.py +38 -134
- qiskit/result/sampled_expval.py +1 -2
- qiskit/result/utils.py +3 -4
- qiskit/synthesis/__init__.py +21 -1
- qiskit/synthesis/arithmetic/__init__.py +3 -1
- qiskit/synthesis/arithmetic/adders/cdkm_ripple_carry_adder.py +1 -1
- qiskit/synthesis/arithmetic/adders/draper_qft_adder.py +1 -1
- qiskit/synthesis/arithmetic/adders/vbe_ripple_carry_adder.py +2 -2
- qiskit/{providers/fake_provider/backends_v1/fake_20q → synthesis/arithmetic/comparators}/__init__.py +4 -6
- qiskit/synthesis/arithmetic/comparators/compare_2s.py +112 -0
- qiskit/synthesis/arithmetic/comparators/compare_greedy.py +66 -0
- qiskit/synthesis/arithmetic/multipliers/hrs_cumulative_multiplier.py +1 -1
- qiskit/synthesis/arithmetic/multipliers/rg_qft_multiplier.py +1 -1
- qiskit/synthesis/arithmetic/weighted_sum.py +155 -0
- qiskit/{result/mitigation → synthesis/boolean}/__init__.py +2 -2
- qiskit/synthesis/boolean/boolean_expression.py +231 -0
- qiskit/synthesis/boolean/boolean_expression_synth.py +124 -0
- qiskit/synthesis/boolean/boolean_expression_visitor.py +96 -0
- qiskit/synthesis/evolution/lie_trotter.py +10 -7
- qiskit/synthesis/evolution/product_formula.py +44 -35
- qiskit/synthesis/evolution/qdrift.py +17 -24
- qiskit/synthesis/evolution/suzuki_trotter.py +20 -27
- qiskit/synthesis/linear/linear_depth_lnn.py +6 -221
- qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py +4 -205
- qiskit/synthesis/multi_controlled/__init__.py +1 -0
- qiskit/synthesis/multi_controlled/mcx_synthesis.py +5 -2
- qiskit/synthesis/multi_controlled/multi_control_rotation_gates.py +206 -0
- qiskit/synthesis/one_qubit/one_qubit_decompose.py +1 -1
- qiskit/synthesis/two_qubit/__init__.py +1 -0
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +28 -145
- qiskit/transpiler/__init__.py +32 -232
- qiskit/transpiler/basepasses.py +20 -51
- qiskit/transpiler/layout.py +1 -1
- qiskit/transpiler/passes/__init__.py +4 -40
- qiskit/transpiler/passes/basis/basis_translator.py +5 -4
- qiskit/transpiler/passes/basis/decompose.py +1 -15
- qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -5
- qiskit/transpiler/passes/basis/unroll_custom_definitions.py +3 -2
- qiskit/transpiler/passes/layout/apply_layout.py +4 -0
- qiskit/transpiler/passes/layout/dense_layout.py +2 -39
- qiskit/transpiler/passes/layout/full_ancilla_allocation.py +3 -4
- qiskit/transpiler/passes/layout/sabre_layout.py +7 -3
- qiskit/transpiler/passes/layout/vf2_layout.py +2 -20
- qiskit/transpiler/passes/layout/vf2_post_layout.py +60 -125
- qiskit/transpiler/passes/layout/vf2_utils.py +2 -26
- qiskit/transpiler/passes/optimization/__init__.py +2 -3
- qiskit/transpiler/passes/optimization/collect_and_collapse.py +2 -0
- qiskit/transpiler/passes/optimization/collect_cliffords.py +5 -0
- qiskit/transpiler/passes/optimization/collect_linear_functions.py +5 -0
- qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +16 -1
- qiskit/transpiler/passes/optimization/commutation_analysis.py +3 -3
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +41 -19
- qiskit/transpiler/passes/optimization/contract_idle_wires_in_control_flow.py +104 -0
- qiskit/transpiler/passes/optimization/light_cone.py +135 -0
- qiskit/transpiler/passes/optimization/optimize_1q_commutation.py +0 -1
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +18 -22
- qiskit/transpiler/passes/optimization/optimize_annotated.py +3 -2
- qiskit/transpiler/passes/optimization/remove_identity_equiv.py +6 -4
- qiskit/transpiler/passes/optimization/reset_after_measure_simplification.py +5 -2
- qiskit/transpiler/passes/optimization/split_2q_unitaries.py +26 -3
- qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +1 -0
- qiskit/transpiler/passes/routing/__init__.py +0 -1
- qiskit/transpiler/passes/routing/commuting_2q_gate_routing/commuting_2q_gate_router.py +3 -1
- qiskit/transpiler/passes/routing/sabre_swap.py +14 -6
- qiskit/transpiler/passes/routing/star_prerouting.py +1 -1
- qiskit/transpiler/passes/scheduling/__init__.py +1 -7
- qiskit/transpiler/passes/scheduling/alignments/__init__.py +2 -4
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +1 -9
- qiskit/transpiler/passes/scheduling/alignments/reschedule.py +17 -16
- qiskit/transpiler/passes/scheduling/padding/base_padding.py +32 -4
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +25 -63
- qiskit/transpiler/passes/scheduling/padding/pad_delay.py +12 -4
- qiskit/transpiler/passes/scheduling/scheduling/alap.py +5 -39
- qiskit/transpiler/passes/scheduling/scheduling/asap.py +4 -35
- qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +10 -16
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +134 -62
- qiskit/transpiler/passes/synthesis/default_unitary_synth_plugin.py +653 -0
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +176 -601
- qiskit/transpiler/passes/synthesis/hls_plugins.py +294 -1
- qiskit/transpiler/passes/synthesis/plugin.py +4 -0
- qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +16 -10
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +34 -697
- qiskit/transpiler/passes/utils/__init__.py +0 -1
- qiskit/transpiler/passes/utils/check_gate_direction.py +13 -5
- qiskit/transpiler/passes/utils/control_flow.py +2 -6
- qiskit/transpiler/passes/utils/gate_direction.py +7 -0
- qiskit/transpiler/passes/utils/remove_final_measurements.py +40 -33
- qiskit/transpiler/passmanager.py +13 -0
- qiskit/transpiler/passmanager_config.py +5 -81
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +225 -344
- qiskit/transpiler/preset_passmanagers/common.py +140 -167
- qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py +107 -322
- qiskit/transpiler/preset_passmanagers/level0.py +2 -11
- qiskit/transpiler/preset_passmanagers/level1.py +2 -14
- qiskit/transpiler/preset_passmanagers/level2.py +2 -12
- qiskit/transpiler/preset_passmanagers/level3.py +2 -11
- qiskit/transpiler/preset_passmanagers/plugin.py +5 -3
- qiskit/transpiler/target.py +78 -524
- qiskit/user_config.py +8 -4
- qiskit/utils/__init__.py +13 -12
- qiskit/utils/deprecation.py +4 -112
- qiskit/utils/optionals.py +11 -4
- qiskit/utils/parallel.py +214 -87
- qiskit/utils/units.py +4 -1
- qiskit/visualization/__init__.py +3 -7
- qiskit/visualization/array.py +4 -1
- qiskit/visualization/bloch.py +1 -1
- qiskit/visualization/circuit/_utils.py +19 -19
- qiskit/visualization/circuit/circuit_visualization.py +11 -4
- qiskit/visualization/circuit/matplotlib.py +13 -23
- qiskit/visualization/circuit/text.py +7 -3
- qiskit/visualization/counts_visualization.py +4 -0
- qiskit/visualization/dag_visualization.py +2 -1
- qiskit/visualization/gate_map.py +39 -154
- qiskit/visualization/library.py +4 -1
- qiskit/visualization/pass_manager_visualization.py +6 -2
- qiskit/visualization/state_visualization.py +19 -2
- qiskit/visualization/timeline/core.py +19 -13
- qiskit/visualization/timeline/interface.py +19 -18
- qiskit/visualization/timeline/plotters/matplotlib.py +4 -1
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/METADATA +4 -3
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/RECORD +300 -447
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/WHEEL +2 -1
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/entry_points.txt +8 -2
- qiskit/assembler/__init__.py +0 -42
- qiskit/assembler/assemble_circuits.py +0 -451
- qiskit/assembler/assemble_schedules.py +0 -367
- qiskit/assembler/disassemble.py +0 -310
- qiskit/assembler/run_config.py +0 -77
- qiskit/circuit/bit.py +0 -106
- qiskit/circuit/classicalfunction/__init__.py +0 -152
- qiskit/circuit/classicalfunction/boolean_expression.py +0 -138
- qiskit/circuit/classicalfunction/classical_element.py +0 -54
- qiskit/circuit/classicalfunction/classical_function_visitor.py +0 -155
- qiskit/circuit/classicalfunction/classicalfunction.py +0 -182
- qiskit/circuit/classicalfunction/exceptions.py +0 -41
- qiskit/circuit/classicalfunction/types.py +0 -18
- qiskit/circuit/classicalfunction/utils.py +0 -91
- qiskit/circuit/classicalregister.py +0 -57
- qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +0 -405
- qiskit/circuit/quantumregister.py +0 -75
- qiskit/circuit/register.py +0 -246
- qiskit/compiler/assembler.py +0 -689
- qiskit/compiler/scheduler.py +0 -109
- qiskit/compiler/sequencer.py +0 -71
- qiskit/primitives/backend_estimator.py +0 -486
- qiskit/primitives/backend_sampler.py +0 -222
- qiskit/primitives/estimator.py +0 -172
- qiskit/primitives/sampler.py +0 -162
- qiskit/providers/backend_compat.py +0 -507
- qiskit/providers/fake_provider/backends_v1/__init__.py +0 -22
- qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/__init__.py +0 -18
- qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/conf_washington.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/defs_washington.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/fake_127q_pulse_v1.py +0 -37
- qiskit/providers/fake_provider/backends_v1/fake_127q_pulse/props_washington.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_20q/conf_singapore.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_20q/fake_20q.py +0 -43
- qiskit/providers/fake_provider/backends_v1/fake_20q/props_singapore.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/__init__.py +0 -18
- qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/conf_hanoi.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/defs_hanoi.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/fake_27q_pulse_v1.py +0 -50
- qiskit/providers/fake_provider/backends_v1/fake_27q_pulse/props_hanoi.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_5q/__init__.py +0 -18
- qiskit/providers/fake_provider/backends_v1/fake_5q/conf_yorktown.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_5q/fake_5q_v1.py +0 -41
- qiskit/providers/fake_provider/backends_v1/fake_5q/props_yorktown.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/__init__.py +0 -18
- qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/conf_nairobi.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/defs_nairobi.json +0 -1
- qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/fake_7q_pulse_v1.py +0 -44
- qiskit/providers/fake_provider/backends_v1/fake_7q_pulse/props_nairobi.json +0 -1
- qiskit/providers/fake_provider/fake_1q.py +0 -91
- qiskit/providers/fake_provider/fake_backend.py +0 -165
- qiskit/providers/fake_provider/fake_openpulse_2q.py +0 -391
- qiskit/providers/fake_provider/fake_openpulse_3q.py +0 -340
- qiskit/providers/fake_provider/fake_pulse_backend.py +0 -49
- qiskit/providers/fake_provider/fake_qasm_backend.py +0 -77
- qiskit/providers/fake_provider/utils/backend_converter.py +0 -150
- qiskit/providers/fake_provider/utils/json_decoder.py +0 -109
- qiskit/providers/models/__init__.py +0 -89
- qiskit/providers/models/backendconfiguration.py +0 -1040
- qiskit/providers/models/backendproperties.py +0 -535
- qiskit/providers/models/backendstatus.py +0 -104
- qiskit/providers/models/jobstatus.py +0 -77
- qiskit/providers/models/pulsedefaults.py +0 -305
- qiskit/providers/provider.py +0 -95
- qiskit/pulse/__init__.py +0 -158
- qiskit/pulse/builder.py +0 -2262
- qiskit/pulse/calibration_entries.py +0 -381
- qiskit/pulse/channels.py +0 -227
- qiskit/pulse/configuration.py +0 -245
- qiskit/pulse/exceptions.py +0 -45
- qiskit/pulse/filters.py +0 -309
- qiskit/pulse/instruction_schedule_map.py +0 -424
- qiskit/pulse/instructions/__init__.py +0 -67
- qiskit/pulse/instructions/acquire.py +0 -150
- qiskit/pulse/instructions/delay.py +0 -71
- qiskit/pulse/instructions/directives.py +0 -154
- qiskit/pulse/instructions/frequency.py +0 -135
- qiskit/pulse/instructions/instruction.py +0 -270
- qiskit/pulse/instructions/phase.py +0 -152
- qiskit/pulse/instructions/play.py +0 -99
- qiskit/pulse/instructions/reference.py +0 -100
- qiskit/pulse/instructions/snapshot.py +0 -82
- qiskit/pulse/library/__init__.py +0 -97
- qiskit/pulse/library/continuous.py +0 -430
- qiskit/pulse/library/pulse.py +0 -148
- qiskit/pulse/library/samplers/__init__.py +0 -15
- qiskit/pulse/library/samplers/decorators.py +0 -295
- qiskit/pulse/library/samplers/strategies.py +0 -71
- qiskit/pulse/library/symbolic_pulses.py +0 -1989
- qiskit/pulse/library/waveform.py +0 -136
- qiskit/pulse/macros.py +0 -262
- qiskit/pulse/parameter_manager.py +0 -445
- qiskit/pulse/parser.py +0 -314
- qiskit/pulse/reference_manager.py +0 -58
- qiskit/pulse/schedule.py +0 -1854
- qiskit/pulse/transforms/__init__.py +0 -106
- qiskit/pulse/transforms/alignments.py +0 -406
- qiskit/pulse/transforms/base_transforms.py +0 -71
- qiskit/pulse/transforms/canonicalization.py +0 -498
- qiskit/pulse/transforms/dag.py +0 -122
- qiskit/pulse/utils.py +0 -149
- qiskit/qobj/__init__.py +0 -75
- qiskit/qobj/common.py +0 -81
- qiskit/qobj/converters/__init__.py +0 -18
- qiskit/qobj/converters/lo_config.py +0 -177
- qiskit/qobj/converters/pulse_instruction.py +0 -897
- qiskit/qobj/pulse_qobj.py +0 -709
- qiskit/qobj/qasm_qobj.py +0 -708
- qiskit/qobj/utils.py +0 -46
- qiskit/result/mitigation/base_readout_mitigator.py +0 -79
- qiskit/result/mitigation/correlated_readout_mitigator.py +0 -277
- qiskit/result/mitigation/local_readout_mitigator.py +0 -328
- qiskit/result/mitigation/utils.py +0 -217
- qiskit/scheduler/__init__.py +0 -40
- qiskit/scheduler/config.py +0 -37
- qiskit/scheduler/lowering.py +0 -187
- qiskit/scheduler/methods/__init__.py +0 -15
- qiskit/scheduler/methods/basic.py +0 -140
- qiskit/scheduler/schedule_circuit.py +0 -69
- qiskit/scheduler/sequence.py +0 -104
- qiskit/transpiler/passes/calibration/__init__.py +0 -17
- qiskit/transpiler/passes/calibration/base_builder.py +0 -79
- qiskit/transpiler/passes/calibration/builders.py +0 -20
- qiskit/transpiler/passes/calibration/exceptions.py +0 -22
- qiskit/transpiler/passes/calibration/pulse_gate.py +0 -100
- qiskit/transpiler/passes/calibration/rx_builder.py +0 -164
- qiskit/transpiler/passes/calibration/rzx_builder.py +0 -411
- qiskit/transpiler/passes/calibration/rzx_templates.py +0 -58
- qiskit/transpiler/passes/optimization/cx_cancellation.py +0 -65
- qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py +0 -162
- qiskit/transpiler/passes/optimization/normalize_rx_angle.py +0 -157
- qiskit/transpiler/passes/routing/stochastic_swap.py +0 -532
- qiskit/transpiler/passes/scheduling/alap.py +0 -153
- qiskit/transpiler/passes/scheduling/alignments/align_measures.py +0 -255
- qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +0 -107
- qiskit/transpiler/passes/scheduling/asap.py +0 -175
- qiskit/transpiler/passes/scheduling/base_scheduler.py +0 -310
- qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +0 -313
- qiskit/transpiler/passes/utils/convert_conditions_to_if_ops.py +0 -93
- qiskit/utils/deprecate_pulse.py +0 -119
- qiskit/utils/multiprocessing.py +0 -56
- qiskit/visualization/pulse_v2/__init__.py +0 -21
- qiskit/visualization/pulse_v2/core.py +0 -901
- qiskit/visualization/pulse_v2/device_info.py +0 -173
- qiskit/visualization/pulse_v2/drawings.py +0 -253
- qiskit/visualization/pulse_v2/events.py +0 -254
- qiskit/visualization/pulse_v2/generators/__init__.py +0 -40
- qiskit/visualization/pulse_v2/generators/barrier.py +0 -76
- qiskit/visualization/pulse_v2/generators/chart.py +0 -208
- qiskit/visualization/pulse_v2/generators/frame.py +0 -436
- qiskit/visualization/pulse_v2/generators/snapshot.py +0 -133
- qiskit/visualization/pulse_v2/generators/waveform.py +0 -645
- qiskit/visualization/pulse_v2/interface.py +0 -459
- qiskit/visualization/pulse_v2/layouts.py +0 -387
- qiskit/visualization/pulse_v2/plotters/__init__.py +0 -17
- qiskit/visualization/pulse_v2/plotters/base_plotter.py +0 -53
- qiskit/visualization/pulse_v2/plotters/matplotlib.py +0 -201
- qiskit/visualization/pulse_v2/stylesheet.py +0 -312
- qiskit/visualization/pulse_v2/types.py +0 -242
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info/licenses}/LICENSE.txt +0 -0
- {qiskit-1.4.2.dist-info → qiskit-2.0.0.dist-info}/top_level.txt +0 -0
qiskit/circuit/quantumcircuit.py
CHANGED
@@ -18,10 +18,11 @@ from __future__ import annotations
|
|
18
18
|
|
19
19
|
import collections.abc
|
20
20
|
import copy as _copy
|
21
|
+
|
21
22
|
import itertools
|
22
|
-
import multiprocessing
|
23
|
+
import multiprocessing
|
23
24
|
import typing
|
24
|
-
from collections import OrderedDict
|
25
|
+
from collections import OrderedDict
|
25
26
|
from typing import (
|
26
27
|
Union,
|
27
28
|
Optional,
|
@@ -33,26 +34,36 @@ from typing import (
|
|
33
34
|
Mapping,
|
34
35
|
Iterable,
|
35
36
|
Any,
|
36
|
-
DefaultDict,
|
37
37
|
Literal,
|
38
38
|
overload,
|
39
39
|
)
|
40
|
+
from math import pi
|
40
41
|
import numpy as np
|
41
42
|
from qiskit._accelerate.circuit import CircuitData
|
42
43
|
from qiskit._accelerate.circuit import StandardGate
|
44
|
+
from qiskit._accelerate.circuit import BitLocations
|
43
45
|
from qiskit._accelerate.circuit_duration import compute_estimated_duration
|
44
46
|
from qiskit.exceptions import QiskitError
|
45
|
-
from qiskit.utils.multiprocessing import is_main_process
|
46
47
|
from qiskit.circuit.instruction import Instruction
|
47
48
|
from qiskit.circuit.gate import Gate
|
48
49
|
from qiskit.circuit.parameter import Parameter
|
49
50
|
from qiskit.circuit.exceptions import CircuitError
|
50
51
|
from qiskit.utils import deprecate_func
|
51
|
-
from
|
52
|
+
from . import ( # pylint: disable=cyclic-import
|
53
|
+
Bit,
|
54
|
+
QuantumRegister,
|
55
|
+
Qubit,
|
56
|
+
AncillaRegister,
|
57
|
+
AncillaQubit,
|
58
|
+
Clbit,
|
59
|
+
ClassicalRegister,
|
60
|
+
Register,
|
61
|
+
)
|
52
62
|
from . import _classical_resource_map
|
53
63
|
from .controlflow import ControlFlowOp, _builder_utils
|
54
64
|
from .controlflow.builder import CircuitScopeInterface, ControlFlowBuilderBlock
|
55
65
|
from .controlflow.break_loop import BreakLoopOp, BreakLoopPlaceholder
|
66
|
+
from .controlflow.box import BoxOp, BoxContext
|
56
67
|
from .controlflow.continue_loop import ContinueLoopOp, ContinueLoopPlaceholder
|
57
68
|
from .controlflow.for_loop import ForLoopOp, ForLoopContext
|
58
69
|
from .controlflow.if_else import IfElseOp, IfContext
|
@@ -60,14 +71,10 @@ from .controlflow.switch_case import SwitchCaseOp, SwitchContext
|
|
60
71
|
from .controlflow.while_loop import WhileLoopOp, WhileLoopContext
|
61
72
|
from .classical import expr, types
|
62
73
|
from .parameterexpression import ParameterExpression, ParameterValueType
|
63
|
-
from .quantumregister import QuantumRegister, Qubit, AncillaRegister, AncillaQubit
|
64
|
-
from .classicalregister import ClassicalRegister, Clbit
|
65
74
|
from .parametertable import ParameterView
|
66
75
|
from .parametervector import ParameterVector
|
67
76
|
from .instructionset import InstructionSet
|
68
77
|
from .operation import Operation
|
69
|
-
from .register import Register
|
70
|
-
from .bit import Bit
|
71
78
|
from .quantumcircuitdata import QuantumCircuitData, CircuitInstruction
|
72
79
|
from .delay import Delay
|
73
80
|
from .store import Store
|
@@ -79,8 +86,6 @@ if typing.TYPE_CHECKING:
|
|
79
86
|
from qiskit.quantum_info.operators.base_operator import BaseOperator
|
80
87
|
from qiskit.quantum_info.states.statevector import Statevector # pylint: disable=cyclic-import
|
81
88
|
|
82
|
-
BitLocations = namedtuple("BitLocations", ("index", "registers"))
|
83
|
-
|
84
89
|
|
85
90
|
# The following types are not marked private to avoid leaking this "private/public" abstraction out
|
86
91
|
# into the documentation. They are not imported by circuit.__init__, nor are they meant to be.
|
@@ -150,7 +155,6 @@ class QuantumCircuit:
|
|
150
155
|
Immutable data attribute Summary
|
151
156
|
========================= ======================================================================
|
152
157
|
:attr:`ancillas` List of :class:`AncillaQubit`\\ s tracked by the circuit.
|
153
|
-
:attr:`calibrations` Custom user-supplied pulse calibrations for individual instructions.
|
154
158
|
:attr:`cregs` List of :class:`ClassicalRegister`\\ s tracked by the circuit.
|
155
159
|
|
156
160
|
:attr:`clbits` List of :class:`Clbit`\\ s tracked by the circuit.
|
@@ -231,12 +235,6 @@ class QuantumCircuit:
|
|
231
235
|
|
232
236
|
.. autoattribute:: parameters
|
233
237
|
|
234
|
-
The storage of any :ref:`manual pulse-level calibrations <circuit-calibrations>` for individual
|
235
|
-
instructions on the circuit is in :attr:`calibrations`. This presents as a :class:`dict`, but
|
236
|
-
should not be mutated directly; use the methods discussed in :ref:`circuit-calibrations`.
|
237
|
-
|
238
|
-
.. autoattribute:: calibrations
|
239
|
-
|
240
238
|
If you have transpiled your circuit, so you have a physical circuit, you can inspect the
|
241
239
|
:attr:`layout` attribute for information stored by the transpiler about how the virtual qubits
|
242
240
|
of the source circuit map to the hardware qubits of your physical circuit, both at the start and
|
@@ -746,13 +744,14 @@ class QuantumCircuit:
|
|
746
744
|
============================== ================================================================
|
747
745
|
:class:`QuantumCircuit` method Control-flow instruction
|
748
746
|
============================== ================================================================
|
749
|
-
:meth:`if_test` :class:`.IfElseOp` with only a ``True`` body
|
750
|
-
:meth:`if_else` :class:`.IfElseOp` with both ``True`` and ``False`` bodies
|
751
|
-
:meth:`while_loop` :class:`.WhileLoopOp
|
752
|
-
:meth:`switch` :class:`.SwitchCaseOp
|
753
|
-
:meth:`for_loop` :class:`.ForLoopOp
|
754
|
-
:meth:`
|
755
|
-
:meth:`
|
747
|
+
:meth:`if_test` :class:`.IfElseOp` with only a ``True`` body
|
748
|
+
:meth:`if_else` :class:`.IfElseOp` with both ``True`` and ``False`` bodies
|
749
|
+
:meth:`while_loop` :class:`.WhileLoopOp`
|
750
|
+
:meth:`switch` :class:`.SwitchCaseOp`
|
751
|
+
:meth:`for_loop` :class:`.ForLoopOp`
|
752
|
+
:meth:`box` :class:`.BoxOp`
|
753
|
+
:meth:`break_loop` :class:`.BreakLoopOp`
|
754
|
+
:meth:`continue_loop` :class:`.ContinueLoopOp`
|
756
755
|
============================== ================================================================
|
757
756
|
|
758
757
|
:class:`QuantumCircuit` has corresponding methods for all of the control-flow operations that
|
@@ -771,9 +770,14 @@ class QuantumCircuit:
|
|
771
770
|
``with`` statement. It is far simpler and less error-prone to build control flow
|
772
771
|
programmatically this way.
|
773
772
|
|
773
|
+
When using the control-flow builder interface, you may sometimes want a qubit to be included in
|
774
|
+
a block, even though it has no operations defined. In this case, you can use the :meth:`noop`
|
775
|
+
method.
|
776
|
+
|
774
777
|
..
|
775
778
|
TODO: expand the examples of the builder interface.
|
776
779
|
|
780
|
+
.. automethod:: box
|
777
781
|
.. automethod:: break_loop
|
778
782
|
.. automethod:: continue_loop
|
779
783
|
.. automethod:: for_loop
|
@@ -781,6 +785,7 @@ class QuantumCircuit:
|
|
781
785
|
.. automethod:: if_test
|
782
786
|
.. automethod:: switch
|
783
787
|
.. automethod:: while_loop
|
788
|
+
.. automethod:: noop
|
784
789
|
|
785
790
|
|
786
791
|
Converting circuits to single objects
|
@@ -810,17 +815,6 @@ class QuantumCircuit:
|
|
810
815
|
.. automethod:: clear
|
811
816
|
.. automethod:: remove_final_measurements
|
812
817
|
|
813
|
-
.. _circuit-calibrations:
|
814
|
-
|
815
|
-
Manual calibration of instructions
|
816
|
-
----------------------------------
|
817
|
-
|
818
|
-
:class:`QuantumCircuit` can store :attr:`calibrations` of instructions that define the pulses
|
819
|
-
used to run them on one particular hardware backend. You can
|
820
|
-
|
821
|
-
.. automethod:: add_calibration
|
822
|
-
.. automethod:: has_calibration_for
|
823
|
-
|
824
818
|
|
825
819
|
Circuit properties
|
826
820
|
==================
|
@@ -956,19 +950,6 @@ class QuantumCircuit:
|
|
956
950
|
|
957
951
|
.. automethod:: decompose
|
958
952
|
.. automethod:: reverse_bits
|
959
|
-
|
960
|
-
Internal utilities
|
961
|
-
==================
|
962
|
-
|
963
|
-
These functions are not intended for public use, but were accidentally left documented in the
|
964
|
-
public API during the 1.0 release. They will be removed in Qiskit 2.0, but will be supported
|
965
|
-
until then.
|
966
|
-
|
967
|
-
.. automethod:: cast
|
968
|
-
.. automethod:: cbit_argument_conversion
|
969
|
-
.. automethod:: cls_instances
|
970
|
-
.. automethod:: cls_prefix
|
971
|
-
.. automethod:: qbit_argument_conversion
|
972
953
|
"""
|
973
954
|
|
974
955
|
instances = 0
|
@@ -981,7 +962,7 @@ class QuantumCircuit:
|
|
981
962
|
global_phase: ParameterValueType = 0,
|
982
963
|
metadata: dict | None = None,
|
983
964
|
inputs: Iterable[expr.Var] = (),
|
984
|
-
captures: Iterable[expr.Var] = (),
|
965
|
+
captures: Iterable[expr.Var | expr.Stretch] = (),
|
985
966
|
declarations: Mapping[expr.Var, expr.Expr] | Iterable[Tuple[expr.Var, expr.Expr]] = (),
|
986
967
|
):
|
987
968
|
"""
|
@@ -1029,7 +1010,7 @@ class QuantumCircuit:
|
|
1029
1010
|
:meth:`QuantumCircuit.add_input`. The variables given in this argument will be
|
1030
1011
|
passed directly to :meth:`add_input`. A circuit cannot have both ``inputs`` and
|
1031
1012
|
``captures``.
|
1032
|
-
captures: any variables that
|
1013
|
+
captures: any variables that this circuit scope should capture from a containing
|
1033
1014
|
scope. The variables given here will be passed directly to :meth:`add_capture`. A
|
1034
1015
|
circuit cannot have both ``inputs`` and ``captures``.
|
1035
1016
|
declarations: any variables that this circuit should declare and initialize immediately.
|
@@ -1094,26 +1075,11 @@ class QuantumCircuit:
|
|
1094
1075
|
"qiskit.circuit.controlflow.builder.ControlFlowBuilderBlock"
|
1095
1076
|
] = []
|
1096
1077
|
|
1097
|
-
self.qregs: list[QuantumRegister] = []
|
1098
|
-
"""A list of the :class:`QuantumRegister`\\ s in this circuit. You should not mutate
|
1099
|
-
this."""
|
1100
|
-
self.cregs: list[ClassicalRegister] = []
|
1101
|
-
"""A list of the :class:`ClassicalRegister`\\ s in this circuit. You should not mutate
|
1102
|
-
this."""
|
1103
|
-
|
1104
|
-
# Dict mapping Qubit or Clbit instances to tuple comprised of 0) the
|
1105
|
-
# corresponding index in circuit.{qubits,clbits} and 1) a list of
|
1106
|
-
# Register-int pairs for each Register containing the Bit and its index
|
1107
|
-
# within that register.
|
1108
|
-
self._qubit_indices: dict[Qubit, BitLocations] = {}
|
1109
|
-
self._clbit_indices: dict[Clbit, BitLocations] = {}
|
1110
|
-
|
1111
1078
|
# Data contains a list of instructions and their contexts,
|
1112
1079
|
# in the order they were applied.
|
1113
1080
|
self._data: CircuitData = CircuitData()
|
1114
1081
|
|
1115
1082
|
self._ancillas: list[AncillaQubit] = []
|
1116
|
-
self._calibrations: DefaultDict[str, dict[tuple, Any]] = defaultdict(dict)
|
1117
1083
|
self.add_register(*regs)
|
1118
1084
|
|
1119
1085
|
self._layout = None
|
@@ -1124,6 +1090,8 @@ class QuantumCircuit:
|
|
1124
1090
|
self._vars_input: dict[str, expr.Var] = {}
|
1125
1091
|
self._vars_capture: dict[str, expr.Var] = {}
|
1126
1092
|
self._vars_local: dict[str, expr.Var] = {}
|
1093
|
+
self._stretches_capture: dict[str, expr.Stretch] = {}
|
1094
|
+
self._stretches_local: dict[str, expr.Stretch] = {}
|
1127
1095
|
for input_ in inputs:
|
1128
1096
|
self.add_input(input_)
|
1129
1097
|
for capture in captures:
|
@@ -1142,7 +1110,7 @@ class QuantumCircuit:
|
|
1142
1110
|
transpiler and reattach it to the output, so you can track your own metadata."""
|
1143
1111
|
|
1144
1112
|
@property
|
1145
|
-
@deprecate_func(since="1.3.0", removal_timeline="in Qiskit
|
1113
|
+
@deprecate_func(since="1.3.0", removal_timeline="in Qiskit 3.0.0", is_property=True)
|
1146
1114
|
def duration(self):
|
1147
1115
|
"""The total duration of the circuit, set by a scheduling transpiler pass. Its unit is
|
1148
1116
|
specified by :attr:`unit`."""
|
@@ -1153,7 +1121,7 @@ class QuantumCircuit:
|
|
1153
1121
|
self._duration = value
|
1154
1122
|
|
1155
1123
|
@property
|
1156
|
-
@deprecate_func(since="1.3.0", removal_timeline="in Qiskit
|
1124
|
+
@deprecate_func(since="1.3.0", removal_timeline="in Qiskit 3.0.0", is_property=True)
|
1157
1125
|
def unit(self):
|
1158
1126
|
"""The unit that :attr:`duration` is specified in."""
|
1159
1127
|
return self._unit
|
@@ -1171,27 +1139,11 @@ class QuantumCircuit:
|
|
1171
1139
|
|
1172
1140
|
if data.num_qubits > 0:
|
1173
1141
|
if add_regs:
|
1174
|
-
|
1175
|
-
out.qregs = [qr]
|
1176
|
-
out._qubit_indices = {
|
1177
|
-
bit: BitLocations(index, [(qr, index)]) for index, bit in enumerate(data.qubits)
|
1178
|
-
}
|
1179
|
-
else:
|
1180
|
-
out._qubit_indices = {
|
1181
|
-
bit: BitLocations(index, []) for index, bit in enumerate(data.qubits)
|
1182
|
-
}
|
1142
|
+
data.qregs = [QuantumRegister(name="q", bits=data.qubits)]
|
1183
1143
|
|
1184
1144
|
if data.num_clbits > 0:
|
1185
1145
|
if add_regs:
|
1186
|
-
|
1187
|
-
out.cregs = [cr]
|
1188
|
-
out._clbit_indices = {
|
1189
|
-
bit: BitLocations(index, [(cr, index)]) for index, bit in enumerate(data.clbits)
|
1190
|
-
}
|
1191
|
-
else:
|
1192
|
-
out._clbit_indices = {
|
1193
|
-
bit: BitLocations(index, []) for index, bit in enumerate(data.clbits)
|
1194
|
-
}
|
1146
|
+
data.creg = [ClassicalRegister(name="c", bits=data.clbits)]
|
1195
1147
|
|
1196
1148
|
out._data = data
|
1197
1149
|
|
@@ -1311,11 +1263,16 @@ class QuantumCircuit:
|
|
1311
1263
|
def op_start_times(self) -> list[int]:
|
1312
1264
|
"""Return a list of operation start times.
|
1313
1265
|
|
1266
|
+
.. note::
|
1267
|
+
This attribute computes the estimate starting time of the operations in the scheduled circuit
|
1268
|
+
and only works for simple circuits that have no control flow or other classical feed-forward
|
1269
|
+
operations.
|
1270
|
+
|
1314
1271
|
This attribute is enabled once one of scheduling analysis passes
|
1315
1272
|
runs on the quantum circuit.
|
1316
1273
|
|
1317
1274
|
Returns:
|
1318
|
-
List of integers representing instruction start times.
|
1275
|
+
List of integers representing instruction estimated start times.
|
1319
1276
|
The index corresponds to the index of instruction in :attr:`QuantumCircuit.data`.
|
1320
1277
|
|
1321
1278
|
Raises:
|
@@ -1328,67 +1285,6 @@ class QuantumCircuit:
|
|
1328
1285
|
)
|
1329
1286
|
return self._op_start_times
|
1330
1287
|
|
1331
|
-
@property
|
1332
|
-
@deprecate_pulse_dependency(is_property=True)
|
1333
|
-
def calibrations(self) -> dict:
|
1334
|
-
"""Return calibration dictionary.
|
1335
|
-
|
1336
|
-
The custom pulse definition of a given gate is of the form
|
1337
|
-
``{'gate_name': {(qubits, params): schedule}}``
|
1338
|
-
"""
|
1339
|
-
return self._calibrations_prop
|
1340
|
-
|
1341
|
-
@calibrations.setter
|
1342
|
-
@deprecate_pulse_dependency(is_property=True)
|
1343
|
-
def calibrations(self, calibrations: dict):
|
1344
|
-
"""Set the circuit calibration data from a dictionary of calibration definition.
|
1345
|
-
|
1346
|
-
Args:
|
1347
|
-
calibrations (dict): A dictionary of input in the format
|
1348
|
-
``{'gate_name': {(qubits, gate_params): schedule}}``
|
1349
|
-
"""
|
1350
|
-
self._calibrations_prop = calibrations
|
1351
|
-
|
1352
|
-
@property
|
1353
|
-
def _calibrations_prop(self) -> dict:
|
1354
|
-
"""An alternative private path to the `calibrations` property for
|
1355
|
-
avoiding deprecation warnings."""
|
1356
|
-
return dict(self._calibrations)
|
1357
|
-
|
1358
|
-
@_calibrations_prop.setter
|
1359
|
-
def _calibrations_prop(self, calibrations: dict):
|
1360
|
-
"""An alternative private path to the `calibrations` property for
|
1361
|
-
avoiding deprecation warnings."""
|
1362
|
-
self._calibrations = defaultdict(dict, calibrations)
|
1363
|
-
|
1364
|
-
@deprecate_pulse_dependency
|
1365
|
-
def has_calibration_for(self, instruction: CircuitInstruction | tuple):
|
1366
|
-
"""Return True if the circuit has a calibration defined for the instruction context. In this
|
1367
|
-
case, the operation does not need to be translated to the device basis.
|
1368
|
-
"""
|
1369
|
-
|
1370
|
-
return self._has_calibration_for(instruction)
|
1371
|
-
|
1372
|
-
def _has_calibration_for(self, instruction: CircuitInstruction | tuple):
|
1373
|
-
"""An alternative private path to the `has_calibration_for` method for
|
1374
|
-
avoiding deprecation warnings."""
|
1375
|
-
if isinstance(instruction, CircuitInstruction):
|
1376
|
-
operation = instruction.operation
|
1377
|
-
qubits = instruction.qubits
|
1378
|
-
else:
|
1379
|
-
operation, qubits, _ = instruction
|
1380
|
-
if not self._calibrations_prop or operation.name not in self._calibrations_prop:
|
1381
|
-
return False
|
1382
|
-
qubits = tuple(self.qubits.index(qubit) for qubit in qubits)
|
1383
|
-
params = []
|
1384
|
-
for p in operation.params:
|
1385
|
-
if isinstance(p, ParameterExpression) and not p.parameters:
|
1386
|
-
params.append(float(p))
|
1387
|
-
else:
|
1388
|
-
params.append(p)
|
1389
|
-
params = tuple(params)
|
1390
|
-
return (qubits, params) in self._calibrations_prop[operation.name]
|
1391
|
-
|
1392
1288
|
@property
|
1393
1289
|
def metadata(self) -> dict:
|
1394
1290
|
"""The user provided metadata associated with the circuit.
|
@@ -1443,6 +1339,8 @@ class QuantumCircuit:
|
|
1443
1339
|
result._data.replace_bits(
|
1444
1340
|
qubits=_copy.deepcopy(self._data.qubits, memo),
|
1445
1341
|
clbits=_copy.deepcopy(self._data.clbits, memo),
|
1342
|
+
qregs=_copy.deepcopy(self._data.qregs, memo),
|
1343
|
+
cregs=_copy.deepcopy(self._data.cregs, memo),
|
1446
1344
|
)
|
1447
1345
|
return result
|
1448
1346
|
|
@@ -1450,35 +1348,12 @@ class QuantumCircuit:
|
|
1450
1348
|
def _increment_instances(cls):
|
1451
1349
|
cls.instances += 1
|
1452
1350
|
|
1453
|
-
@classmethod
|
1454
|
-
@deprecate_func(
|
1455
|
-
since=1.2,
|
1456
|
-
removal_timeline="in the 2.0 release",
|
1457
|
-
additional_msg="This method is only used as an internal helper "
|
1458
|
-
"and will be removed with no replacement.",
|
1459
|
-
)
|
1460
|
-
def cls_instances(cls) -> int:
|
1461
|
-
"""Return the current number of instances of this class,
|
1462
|
-
useful for auto naming."""
|
1463
|
-
return cls.instances
|
1464
|
-
|
1465
1351
|
@classmethod
|
1466
1352
|
def _cls_instances(cls) -> int:
|
1467
1353
|
"""Return the current number of instances of this class,
|
1468
1354
|
useful for auto naming."""
|
1469
1355
|
return cls.instances
|
1470
1356
|
|
1471
|
-
@classmethod
|
1472
|
-
@deprecate_func(
|
1473
|
-
since=1.2,
|
1474
|
-
removal_timeline="in the 2.0 release",
|
1475
|
-
additional_msg="This method is only used as an internal helper "
|
1476
|
-
"and will be removed with no replacement.",
|
1477
|
-
)
|
1478
|
-
def cls_prefix(cls) -> str:
|
1479
|
-
"""Return the prefix to use for auto naming."""
|
1480
|
-
return cls.prefix
|
1481
|
-
|
1482
1357
|
@classmethod
|
1483
1358
|
def _cls_prefix(cls) -> str:
|
1484
1359
|
"""Return the prefix to use for auto naming."""
|
@@ -1486,11 +1361,10 @@ class QuantumCircuit:
|
|
1486
1361
|
|
1487
1362
|
def _name_update(self) -> None:
|
1488
1363
|
"""update name of instance using instance number"""
|
1489
|
-
if
|
1490
|
-
pid_name = f"-{mp.current_process().pid}"
|
1491
|
-
else:
|
1364
|
+
if multiprocessing.parent_process() is None:
|
1492
1365
|
pid_name = ""
|
1493
|
-
|
1366
|
+
else:
|
1367
|
+
pid_name = f"-{multiprocessing.current_process().pid}"
|
1494
1368
|
self.name = f"{self._base_name}-{self._cls_instances()}{pid_name}"
|
1495
1369
|
|
1496
1370
|
def has_register(self, register: Register) -> bool:
|
@@ -1546,8 +1420,8 @@ class QuantumCircuit:
|
|
1546
1420
|
for instruction in reversed(self.data):
|
1547
1421
|
reverse_circ._append(instruction.replace(operation=instruction.operation.reverse_ops()))
|
1548
1422
|
|
1549
|
-
reverse_circ.
|
1550
|
-
reverse_circ.
|
1423
|
+
reverse_circ._duration = self._duration
|
1424
|
+
reverse_circ._unit = self._unit
|
1551
1425
|
return reverse_circ
|
1552
1426
|
|
1553
1427
|
def reverse_bits(self) -> "QuantumCircuit":
|
@@ -1804,7 +1678,9 @@ class QuantumCircuit:
|
|
1804
1678
|
wrap: bool = False,
|
1805
1679
|
*,
|
1806
1680
|
copy: bool = True,
|
1807
|
-
var_remap:
|
1681
|
+
var_remap: (
|
1682
|
+
Mapping[str | expr.Var | expr.Stretch, str | expr.Var | expr.Stretch] | None
|
1683
|
+
) = None,
|
1808
1684
|
inline_captures: bool = False,
|
1809
1685
|
) -> Optional["QuantumCircuit"]:
|
1810
1686
|
"""Apply the instructions from one circuit onto specified qubits and/or clbits on another.
|
@@ -1848,23 +1724,25 @@ class QuantumCircuit:
|
|
1848
1724
|
the base circuit, in order to avoid unnecessary copies; in this case, it is not
|
1849
1725
|
valid to use ``other`` afterward, and some instructions may have been mutated in
|
1850
1726
|
place.
|
1851
|
-
var_remap (Mapping): mapping to use to rewrite :class:`.expr.Var`
|
1852
|
-
they are inlined into ``self``.
|
1853
|
-
|
1854
|
-
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1858
|
-
:class:`~.expr.
|
1859
|
-
|
1860
|
-
|
1727
|
+
var_remap (Mapping): mapping to use to rewrite :class:`.expr.Var` and
|
1728
|
+
:class:`.expr.Stretch` nodes in ``other`` as they are inlined into ``self``.
|
1729
|
+
This can be used to avoid naming conflicts.
|
1730
|
+
|
1731
|
+
Both keys and values can be given as strings or direct identifier instances.
|
1732
|
+
If a key is a string, it matches any :class:`~.expr.Var` or :class:`~.expr.Stretch`
|
1733
|
+
with the same name. If a value is a string, whenever a new key matches it, a new
|
1734
|
+
:class:`~.expr.Var` or :class:`~.expr.Stretch` is created with the correct type.
|
1735
|
+
If a value is a :class:`~.expr.Var`, its :class:`~.expr.Expr.type` must exactly
|
1736
|
+
match that of the variable it is replacing.
|
1737
|
+
inline_captures (bool): if ``True``, then all "captured" identifier nodes in
|
1738
|
+
the ``other`` :class:`.QuantumCircuit` are assumed to refer to identifiers already
|
1861
1739
|
declared in ``self`` (as any input/capture/local type), and the uses in ``other``
|
1862
|
-
will apply to the existing
|
1740
|
+
will apply to the existing identifiers. If you want to build up a layer for an
|
1863
1741
|
existing circuit to use with :meth:`compose`, you might find the
|
1864
1742
|
``vars_mode="captures"`` argument to :meth:`copy_empty_like` useful. Any remapping
|
1865
1743
|
in ``vars_remap`` occurs before evaluating this variable inlining.
|
1866
1744
|
|
1867
|
-
If this is ``False`` (the default), then all
|
1745
|
+
If this is ``False`` (the default), then all identifiers in ``other`` will be required
|
1868
1746
|
to be distinct from those in ``self``, and new declarations will be made for them.
|
1869
1747
|
wrap (bool): If True, wraps the other circuit into a gate (or instruction, depending on
|
1870
1748
|
whether it contains only unitary instructions) before composing it onto self.
|
@@ -1933,20 +1811,36 @@ class QuantumCircuit:
|
|
1933
1811
|
# instructions. We cache all replacement lookups for a) speed and b) to ensure that
|
1934
1812
|
# the same variable _always_ maps to the same replacement even if it's used in different
|
1935
1813
|
# places in the recursion tree (such as being a captured variable).
|
1936
|
-
def replace_var(
|
1814
|
+
def replace_var(
|
1815
|
+
var: Union[expr.Var, expr.Stretch], cache: Mapping[expr.Var, expr.Var]
|
1816
|
+
) -> Union[expr.Var | expr.Stretch]:
|
1937
1817
|
# This is closing over an argument to `compose`.
|
1938
1818
|
nonlocal var_remap
|
1939
1819
|
|
1940
1820
|
if out := cache.get(var):
|
1941
1821
|
return out
|
1942
1822
|
if (replacement := var_remap.get(var)) or (replacement := var_remap.get(var.name)):
|
1943
|
-
if isinstance(
|
1944
|
-
|
1945
|
-
|
1946
|
-
|
1947
|
-
|
1948
|
-
|
1949
|
-
)
|
1823
|
+
if isinstance(var, expr.Var):
|
1824
|
+
if isinstance(replacement, expr.Stretch):
|
1825
|
+
raise CircuitError(
|
1826
|
+
"mismatched identifier kinds in replacement:"
|
1827
|
+
f" '{var}' cannot become '{replacement}'"
|
1828
|
+
)
|
1829
|
+
if isinstance(replacement, str):
|
1830
|
+
replacement = expr.Var.new(replacement, var.type)
|
1831
|
+
if replacement.type != var.type:
|
1832
|
+
raise CircuitError(
|
1833
|
+
f"mismatched types in replacement for '{var.name}':"
|
1834
|
+
f" '{var.type}' cannot become '{replacement.type}'"
|
1835
|
+
)
|
1836
|
+
else:
|
1837
|
+
if isinstance(replacement, expr.Var):
|
1838
|
+
raise CircuitError(
|
1839
|
+
"mismatched identifier kind in replacement:"
|
1840
|
+
f" '{var}' cannot become '{replacement}'"
|
1841
|
+
)
|
1842
|
+
if isinstance(replacement, str):
|
1843
|
+
replacement = expr.Stretch.new(replacement)
|
1950
1844
|
else:
|
1951
1845
|
replacement = var
|
1952
1846
|
cache[var] = replacement
|
@@ -2028,9 +1922,6 @@ class QuantumCircuit:
|
|
2028
1922
|
)
|
2029
1923
|
edge_map.update(zip(other.clbits, dest._cbit_argument_conversion(clbits)))
|
2030
1924
|
|
2031
|
-
for gate, cals in other._calibrations_prop.items():
|
2032
|
-
dest._calibrations[gate].update(cals)
|
2033
|
-
|
2034
1925
|
dest.duration = None
|
2035
1926
|
dest.unit = "dt"
|
2036
1927
|
dest.global_phase += other.global_phase
|
@@ -2048,9 +1939,9 @@ class QuantumCircuit:
|
|
2048
1939
|
for var in source.iter_input_vars():
|
2049
1940
|
dest.add_input(replace_var(var, var_map))
|
2050
1941
|
if inline_captures:
|
2051
|
-
for var in source.
|
1942
|
+
for var in source.iter_captures():
|
2052
1943
|
replacement = replace_var(var, var_map)
|
2053
|
-
if not dest.
|
1944
|
+
if not dest.has_identifier(replace_var(var, var_map)):
|
2054
1945
|
if var is replacement:
|
2055
1946
|
raise CircuitError(
|
2056
1947
|
f"Variable '{var}' to be inlined is not in the base circuit."
|
@@ -2062,10 +1953,12 @@ class QuantumCircuit:
|
|
2062
1953
|
" base circuit. Is the replacement correct?"
|
2063
1954
|
)
|
2064
1955
|
else:
|
2065
|
-
for var in source.
|
1956
|
+
for var in source.iter_captures():
|
2066
1957
|
dest.add_capture(replace_var(var, var_map))
|
2067
1958
|
for var in source.iter_declared_vars():
|
2068
1959
|
dest.add_uninitialized_var(replace_var(var, var_map))
|
1960
|
+
for stretch in source.iter_declared_stretches():
|
1961
|
+
dest.add_stretch(replace_var(stretch, var_map))
|
2069
1962
|
|
2070
1963
|
def recurse_block(block):
|
2071
1964
|
# Recurse the remapping into a control-flow block. Note that this doesn't remap the
|
@@ -2076,6 +1969,8 @@ class QuantumCircuit:
|
|
2076
1969
|
new_block._vars_input = {}
|
2077
1970
|
new_block._vars_capture = {}
|
2078
1971
|
new_block._vars_local = {}
|
1972
|
+
new_block._stretches_capture = {}
|
1973
|
+
new_block._stretches_local = {}
|
2079
1974
|
# For the recursion, we never want to inline captured variables because we're not
|
2080
1975
|
# copying onto a base that has variables.
|
2081
1976
|
copy_with_remapping(block, new_block, bit_map, var_map, inline_captures=False)
|
@@ -2087,14 +1982,7 @@ class QuantumCircuit:
|
|
2087
1982
|
|
2088
1983
|
def map_vars(op):
|
2089
1984
|
n_op = op
|
2090
|
-
|
2091
|
-
if (
|
2092
|
-
not is_control_flow
|
2093
|
-
and (condition := getattr(n_op, "_condition", None)) is not None
|
2094
|
-
):
|
2095
|
-
n_op = n_op.copy() if n_op is op and copy else n_op
|
2096
|
-
n_op.condition = variable_mapper.map_condition(condition)
|
2097
|
-
elif is_control_flow:
|
1985
|
+
if isinstance(n_op, ControlFlowOp):
|
2098
1986
|
n_op = n_op.replace_blocks(recurse_block(block) for block in n_op.blocks)
|
2099
1987
|
if isinstance(n_op, (IfElseOp, WhileLoopOp)):
|
2100
1988
|
n_op.condition = variable_mapper.map_condition(n_op._condition)
|
@@ -2223,6 +2111,22 @@ class QuantumCircuit:
|
|
2223
2111
|
return None
|
2224
2112
|
return dest
|
2225
2113
|
|
2114
|
+
@property
|
2115
|
+
def _clbit_indices(self) -> dict[Clbit, BitLocations]:
|
2116
|
+
"""Dict mapping Clbit instances to an object comprised of `.index` the
|
2117
|
+
corresponding index in circuit. and `.registers` a list of
|
2118
|
+
Register-int pairs for each Register containing the Bit and its index
|
2119
|
+
within that register."""
|
2120
|
+
return self._data._clbit_indices
|
2121
|
+
|
2122
|
+
@property
|
2123
|
+
def _qubit_indices(self) -> dict[Qubit, BitLocations]:
|
2124
|
+
"""Dict mapping Qubit instances to an object comprised of `.index` the
|
2125
|
+
corresponding index in circuit. and `.registers` a list of
|
2126
|
+
Register-int pairs for each Register containing the Bit and its index
|
2127
|
+
within that register."""
|
2128
|
+
return self._data._qubit_indices
|
2129
|
+
|
2226
2130
|
@property
|
2227
2131
|
def qubits(self) -> list[Qubit]:
|
2228
2132
|
"""A list of :class:`Qubit`\\ s in the order that they were added. You should not mutate
|
@@ -2235,6 +2139,26 @@ class QuantumCircuit:
|
|
2235
2139
|
this."""
|
2236
2140
|
return self._data.clbits
|
2237
2141
|
|
2142
|
+
@property
|
2143
|
+
def qregs(self) -> list[QuantumRegister]:
|
2144
|
+
"""A list of :class:`Qubit`\\ s in the order that they were added. You should not mutate
|
2145
|
+
this."""
|
2146
|
+
return self._data.qregs
|
2147
|
+
|
2148
|
+
@qregs.setter
|
2149
|
+
def qregs(self, other: list[QuantumRegister]):
|
2150
|
+
self._data.qregs = other
|
2151
|
+
|
2152
|
+
@property
|
2153
|
+
def cregs(self) -> list[ClassicalRegister]:
|
2154
|
+
"""A list of :class:`Clbit`\\ s in the order that they were added. You should not mutate
|
2155
|
+
this."""
|
2156
|
+
return self._data.cregs
|
2157
|
+
|
2158
|
+
@cregs.setter
|
2159
|
+
def cregs(self, other: list[ClassicalRegister]):
|
2160
|
+
self._data.cregs = other
|
2161
|
+
|
2238
2162
|
@property
|
2239
2163
|
def ancillas(self) -> list[AncillaQubit]:
|
2240
2164
|
"""A list of :class:`AncillaQubit`\\ s in the order that they were added. You should not
|
@@ -2248,6 +2172,22 @@ class QuantumCircuit:
|
|
2248
2172
|
This is the length of the :meth:`iter_vars` iterable."""
|
2249
2173
|
return self.num_input_vars + self.num_captured_vars + self.num_declared_vars
|
2250
2174
|
|
2175
|
+
@property
|
2176
|
+
def num_stretches(self) -> int:
|
2177
|
+
"""The number of stretches in the circuit.
|
2178
|
+
|
2179
|
+
This is the length of the :meth:`iter_stretches` iterable."""
|
2180
|
+
return self.num_captured_stretches + self.num_declared_stretches
|
2181
|
+
|
2182
|
+
@property
|
2183
|
+
def num_identifiers(self) -> int:
|
2184
|
+
"""The number of real-time classical variables and stretches in
|
2185
|
+
the circuit.
|
2186
|
+
|
2187
|
+
This is equal to :meth:`num_vars` + :meth:`num_stretches`.
|
2188
|
+
"""
|
2189
|
+
return self.num_vars + self.num_stretches
|
2190
|
+
|
2251
2191
|
@property
|
2252
2192
|
def num_input_vars(self) -> int:
|
2253
2193
|
"""The number of real-time classical variables in the circuit marked as circuit inputs.
|
@@ -2265,6 +2205,15 @@ class QuantumCircuit:
|
|
2265
2205
|
:attr:`num_input_vars` must be zero."""
|
2266
2206
|
return len(self._vars_capture)
|
2267
2207
|
|
2208
|
+
@property
|
2209
|
+
def num_captured_stretches(self) -> int:
|
2210
|
+
"""The number of stretches in the circuit marked as captured from an
|
2211
|
+
enclosing scope.
|
2212
|
+
|
2213
|
+
This is the length of the :meth:`iter_captured_stretches` iterable. If this is non-zero,
|
2214
|
+
:attr:`num_input_vars` must be zero."""
|
2215
|
+
return len(self._stretches_capture)
|
2216
|
+
|
2268
2217
|
@property
|
2269
2218
|
def num_declared_vars(self) -> int:
|
2270
2219
|
"""The number of real-time classical variables in the circuit that are declared by this
|
@@ -2273,6 +2222,14 @@ class QuantumCircuit:
|
|
2273
2222
|
This is the length of the :meth:`iter_declared_vars` iterable."""
|
2274
2223
|
return len(self._vars_local)
|
2275
2224
|
|
2225
|
+
@property
|
2226
|
+
def num_declared_stretches(self) -> int:
|
2227
|
+
"""The number of stretches in the circuit that are declared by this
|
2228
|
+
circuit scope, excluding captures.
|
2229
|
+
|
2230
|
+
This is the length of the :meth:`iter_declared_stretches` iterable."""
|
2231
|
+
return len(self._stretches_local)
|
2232
|
+
|
2276
2233
|
def iter_vars(self) -> typing.Iterable[expr.Var]:
|
2277
2234
|
"""Get an iterable over all real-time classical variables in scope within this circuit.
|
2278
2235
|
|
@@ -2285,6 +2242,18 @@ class QuantumCircuit:
|
|
2285
2242
|
self._vars_input.values(), self._vars_capture.values(), self._vars_local.values()
|
2286
2243
|
)
|
2287
2244
|
|
2245
|
+
def iter_stretches(self) -> typing.Iterable[expr.Stretch]:
|
2246
|
+
"""Get an iterable over all stretches in scope within this circuit.
|
2247
|
+
|
2248
|
+
This method will iterate over all stretches in scope. For more fine-grained iterators, see
|
2249
|
+
:meth:`iter_declared_stretches` and :meth:`iter_captured_stretches`."""
|
2250
|
+
if self._control_flow_scopes:
|
2251
|
+
builder = self._control_flow_scopes[-1]
|
2252
|
+
return itertools.chain(
|
2253
|
+
builder.iter_captured_stretches(), builder.iter_local_stretches()
|
2254
|
+
)
|
2255
|
+
return itertools.chain(self._stretches_capture.values(), self._stretches_local.values())
|
2256
|
+
|
2288
2257
|
def iter_declared_vars(self) -> typing.Iterable[expr.Var]:
|
2289
2258
|
"""Get an iterable over all real-time classical variables that are declared with automatic
|
2290
2259
|
storage duration in this scope. This excludes input variables (see :meth:`iter_input_vars`)
|
@@ -2293,6 +2262,13 @@ class QuantumCircuit:
|
|
2293
2262
|
return self._control_flow_scopes[-1].iter_local_vars()
|
2294
2263
|
return self._vars_local.values()
|
2295
2264
|
|
2265
|
+
def iter_declared_stretches(self) -> typing.Iterable[expr.Stretch]:
|
2266
|
+
"""Get an iterable over all stretches that are declared in this scope.
|
2267
|
+
This excludes captured stretches (see :meth:`iter_captured_stretches`)."""
|
2268
|
+
if self._control_flow_scopes:
|
2269
|
+
return self._control_flow_scopes[-1].iter_local_stretches()
|
2270
|
+
return self._stretches_local.values()
|
2271
|
+
|
2296
2272
|
def iter_input_vars(self) -> typing.Iterable[expr.Var]:
|
2297
2273
|
"""Get an iterable over all real-time classical variables that are declared as inputs to
|
2298
2274
|
this circuit scope. This excludes locally declared variables (see
|
@@ -2301,6 +2277,18 @@ class QuantumCircuit:
|
|
2301
2277
|
return ()
|
2302
2278
|
return self._vars_input.values()
|
2303
2279
|
|
2280
|
+
def iter_captures(self) -> typing.Iterable[typing.Union[expr.Var, expr.Stretch]]:
|
2281
|
+
"""Get an iterable over all identifiers are captured by this circuit scope from a
|
2282
|
+
containing scope. This excludes input variables (see :meth:`iter_input_vars`)
|
2283
|
+
and locally declared variables and stretches (see :meth:`iter_declared_vars`
|
2284
|
+
and :meth:`iter_declared_stretches`)."""
|
2285
|
+
if self._control_flow_scopes:
|
2286
|
+
return itertools.chain(
|
2287
|
+
self._control_flow_scopes[-1].iter_captured_vars(),
|
2288
|
+
self._control_flow_scopes[-1].iter_captured_stretches(),
|
2289
|
+
)
|
2290
|
+
return itertools.chain(self._vars_capture.values(), self._stretches_capture.values())
|
2291
|
+
|
2304
2292
|
def iter_captured_vars(self) -> typing.Iterable[expr.Var]:
|
2305
2293
|
"""Get an iterable over all real-time classical variables that are captured by this circuit
|
2306
2294
|
scope from a containing scope. This excludes input variables (see :meth:`iter_input_vars`)
|
@@ -2309,6 +2297,14 @@ class QuantumCircuit:
|
|
2309
2297
|
return self._control_flow_scopes[-1].iter_captured_vars()
|
2310
2298
|
return self._vars_capture.values()
|
2311
2299
|
|
2300
|
+
def iter_captured_stretches(self) -> typing.Iterable[expr.Stretch]:
|
2301
|
+
"""Get an iterable over stretches that are captured by this circuit
|
2302
|
+
scope from a containing scope. This excludes locally declared stretches
|
2303
|
+
(see :meth:`iter_declared_stretches`)."""
|
2304
|
+
if self._control_flow_scopes:
|
2305
|
+
return self._control_flow_scopes[-1].iter_captured_stretches()
|
2306
|
+
return self._stretches_capture.values()
|
2307
|
+
|
2312
2308
|
def __and__(self, rhs: "QuantumCircuit") -> "QuantumCircuit":
|
2313
2309
|
"""Overload & to implement self.compose."""
|
2314
2310
|
return self.compose(rhs)
|
@@ -2341,20 +2337,6 @@ class QuantumCircuit:
|
|
2341
2337
|
"""Return indexed operation."""
|
2342
2338
|
return self._data[item]
|
2343
2339
|
|
2344
|
-
@staticmethod
|
2345
|
-
@deprecate_func(
|
2346
|
-
since=1.2,
|
2347
|
-
removal_timeline="in the 2.0 release",
|
2348
|
-
additional_msg="This method is only used as an internal helper "
|
2349
|
-
"and will be removed with no replacement.",
|
2350
|
-
)
|
2351
|
-
def cast(value: S, type_: Callable[..., T]) -> Union[S, T]:
|
2352
|
-
"""Best effort to cast value to type. Otherwise, returns the value."""
|
2353
|
-
try:
|
2354
|
-
return type_(value)
|
2355
|
-
except (ValueError, TypeError):
|
2356
|
-
return value
|
2357
|
-
|
2358
2340
|
@staticmethod
|
2359
2341
|
def _cast(value: S, type_: Callable[..., T]) -> Union[S, T]:
|
2360
2342
|
"""Best effort to cast value to type. Otherwise, returns the value."""
|
@@ -2363,26 +2345,6 @@ class QuantumCircuit:
|
|
2363
2345
|
except (ValueError, TypeError):
|
2364
2346
|
return value
|
2365
2347
|
|
2366
|
-
@deprecate_func(
|
2367
|
-
since=1.2,
|
2368
|
-
removal_timeline="in the 2.0 release",
|
2369
|
-
additional_msg="This method is only used as an internal helper "
|
2370
|
-
"and will be removed with no replacement.",
|
2371
|
-
)
|
2372
|
-
def qbit_argument_conversion(self, qubit_representation: QubitSpecifier) -> list[Qubit]:
|
2373
|
-
"""
|
2374
|
-
Converts several qubit representations (such as indexes, range, etc.)
|
2375
|
-
into a list of qubits.
|
2376
|
-
|
2377
|
-
Args:
|
2378
|
-
qubit_representation: Representation to expand.
|
2379
|
-
|
2380
|
-
Returns:
|
2381
|
-
The resolved instances of the qubits.
|
2382
|
-
"""
|
2383
|
-
|
2384
|
-
return self._qbit_argument_conversion(qubit_representation)
|
2385
|
-
|
2386
2348
|
def _qbit_argument_conversion(self, qubit_representation: QubitSpecifier) -> list[Qubit]:
|
2387
2349
|
"""
|
2388
2350
|
Converts several qubit representations (such as indexes, range, etc.)
|
@@ -2394,28 +2356,7 @@ class QuantumCircuit:
|
|
2394
2356
|
Returns:
|
2395
2357
|
The resolved instances of the qubits.
|
2396
2358
|
"""
|
2397
|
-
return
|
2398
|
-
qubit_representation, self.qubits, self._qubit_indices, Qubit
|
2399
|
-
)
|
2400
|
-
|
2401
|
-
@deprecate_func(
|
2402
|
-
since=1.2,
|
2403
|
-
removal_timeline="in the 2.0 release",
|
2404
|
-
additional_msg="This method is only used as an internal helper "
|
2405
|
-
"and will be removed with no replacement.",
|
2406
|
-
)
|
2407
|
-
def cbit_argument_conversion(self, clbit_representation: ClbitSpecifier) -> list[Clbit]:
|
2408
|
-
"""
|
2409
|
-
Converts several classical bit representations (such as indexes, range, etc.)
|
2410
|
-
into a list of classical bits.
|
2411
|
-
|
2412
|
-
Args:
|
2413
|
-
clbit_representation : Representation to expand.
|
2414
|
-
|
2415
|
-
Returns:
|
2416
|
-
A list of tuples where each tuple is a classical bit.
|
2417
|
-
"""
|
2418
|
-
return self._cbit_argument_conversion(clbit_representation)
|
2359
|
+
return self._data._qbit_argument_conversion(qubit_representation)
|
2419
2360
|
|
2420
2361
|
def _cbit_argument_conversion(self, clbit_representation: ClbitSpecifier) -> list[Clbit]:
|
2421
2362
|
"""
|
@@ -2428,9 +2369,7 @@ class QuantumCircuit:
|
|
2428
2369
|
Returns:
|
2429
2370
|
A list of tuples where each tuple is a classical bit.
|
2430
2371
|
"""
|
2431
|
-
return
|
2432
|
-
clbit_representation, self.clbits, self._clbit_indices, Clbit
|
2433
|
-
)
|
2372
|
+
return self._data._cbit_argument_conversion(clbit_representation)
|
2434
2373
|
|
2435
2374
|
def _append_standard_gate(
|
2436
2375
|
self,
|
@@ -2535,9 +2474,9 @@ class QuantumCircuit:
|
|
2535
2474
|
if bad_captures := {
|
2536
2475
|
var
|
2537
2476
|
for var in itertools.chain.from_iterable(
|
2538
|
-
block.
|
2477
|
+
block.iter_captures() for block in operation.blocks
|
2539
2478
|
)
|
2540
|
-
if not self.
|
2479
|
+
if not self.has_identifier(var)
|
2541
2480
|
}:
|
2542
2481
|
raise CircuitError(
|
2543
2482
|
f"Control-flow op attempts to capture '{bad_captures}'"
|
@@ -2588,8 +2527,8 @@ class QuantumCircuit:
|
|
2588
2527
|
|
2589
2528
|
* all the qubits and clbits must already exist in the circuit and there can be no
|
2590
2529
|
duplicates in the list.
|
2591
|
-
* any control-flow operations
|
2592
|
-
|
2530
|
+
* any control-flow operations instructions must act only on variables present in the
|
2531
|
+
circuit.
|
2593
2532
|
* the circuit must not be within a control-flow builder context.
|
2594
2533
|
|
2595
2534
|
.. note::
|
@@ -2620,8 +2559,8 @@ class QuantumCircuit:
|
|
2620
2559
|
"""
|
2621
2560
|
if _standard_gate:
|
2622
2561
|
self._data.append(instruction)
|
2623
|
-
self.
|
2624
|
-
self.
|
2562
|
+
self._duration = None
|
2563
|
+
self._unit = "dt"
|
2625
2564
|
return instruction
|
2626
2565
|
|
2627
2566
|
old_style = not isinstance(instruction, CircuitInstruction)
|
@@ -2643,8 +2582,8 @@ class QuantumCircuit:
|
|
2643
2582
|
self._data.append_manual_params(instruction, params)
|
2644
2583
|
|
2645
2584
|
# Invalidate whole circuit duration if an instruction is added
|
2646
|
-
self.
|
2647
|
-
self.
|
2585
|
+
self._duration = None
|
2586
|
+
self._unit = "dt"
|
2648
2587
|
return instruction.operation if old_style else instruction
|
2649
2588
|
|
2650
2589
|
@typing.overload
|
@@ -2802,6 +2741,144 @@ class QuantumCircuit:
|
|
2802
2741
|
return self.get_var(name_or_var, None) is not None
|
2803
2742
|
return self.get_var(name_or_var.name, None) == name_or_var
|
2804
2743
|
|
2744
|
+
@typing.overload
|
2745
|
+
def get_stretch(self, name: str, default: T) -> Union[expr.Stretch, T]: ...
|
2746
|
+
|
2747
|
+
# The builtin `types` module has `EllipsisType`, but only from 3.10+!
|
2748
|
+
@typing.overload
|
2749
|
+
def get_stretch(self, name: str, default: type(...) = ...) -> expr.Stretch: ...
|
2750
|
+
|
2751
|
+
def get_stretch(self, name: str, default: typing.Any = ...):
|
2752
|
+
"""Retrieve a stretch that is accessible in this circuit scope by name.
|
2753
|
+
|
2754
|
+
Args:
|
2755
|
+
name: the name of the stretch to retrieve.
|
2756
|
+
default: if given, this value will be returned if the variable is not present. If it
|
2757
|
+
is not given, a :exc:`KeyError` is raised instead.
|
2758
|
+
|
2759
|
+
Returns:
|
2760
|
+
The corresponding stretch.
|
2761
|
+
|
2762
|
+
Raises:
|
2763
|
+
KeyError: if no default is given, but the variable does not exist.
|
2764
|
+
|
2765
|
+
Examples:
|
2766
|
+
Retrieve a stretch by name from a circuit::
|
2767
|
+
|
2768
|
+
from qiskit.circuit import QuantumCircuit
|
2769
|
+
|
2770
|
+
# Create a circuit and create a variable in it.
|
2771
|
+
qc = QuantumCircuit()
|
2772
|
+
my_stretch = qc.add_stretch("my_stretch")
|
2773
|
+
|
2774
|
+
# We can use 'my_stretch' as a variable, but let's say we've lost the Python object and
|
2775
|
+
# need to retrieve it.
|
2776
|
+
my_stretch_again = qc.get_stretch("my_stretch")
|
2777
|
+
|
2778
|
+
assert my_stretch is my_stretch_again
|
2779
|
+
|
2780
|
+
Get a variable from a circuit by name, returning some default if it is not present::
|
2781
|
+
|
2782
|
+
assert qc.get_stretch("my_stretch", None) is my_stretch
|
2783
|
+
assert qc.get_stretch("unknown_stretch", None) is None
|
2784
|
+
"""
|
2785
|
+
if (out := self._current_scope().get_stretch(name)) is not None:
|
2786
|
+
return out
|
2787
|
+
if default is Ellipsis:
|
2788
|
+
raise KeyError(f"no stretch named '{name}' is present")
|
2789
|
+
return default
|
2790
|
+
|
2791
|
+
def has_stretch(self, name_or_stretch: str | expr.Stretch, /) -> bool:
|
2792
|
+
"""Check whether a stretch is accessible in this scope.
|
2793
|
+
|
2794
|
+
Args:
|
2795
|
+
name_or_stretch: the stretch, or name of a stretch to check. If this is a
|
2796
|
+
:class:`.expr.Stretch` node, the stretch must be exactly the given one for this
|
2797
|
+
function to return ``True``.
|
2798
|
+
|
2799
|
+
Returns:
|
2800
|
+
whether a matching stretch is accessible.
|
2801
|
+
|
2802
|
+
See also:
|
2803
|
+
:meth:`QuantumCircuit.get_stretch`
|
2804
|
+
Retrieve the :class:`.expr.Stretch` instance from this circuit by name.
|
2805
|
+
"""
|
2806
|
+
if isinstance(name_or_stretch, str):
|
2807
|
+
return self.get_stretch(name_or_stretch, None) is not None
|
2808
|
+
return self.get_stretch(name_or_stretch.name, None) == name_or_stretch
|
2809
|
+
|
2810
|
+
@typing.overload
|
2811
|
+
def get_identifier(self, name: str, default: T) -> Union[expr.Var | expr.Stretch, T]: ...
|
2812
|
+
|
2813
|
+
# The builtin `types` module has `EllipsisType`, but only from 3.10+!
|
2814
|
+
@typing.overload
|
2815
|
+
def get_identifier(
|
2816
|
+
self, name: str, default: type(...) = ...
|
2817
|
+
) -> Union[expr.Var, expr.Stretch]: ...
|
2818
|
+
|
2819
|
+
# We use a _literal_ `Ellipsis` as the marker value to leave `None` available as a default.
|
2820
|
+
def get_identifier(self, name: str, default: typing.Any = ...):
|
2821
|
+
"""Retrieve an identifier that is accessible in this circuit scope by name.
|
2822
|
+
|
2823
|
+
This currently includes both real-time classical variables and stretches.
|
2824
|
+
|
2825
|
+
Args:
|
2826
|
+
name: the name of the identifier to retrieve.
|
2827
|
+
default: if given, this value will be returned if the variable is not present. If it
|
2828
|
+
is not given, a :exc:`KeyError` is raised instead.
|
2829
|
+
|
2830
|
+
Returns:
|
2831
|
+
The corresponding variable.
|
2832
|
+
|
2833
|
+
Raises:
|
2834
|
+
KeyError: if no default is given, but the identifier does not exist.
|
2835
|
+
|
2836
|
+
See also:
|
2837
|
+
:meth:`get_var`
|
2838
|
+
Gets an identifier known to be a :class:`.expr.Var` instance.
|
2839
|
+
:meth:`get_stretch`
|
2840
|
+
Gets an identifier known to be a :class:`.expr.Stretch` instance.
|
2841
|
+
:meth:`get_parameter`
|
2842
|
+
A similar method, but for :class:`.Parameter` compile-time parameters instead of
|
2843
|
+
:class:`.expr.Var` run-time variables.
|
2844
|
+
"""
|
2845
|
+
if (out := self._current_scope().get_var(name)) is not None:
|
2846
|
+
return out
|
2847
|
+
if (out := self._current_scope().get_stretch(name)) is not None:
|
2848
|
+
return out
|
2849
|
+
if default is Ellipsis:
|
2850
|
+
raise KeyError(f"no identifier named '{name}' is present")
|
2851
|
+
return default
|
2852
|
+
|
2853
|
+
def has_identifier(self, name_or_ident: str | expr.Var | expr.Stretch, /) -> bool:
|
2854
|
+
"""Check whether an identifier is accessible in this scope.
|
2855
|
+
|
2856
|
+
Args:
|
2857
|
+
name_or_ident: the instance, or name of the identifier to check. If this is a
|
2858
|
+
:class:`.expr.Var` or :class:`.expr.Stretch` node, the matched instance must
|
2859
|
+
be exactly the given one for this function to return ``True``.
|
2860
|
+
|
2861
|
+
Returns:
|
2862
|
+
whether a matching identifier is accessible.
|
2863
|
+
|
2864
|
+
See also:
|
2865
|
+
:meth:`QuantumCircuit.get_identifier`
|
2866
|
+
Retrieve the :class:`.expr.Var` or :class:`.expr.Stretch` instance from this
|
2867
|
+
circuit by name.
|
2868
|
+
:meth:`QuantumCircuit.has_var`
|
2869
|
+
The same as this method, but ignoring anything that isn't a
|
2870
|
+
run-time :class:`expr.Var` variable.
|
2871
|
+
:meth:`QuantumCircuit.has_stretch`
|
2872
|
+
The same as this method, but ignoring anything that isn't a
|
2873
|
+
run-time :class:`expr.Stretch` variable.
|
2874
|
+
:meth:`QuantumCircuit.has_parameter`
|
2875
|
+
A similar method to this, but for compile-time :class:`.Parameter`\\ s instead of
|
2876
|
+
run-time :class:`.expr.Var` variables.
|
2877
|
+
"""
|
2878
|
+
if isinstance(name_or_ident, str):
|
2879
|
+
return self.get_identifier(name_or_ident, None) is not None
|
2880
|
+
return self.get_identifier(name_or_ident.name, None) == name_or_ident
|
2881
|
+
|
2805
2882
|
def _prepare_new_var(
|
2806
2883
|
self, name_or_var: str | expr.Var, type_: types.Type | None, /
|
2807
2884
|
) -> expr.Var:
|
@@ -2826,12 +2903,63 @@ class QuantumCircuit:
|
|
2826
2903
|
|
2827
2904
|
# The `var` is guaranteed to have a name because we already excluded the cases where it's
|
2828
2905
|
# wrapping a bit/register.
|
2829
|
-
if (previous := self.
|
2906
|
+
if (previous := self.get_identifier(var.name, default=None)) is not None:
|
2830
2907
|
if previous == var:
|
2831
2908
|
raise CircuitError(f"'{var}' is already present in the circuit")
|
2832
2909
|
raise CircuitError(f"cannot add '{var}' as its name shadows the existing '{previous}'")
|
2833
2910
|
return var
|
2834
2911
|
|
2912
|
+
def _prepare_new_stretch(self, name_or_stretch: str | expr.Stretch, /) -> expr.Stretch:
|
2913
|
+
"""The common logic for preparing and validating a new :class:`~.expr.Stretch` for the circuit.
|
2914
|
+
|
2915
|
+
Returns the validated stretch, which is guaranteed to be safe to add to the circuit."""
|
2916
|
+
if isinstance(name_or_stretch, str):
|
2917
|
+
stretch = expr.Stretch.new(name_or_stretch)
|
2918
|
+
else:
|
2919
|
+
stretch = name_or_stretch
|
2920
|
+
|
2921
|
+
if (previous := self.get_identifier(stretch.name, default=None)) is not None:
|
2922
|
+
if previous == stretch:
|
2923
|
+
raise CircuitError(f"'{stretch}' is already present in the circuit")
|
2924
|
+
raise CircuitError(
|
2925
|
+
f"cannot add '{stretch}' as its name shadows the existing '{previous}'"
|
2926
|
+
)
|
2927
|
+
return stretch
|
2928
|
+
|
2929
|
+
def add_stretch(self, name_or_stretch: str | expr.Stretch) -> expr.Stretch:
|
2930
|
+
"""Declares a new stretch scoped to this circuit.
|
2931
|
+
|
2932
|
+
Args:
|
2933
|
+
name_or_stretch: either a string of the stretch name, or an existing instance of
|
2934
|
+
:class:`~.expr.Stretch` to re-use. Stretches cannot shadow names that are already in
|
2935
|
+
use within the circuit.
|
2936
|
+
|
2937
|
+
Returns:
|
2938
|
+
The created stretch. If a :class:`~.expr.Stretch` instance was given, the exact same
|
2939
|
+
object will be returned.
|
2940
|
+
|
2941
|
+
Raises:
|
2942
|
+
CircuitError: if the stretch cannot be created due to shadowing an existing
|
2943
|
+
identifier.
|
2944
|
+
|
2945
|
+
Examples:
|
2946
|
+
Define and use a new stretch given just a name::
|
2947
|
+
|
2948
|
+
from qiskit.circuit import QuantumCircuit, Duration
|
2949
|
+
from qiskit.circuit.classical import expr
|
2950
|
+
|
2951
|
+
qc = QuantumCircuit(2)
|
2952
|
+
my_stretch = qc.add_stretch("my_stretch")
|
2953
|
+
|
2954
|
+
qc.delay(expr.add(Duration.dt(200), my_stretch), 1)
|
2955
|
+
"""
|
2956
|
+
if isinstance(name_or_stretch, str):
|
2957
|
+
stretch = expr.Stretch.new(name_or_stretch)
|
2958
|
+
else:
|
2959
|
+
stretch = name_or_stretch
|
2960
|
+
self._current_scope().add_stretch(stretch)
|
2961
|
+
return stretch
|
2962
|
+
|
2835
2963
|
def add_var(self, name_or_var: str | expr.Var, /, initial: typing.Any) -> expr.Var:
|
2836
2964
|
"""Add a classical variable with automatic storage and scope to this circuit.
|
2837
2965
|
|
@@ -2857,7 +2985,7 @@ class QuantumCircuit:
|
|
2857
2985
|
object will be returned.
|
2858
2986
|
|
2859
2987
|
Raises:
|
2860
|
-
CircuitError: if the variable cannot be created due to shadowing an existing
|
2988
|
+
CircuitError: if the variable cannot be created due to shadowing an existing identifier.
|
2861
2989
|
|
2862
2990
|
Examples:
|
2863
2991
|
Define a new variable given just a name and an initializer expression::
|
@@ -2961,37 +3089,51 @@ class QuantumCircuit:
|
|
2961
3089
|
raise CircuitError("cannot add a variable wrapping a bit or register to a circuit")
|
2962
3090
|
self._builder_api.add_uninitialized_var(var)
|
2963
3091
|
|
2964
|
-
|
2965
|
-
|
2966
|
-
|
3092
|
+
@typing.overload
|
3093
|
+
def add_capture(self, var: expr.Var): ...
|
3094
|
+
|
3095
|
+
@typing.overload
|
3096
|
+
def add_capture(self, stretch: expr.Stretch): ...
|
3097
|
+
|
3098
|
+
def add_capture(self, var):
|
3099
|
+
"""Add an identifier to the circuit that it should capture from a scope it will
|
3100
|
+
be contained within.
|
2967
3101
|
|
2968
|
-
This method requires a :class:`~.expr.Var` node to enforce that
|
2969
|
-
because you will need to declare the same
|
2970
|
-
circuit.
|
3102
|
+
This method requires a :class:`~.expr.Var` or :class:`~.expr.Stretch` node to enforce that
|
3103
|
+
you've got a handle to an identifier, because you will need to declare the same identifier
|
3104
|
+
using the same object in the outer circuit.
|
2971
3105
|
|
2972
3106
|
This is a low-level method, which is only really useful if you are manually constructing
|
2973
3107
|
control-flow operations. You typically will not need to call this method, assuming you
|
2974
3108
|
are using the builder interface for control-flow scopes (``with`` context-manager statements
|
2975
3109
|
for :meth:`if_test` and the other scoping constructs). The builder interface will
|
2976
|
-
automatically make the inner scopes closures on your behalf by capturing any
|
2977
|
-
are used within them.
|
3110
|
+
automatically make the inner scopes closures on your behalf by capturing any identifiers
|
3111
|
+
that are used within them.
|
2978
3112
|
|
2979
3113
|
Args:
|
2980
|
-
var: the variable to capture from an
|
3114
|
+
var (Union[expr.Var, expr.Stretch]): the variable or stretch to capture from an
|
3115
|
+
enclosing scope.
|
2981
3116
|
|
2982
3117
|
Raises:
|
2983
|
-
CircuitError: if the
|
3118
|
+
CircuitError: if the identifier cannot be created due to shadowing an existing
|
3119
|
+
identifier.
|
2984
3120
|
"""
|
2985
3121
|
if self._control_flow_scopes:
|
2986
3122
|
# Allow manual capturing. Not sure why it'd be useful, but there's a clear expected
|
2987
3123
|
# behavior here.
|
2988
|
-
|
3124
|
+
if isinstance(var, expr.Stretch):
|
3125
|
+
self._control_flow_scopes[-1].use_stretch(var)
|
3126
|
+
else:
|
3127
|
+
self._control_flow_scopes[-1].use_var(var)
|
2989
3128
|
return
|
2990
3129
|
if self._vars_input:
|
2991
3130
|
raise CircuitError(
|
2992
3131
|
"circuits with input variables cannot be enclosed, so cannot be closures"
|
2993
3132
|
)
|
2994
|
-
|
3133
|
+
if isinstance(var, expr.Stretch):
|
3134
|
+
self._stretches_capture[var.name] = self._prepare_new_stretch(var)
|
3135
|
+
else:
|
3136
|
+
self._vars_capture[var.name] = self._prepare_new_var(var, None)
|
2995
3137
|
|
2996
3138
|
@typing.overload
|
2997
3139
|
def add_input(self, name_or_var: str, type_: types.Type, /) -> expr.Var: ...
|
@@ -3019,7 +3161,7 @@ class QuantumCircuit:
|
|
3019
3161
|
"""
|
3020
3162
|
if self._control_flow_scopes:
|
3021
3163
|
raise CircuitError("cannot add an input variable in a control-flow scope")
|
3022
|
-
if self._vars_capture:
|
3164
|
+
if self._vars_capture or self._stretches_capture:
|
3023
3165
|
raise CircuitError("circuits to be enclosed with captures cannot have input variables")
|
3024
3166
|
if isinstance(name_or_var, expr.Var) and type_ is not None:
|
3025
3167
|
raise ValueError("cannot give an explicit type with an existing Var")
|
@@ -3070,35 +3212,16 @@ class QuantumCircuit:
|
|
3070
3212
|
self._ancillas.append(bit)
|
3071
3213
|
|
3072
3214
|
if isinstance(register, QuantumRegister):
|
3073
|
-
self.
|
3215
|
+
self._data.add_qreg(register)
|
3074
3216
|
|
3075
3217
|
elif isinstance(register, ClassicalRegister):
|
3076
|
-
self.
|
3077
|
-
|
3078
|
-
for idx, bit in enumerate(register):
|
3079
|
-
if bit in self._clbit_indices:
|
3080
|
-
self._clbit_indices[bit].registers.append((register, idx))
|
3081
|
-
else:
|
3082
|
-
self._data.add_clbit(bit)
|
3083
|
-
self._clbit_indices[bit] = BitLocations(
|
3084
|
-
self._data.num_clbits - 1, [(register, idx)]
|
3085
|
-
)
|
3218
|
+
self._data.add_creg(register)
|
3086
3219
|
|
3087
3220
|
elif isinstance(register, list):
|
3088
3221
|
self.add_bits(register)
|
3089
3222
|
else:
|
3090
3223
|
raise CircuitError("expected a register")
|
3091
3224
|
|
3092
|
-
def _add_qreg(self, qreg: QuantumRegister) -> None:
|
3093
|
-
self.qregs.append(qreg)
|
3094
|
-
|
3095
|
-
for idx, bit in enumerate(qreg):
|
3096
|
-
if bit in self._qubit_indices:
|
3097
|
-
self._qubit_indices[bit].registers.append((qreg, idx))
|
3098
|
-
else:
|
3099
|
-
self._data.add_qubit(bit)
|
3100
|
-
self._qubit_indices[bit] = BitLocations(self._data.num_qubits - 1, [(qreg, idx)])
|
3101
|
-
|
3102
3225
|
def add_bits(self, bits: Iterable[Bit]) -> None:
|
3103
3226
|
"""Add Bits to the circuit."""
|
3104
3227
|
duplicate_bits = {
|
@@ -3112,10 +3235,8 @@ class QuantumCircuit:
|
|
3112
3235
|
self._ancillas.append(bit)
|
3113
3236
|
if isinstance(bit, Qubit):
|
3114
3237
|
self._data.add_qubit(bit)
|
3115
|
-
self._qubit_indices[bit] = BitLocations(self._data.num_qubits - 1, [])
|
3116
3238
|
elif isinstance(bit, Clbit):
|
3117
3239
|
self._data.add_clbit(bit)
|
3118
|
-
self._clbit_indices[bit] = BitLocations(self._data.num_clbits - 1, [])
|
3119
3240
|
else:
|
3120
3241
|
raise CircuitError(
|
3121
3242
|
"Expected an instance of Qubit, Clbit, or "
|
@@ -3175,9 +3296,9 @@ class QuantumCircuit:
|
|
3175
3296
|
|
3176
3297
|
try:
|
3177
3298
|
if isinstance(bit, Qubit):
|
3178
|
-
return self._qubit_indices[bit]
|
3299
|
+
return self._data._qubit_indices[bit]
|
3179
3300
|
elif isinstance(bit, Clbit):
|
3180
|
-
return self._clbit_indices[bit]
|
3301
|
+
return self._data._clbit_indices[bit]
|
3181
3302
|
else:
|
3182
3303
|
raise CircuitError(f"Could not locate bit of unknown type: {type(bit)}")
|
3183
3304
|
except KeyError as err:
|
@@ -3187,9 +3308,7 @@ class QuantumCircuit:
|
|
3187
3308
|
|
3188
3309
|
def _check_dups(self, qubits: Sequence[Qubit]) -> None:
|
3189
3310
|
"""Raise exception if list of qubits contains duplicates."""
|
3190
|
-
|
3191
|
-
if len(squbits) != len(qubits):
|
3192
|
-
raise CircuitError("duplicate qubit arguments")
|
3311
|
+
CircuitData._check_dups(qubits)
|
3193
3312
|
|
3194
3313
|
def to_instruction(
|
3195
3314
|
self,
|
@@ -3213,6 +3332,7 @@ class QuantumCircuit:
|
|
3213
3332
|
qiskit.circuit.Instruction: a composite instruction encapsulating this circuit (can be
|
3214
3333
|
decomposed back).
|
3215
3334
|
"""
|
3335
|
+
# pylint: disable=cyclic-import
|
3216
3336
|
from qiskit.converters.circuit_to_instruction import circuit_to_instruction
|
3217
3337
|
|
3218
3338
|
return circuit_to_instruction(self, parameter_map, label=label)
|
@@ -3238,6 +3358,7 @@ class QuantumCircuit:
|
|
3238
3358
|
Returns:
|
3239
3359
|
Gate: a composite gate encapsulating this circuit (can be decomposed back).
|
3240
3360
|
"""
|
3361
|
+
# pylint: disable=cyclic-import
|
3241
3362
|
from qiskit.converters.circuit_to_gate import circuit_to_gate
|
3242
3363
|
|
3243
3364
|
return circuit_to_gate(self, parameter_map, label=label)
|
@@ -3288,7 +3409,7 @@ class QuantumCircuit:
|
|
3288
3409
|
reverse_bits: bool | None = None,
|
3289
3410
|
justify: str | None = None,
|
3290
3411
|
vertical_compression: str | None = "medium",
|
3291
|
-
idle_wires: bool | None = None,
|
3412
|
+
idle_wires: bool | str | None = None,
|
3292
3413
|
with_layout: bool = True,
|
3293
3414
|
fold: int | None = None,
|
3294
3415
|
# The type of ax is matplotlib.axes.Axes, but this is not a fixed dependency, so cannot be
|
@@ -3364,8 +3485,10 @@ class QuantumCircuit:
|
|
3364
3485
|
merges the lines generated by the `text` output so the drawing
|
3365
3486
|
will take less vertical room. Default is ``medium``. Only used by
|
3366
3487
|
the ``text`` output, will be silently ignored otherwise.
|
3367
|
-
idle_wires: Include idle wires (wires with no circuit elements)
|
3368
|
-
in output visualization.
|
3488
|
+
idle_wires: Include (or not) idle wires (wires with no circuit elements)
|
3489
|
+
in output visualization. The string ``"auto"`` is also possible, in which
|
3490
|
+
case idle wires are show except that the circuit has a layout attached.
|
3491
|
+
Default is ``"auto"`` unless the
|
3369
3492
|
user config file (usually ``~/.qiskit/settings.conf``) has an
|
3370
3493
|
alternative value set. For example, ``circuit_idle_wires = False``.
|
3371
3494
|
with_layout: Include layout information, with labels on the
|
@@ -3623,23 +3746,13 @@ class QuantumCircuit:
|
|
3623
3746
|
num_qargs = len(args)
|
3624
3747
|
else:
|
3625
3748
|
args = instruction.qubits + instruction.clbits
|
3626
|
-
num_qargs = len(args)
|
3627
|
-
1 if getattr(instruction.operation, "_condition", None) else 0
|
3628
|
-
)
|
3749
|
+
num_qargs = len(args)
|
3629
3750
|
|
3630
3751
|
if num_qargs >= 2 and not getattr(instruction.operation, "_directive", False):
|
3631
3752
|
graphs_touched = []
|
3632
3753
|
num_touched = 0
|
3633
3754
|
# Controls necessarily join all the cbits in the
|
3634
3755
|
# register that they use.
|
3635
|
-
if not unitary_only:
|
3636
|
-
for bit in instruction.operation.condition_bits:
|
3637
|
-
idx = bit_indices[bit]
|
3638
|
-
for k in range(num_sub_graphs):
|
3639
|
-
if idx in sub_graphs[k]:
|
3640
|
-
graphs_touched.append(k)
|
3641
|
-
break
|
3642
|
-
|
3643
3756
|
for item in args:
|
3644
3757
|
reg_int = bit_indices[item]
|
3645
3758
|
for k in range(num_sub_graphs):
|
@@ -3710,7 +3823,7 @@ class QuantumCircuit:
|
|
3710
3823
|
|
3711
3824
|
That structure includes:
|
3712
3825
|
|
3713
|
-
* name
|
3826
|
+
* name and other metadata
|
3714
3827
|
* global phase
|
3715
3828
|
* all the qubits and clbits, including the registers
|
3716
3829
|
* the realtime variables defined in the circuit, handled according to the ``vars`` keyword
|
@@ -3753,9 +3866,7 @@ class QuantumCircuit:
|
|
3753
3866
|
|
3754
3867
|
_copy_metadata(self, cpy, vars_mode)
|
3755
3868
|
|
3756
|
-
cpy._data =
|
3757
|
-
self._data.qubits, self._data.clbits, global_phase=self._data.global_phase
|
3758
|
-
)
|
3869
|
+
cpy._data = self._data.copy_empty_like()
|
3759
3870
|
|
3760
3871
|
if name:
|
3761
3872
|
cpy.name = name
|
@@ -3764,7 +3875,7 @@ class QuantumCircuit:
|
|
3764
3875
|
def clear(self) -> None:
|
3765
3876
|
"""Clear all instructions in self.
|
3766
3877
|
|
3767
|
-
Clearing the circuits will keep the metadata
|
3878
|
+
Clearing the circuits will keep the metadata.
|
3768
3879
|
|
3769
3880
|
.. seealso::
|
3770
3881
|
:meth:`copy_empty_like`
|
@@ -3778,10 +3889,7 @@ class QuantumCircuit:
|
|
3778
3889
|
def _create_creg(self, length: int, name: str) -> ClassicalRegister:
|
3779
3890
|
"""Creates a creg, checking if ClassicalRegister with same name exists"""
|
3780
3891
|
if name in [creg.name for creg in self.cregs]:
|
3781
|
-
|
3782
|
-
ClassicalRegister.prefix = name
|
3783
|
-
new_creg = ClassicalRegister(length)
|
3784
|
-
ClassicalRegister.prefix = save_prefix
|
3892
|
+
new_creg = ClassicalRegister._new_with_prefix(length, name)
|
3785
3893
|
else:
|
3786
3894
|
new_creg = ClassicalRegister(length, name)
|
3787
3895
|
return new_creg
|
@@ -3789,10 +3897,7 @@ class QuantumCircuit:
|
|
3789
3897
|
def _create_qreg(self, length: int, name: str) -> QuantumRegister:
|
3790
3898
|
"""Creates a qreg, checking if QuantumRegister with same name exists"""
|
3791
3899
|
if name in [qreg.name for qreg in self.qregs]:
|
3792
|
-
|
3793
|
-
QuantumRegister.prefix = name
|
3794
|
-
new_qreg = QuantumRegister(length)
|
3795
|
-
QuantumRegister.prefix = save_prefix
|
3900
|
+
new_qreg = QuantumRegister._new_with_prefix(length, name)
|
3796
3901
|
else:
|
3797
3902
|
new_qreg = QuantumRegister(length, name)
|
3798
3903
|
return new_qreg
|
@@ -3863,7 +3968,10 @@ class QuantumCircuit:
|
|
3863
3968
|
In this example, a qubit is measured and the result of that measurement is stored in the
|
3864
3969
|
classical bit (usually expressed in diagrams as a double line):
|
3865
3970
|
|
3866
|
-
..
|
3971
|
+
.. plot::
|
3972
|
+
:include-source:
|
3973
|
+
:nofigs:
|
3974
|
+
:context: reset
|
3867
3975
|
|
3868
3976
|
from qiskit import QuantumCircuit
|
3869
3977
|
circuit = QuantumCircuit(1, 1)
|
@@ -3883,12 +3991,18 @@ class QuantumCircuit:
|
|
3883
3991
|
It is possible to call ``measure`` with lists of ``qubits`` and ``cbits`` as a shortcut
|
3884
3992
|
for one-to-one measurement. These two forms produce identical results:
|
3885
3993
|
|
3886
|
-
..
|
3994
|
+
.. plot::
|
3995
|
+
:include-source:
|
3996
|
+
:nofigs:
|
3997
|
+
:context:
|
3887
3998
|
|
3888
3999
|
circuit = QuantumCircuit(2, 2)
|
3889
4000
|
circuit.measure([0,1], [0,1])
|
3890
4001
|
|
3891
|
-
..
|
4002
|
+
.. plot::
|
4003
|
+
:include-source:
|
4004
|
+
:nofigs:
|
4005
|
+
:context:
|
3892
4006
|
|
3893
4007
|
circuit = QuantumCircuit(2, 2)
|
3894
4008
|
circuit.measure(0, 0)
|
@@ -3897,7 +4011,10 @@ class QuantumCircuit:
|
|
3897
4011
|
Instead of lists, you can use :class:`~qiskit.circuit.QuantumRegister` and
|
3898
4012
|
:class:`~qiskit.circuit.ClassicalRegister` under the same logic.
|
3899
4013
|
|
3900
|
-
..
|
4014
|
+
.. plot::
|
4015
|
+
:include-source:
|
4016
|
+
:nofigs:
|
4017
|
+
:context: reset
|
3901
4018
|
|
3902
4019
|
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
|
3903
4020
|
qreg = QuantumRegister(2, "qreg")
|
@@ -3907,7 +4024,10 @@ class QuantumCircuit:
|
|
3907
4024
|
|
3908
4025
|
This is equivalent to:
|
3909
4026
|
|
3910
|
-
..
|
4027
|
+
.. plot::
|
4028
|
+
:include-source:
|
4029
|
+
:nofigs:
|
4030
|
+
:context:
|
3911
4031
|
|
3912
4032
|
circuit = QuantumCircuit(qreg, creg)
|
3913
4033
|
circuit.measure(qreg[0], creg[0])
|
@@ -3930,6 +4050,7 @@ class QuantumCircuit:
|
|
3930
4050
|
Returns:
|
3931
4051
|
QuantumCircuit: Returns circuit with measurements when ``inplace = False``.
|
3932
4052
|
"""
|
4053
|
+
# pylint: disable=cyclic-import
|
3933
4054
|
from qiskit.converters.circuit_to_dag import circuit_to_dag
|
3934
4055
|
|
3935
4056
|
if inplace:
|
@@ -3938,7 +4059,7 @@ class QuantumCircuit:
|
|
3938
4059
|
circ = self.copy()
|
3939
4060
|
dag = circuit_to_dag(circ)
|
3940
4061
|
qubits_to_measure = [qubit for qubit in circ.qubits if qubit not in dag.idle_wires()]
|
3941
|
-
new_creg = circ._create_creg(len(qubits_to_measure), "
|
4062
|
+
new_creg = circ._create_creg(len(qubits_to_measure), "meas")
|
3942
4063
|
circ.add_register(new_creg)
|
3943
4064
|
circ.barrier()
|
3944
4065
|
circ.measure(qubits_to_measure, new_creg)
|
@@ -4050,15 +4171,18 @@ class QuantumCircuit:
|
|
4050
4171
|
cregs_to_add = [creg for creg in circ.cregs if creg in kept_cregs]
|
4051
4172
|
clbits_to_add = [clbit for clbit in circ._data.clbits if clbit in kept_clbits]
|
4052
4173
|
|
4053
|
-
#
|
4054
|
-
|
4055
|
-
circ._clbit_indices = {}
|
4174
|
+
# Save the old qregs
|
4175
|
+
old_qregs = circ.qregs
|
4056
4176
|
|
4057
4177
|
# Clear instruction info
|
4058
4178
|
circ._data = CircuitData(
|
4059
4179
|
qubits=circ._data.qubits, reserve=len(circ._data), global_phase=circ.global_phase
|
4060
4180
|
)
|
4061
4181
|
|
4182
|
+
# Re-add old registers
|
4183
|
+
for qreg in old_qregs:
|
4184
|
+
circ.add_register(qreg)
|
4185
|
+
|
4062
4186
|
# We must add the clbits first to preserve the original circuit
|
4063
4187
|
# order. This way, add_register never adds clbits and just
|
4064
4188
|
# creates registers that point to them.
|
@@ -4156,7 +4280,9 @@ class QuantumCircuit:
|
|
4156
4280
|
|
4157
4281
|
The snippet below shows that insertion order of parameters does not matter.
|
4158
4282
|
|
4159
|
-
..
|
4283
|
+
.. plot::
|
4284
|
+
:include-source:
|
4285
|
+
:nofigs:
|
4160
4286
|
|
4161
4287
|
>>> from qiskit.circuit import QuantumCircuit, Parameter
|
4162
4288
|
>>> a, b, elephant = Parameter("a"), Parameter("b"), Parameter("elephant")
|
@@ -4170,7 +4296,9 @@ class QuantumCircuit:
|
|
4170
4296
|
Bear in mind that alphabetical sorting might be unintuitive when it comes to numbers.
|
4171
4297
|
The literal "10" comes before "2" in strict alphabetical sorting.
|
4172
4298
|
|
4173
|
-
..
|
4299
|
+
.. plot::
|
4300
|
+
:include-source:
|
4301
|
+
:nofigs:
|
4174
4302
|
|
4175
4303
|
>>> from qiskit.circuit import QuantumCircuit, Parameter
|
4176
4304
|
>>> angles = [Parameter("angle_1"), Parameter("angle_2"), Parameter("angle_10")]
|
@@ -4185,7 +4313,9 @@ class QuantumCircuit:
|
|
4185
4313
|
|
4186
4314
|
To respect numerical sorting, a :class:`.ParameterVector` can be used.
|
4187
4315
|
|
4188
|
-
..
|
4316
|
+
.. plot::
|
4317
|
+
:include-source:
|
4318
|
+
:nofigs:
|
4189
4319
|
|
4190
4320
|
>>> from qiskit.circuit import QuantumCircuit, Parameter, ParameterVector
|
4191
4321
|
>>> x = ParameterVector("x", 12)
|
@@ -4358,70 +4488,10 @@ class QuantumCircuit:
|
|
4358
4488
|
" the circuit."
|
4359
4489
|
)
|
4360
4490
|
|
4361
|
-
def create_mapping_view():
|
4362
|
-
return raw_mapping
|
4363
|
-
|
4364
4491
|
target._data.assign_parameters_mapping(raw_mapping)
|
4365
4492
|
else:
|
4366
|
-
# This should be a cache retrieval, since we warmed the cache. We need to keep hold of
|
4367
|
-
# what the parameters were before anything is assigned, because we assign parameters in
|
4368
|
-
# the calibrations (which aren't tracked in the internal parameter table) after, which
|
4369
|
-
# would change what we create. We don't make the full Python-space mapping object of
|
4370
|
-
# parameters to values eagerly because 99.9% of the time we don't need it, and it's
|
4371
|
-
# relatively expensive to do for large numbers of parameters.
|
4372
|
-
initial_parameters = target._data.parameters
|
4373
|
-
|
4374
|
-
def create_mapping_view():
|
4375
|
-
return dict(zip(initial_parameters, parameters))
|
4376
|
-
|
4377
4493
|
target._data.assign_parameters_iterable(parameters)
|
4378
4494
|
|
4379
|
-
# Finally, assign the parameters inside any of the calibrations. We don't track these in
|
4380
|
-
# the `ParameterTable`, so we manually reconstruct things. We lazily construct the mapping
|
4381
|
-
# `{parameter: bound_value}` the first time we encounter a binding (we have to scan for
|
4382
|
-
# this, because calibrations don't use a parameter-table lookup), rather than always paying
|
4383
|
-
# the cost - most circuits don't have parametric calibrations, and it's expensive.
|
4384
|
-
mapping_view = None
|
4385
|
-
|
4386
|
-
def map_calibration(qubits, parameters, schedule):
|
4387
|
-
# All calls to this function should share the same `{Parameter: bound_value}` mapping,
|
4388
|
-
# which we only want to lazily construct a single time.
|
4389
|
-
nonlocal mapping_view
|
4390
|
-
if mapping_view is None:
|
4391
|
-
mapping_view = create_mapping_view()
|
4392
|
-
|
4393
|
-
modified = False
|
4394
|
-
new_parameters = list(parameters)
|
4395
|
-
for i, parameter in enumerate(new_parameters):
|
4396
|
-
if not isinstance(parameter, ParameterExpression):
|
4397
|
-
continue
|
4398
|
-
if not (contained := parameter.parameters & mapping_view.keys()):
|
4399
|
-
continue
|
4400
|
-
for to_bind in contained:
|
4401
|
-
parameter = parameter.assign(to_bind, mapping_view[to_bind])
|
4402
|
-
if not parameter.parameters:
|
4403
|
-
parameter = parameter.numeric()
|
4404
|
-
if isinstance(parameter, complex):
|
4405
|
-
raise TypeError(f"Calibration cannot use complex number: '{parameter}'")
|
4406
|
-
new_parameters[i] = parameter
|
4407
|
-
modified = True
|
4408
|
-
if modified:
|
4409
|
-
schedule.assign_parameters(mapping_view)
|
4410
|
-
return (qubits, tuple(new_parameters)), schedule
|
4411
|
-
|
4412
|
-
target._calibrations = defaultdict(
|
4413
|
-
dict,
|
4414
|
-
(
|
4415
|
-
(
|
4416
|
-
gate,
|
4417
|
-
dict(
|
4418
|
-
map_calibration(qubits, parameters, schedule)
|
4419
|
-
for (qubits, parameters), schedule in calibrations.items()
|
4420
|
-
),
|
4421
|
-
)
|
4422
|
-
for gate, calibrations in target._calibrations.items()
|
4423
|
-
),
|
4424
|
-
)
|
4425
4495
|
return None if inplace else target
|
4426
4496
|
|
4427
4497
|
def _unroll_param_dict(
|
@@ -4471,17 +4541,20 @@ class QuantumCircuit:
|
|
4471
4541
|
|
4472
4542
|
def delay(
|
4473
4543
|
self,
|
4474
|
-
duration: ParameterValueType,
|
4544
|
+
duration: Union[ParameterValueType, expr.Expr],
|
4475
4545
|
qarg: QubitSpecifier | None = None,
|
4476
|
-
unit: str =
|
4546
|
+
unit: str | None = None,
|
4477
4547
|
) -> InstructionSet:
|
4478
4548
|
"""Apply :class:`~.circuit.Delay`. If qarg is ``None``, applies to all qubits.
|
4479
4549
|
When applying to multiple qubits, delays with the same duration will be created.
|
4480
4550
|
|
4481
4551
|
Args:
|
4482
|
-
duration (
|
4552
|
+
duration (Object):
|
4553
|
+
duration of the delay. If this is an :class:`~.expr.Expr`, it must be
|
4554
|
+
a constant expression of type :class:`~.types.Duration`.
|
4483
4555
|
qarg (Object): qubit argument to apply this delay.
|
4484
|
-
unit (str): unit of the duration
|
4556
|
+
unit (str | None): unit of the duration, unless ``duration`` is an :class:`~.expr.Expr`
|
4557
|
+
in which case it must not be specified. Supported units: ``'s'``, ``'ms'``, ``'us'``,
|
4485
4558
|
``'ns'``, ``'ps'``, and ``'dt'``. Default is ``'dt'``, i.e. integer time unit
|
4486
4559
|
depending on the target backend.
|
4487
4560
|
|
@@ -4660,6 +4733,198 @@ class QuantumCircuit:
|
|
4660
4733
|
copy=False,
|
4661
4734
|
)
|
4662
4735
|
|
4736
|
+
def mcrx(
|
4737
|
+
self,
|
4738
|
+
theta: ParameterValueType,
|
4739
|
+
q_controls: Sequence[QubitSpecifier],
|
4740
|
+
q_target: QubitSpecifier,
|
4741
|
+
use_basis_gates: bool = False,
|
4742
|
+
):
|
4743
|
+
"""
|
4744
|
+
Apply Multiple-Controlled X rotation gate
|
4745
|
+
|
4746
|
+
Args:
|
4747
|
+
theta: The angle of the rotation.
|
4748
|
+
q_controls: The qubits used as the controls.
|
4749
|
+
q_target: The qubit targeted by the gate.
|
4750
|
+
use_basis_gates: use p, u, cx basis gates.
|
4751
|
+
"""
|
4752
|
+
# pylint: disable=cyclic-import
|
4753
|
+
from .library.standard_gates.rx import RXGate
|
4754
|
+
from qiskit.synthesis.multi_controlled import (
|
4755
|
+
_apply_cu,
|
4756
|
+
_apply_mcu_graycode,
|
4757
|
+
_mcsu2_real_diagonal,
|
4758
|
+
)
|
4759
|
+
|
4760
|
+
control_qubits = self._qbit_argument_conversion(q_controls)
|
4761
|
+
target_qubit = self._qbit_argument_conversion(q_target)
|
4762
|
+
if len(target_qubit) != 1:
|
4763
|
+
raise QiskitError("The mcrx gate needs a single qubit as target.")
|
4764
|
+
all_qubits = control_qubits + target_qubit
|
4765
|
+
target_qubit = target_qubit[0]
|
4766
|
+
self._check_dups(all_qubits)
|
4767
|
+
|
4768
|
+
n_c = len(control_qubits)
|
4769
|
+
if n_c == 1: # cu
|
4770
|
+
_apply_cu(
|
4771
|
+
self,
|
4772
|
+
theta,
|
4773
|
+
-pi / 2,
|
4774
|
+
pi / 2,
|
4775
|
+
control_qubits[0],
|
4776
|
+
target_qubit,
|
4777
|
+
use_basis_gates=use_basis_gates,
|
4778
|
+
)
|
4779
|
+
elif n_c < 4:
|
4780
|
+
theta_step = theta * (1 / (2 ** (n_c - 1)))
|
4781
|
+
_apply_mcu_graycode(
|
4782
|
+
self,
|
4783
|
+
theta_step,
|
4784
|
+
-pi / 2,
|
4785
|
+
pi / 2,
|
4786
|
+
control_qubits,
|
4787
|
+
target_qubit,
|
4788
|
+
use_basis_gates=use_basis_gates,
|
4789
|
+
)
|
4790
|
+
else:
|
4791
|
+
cgate = _mcsu2_real_diagonal(
|
4792
|
+
RXGate(theta),
|
4793
|
+
num_controls=len(control_qubits),
|
4794
|
+
use_basis_gates=use_basis_gates,
|
4795
|
+
)
|
4796
|
+
self.compose(cgate, control_qubits + [target_qubit], inplace=True)
|
4797
|
+
|
4798
|
+
def mcry(
|
4799
|
+
self,
|
4800
|
+
theta: ParameterValueType,
|
4801
|
+
q_controls: Sequence[QubitSpecifier],
|
4802
|
+
q_target: QubitSpecifier,
|
4803
|
+
q_ancillae: QubitSpecifier | Sequence[QubitSpecifier] | None = None,
|
4804
|
+
mode: str | None = None,
|
4805
|
+
use_basis_gates: bool = False,
|
4806
|
+
):
|
4807
|
+
"""
|
4808
|
+
Apply Multiple-Controlled Y rotation gate
|
4809
|
+
|
4810
|
+
Args:
|
4811
|
+
theta: The angle of the rotation.
|
4812
|
+
q_controls: The qubits used as the controls.
|
4813
|
+
q_target: The qubit targeted by the gate.
|
4814
|
+
q_ancillae: The list of ancillary qubits.
|
4815
|
+
mode: The implementation mode to use.
|
4816
|
+
use_basis_gates: use p, u, cx basis gates
|
4817
|
+
"""
|
4818
|
+
# pylint: disable=cyclic-import
|
4819
|
+
from .library.standard_gates.ry import RYGate
|
4820
|
+
from .library.standard_gates.x import MCXGate
|
4821
|
+
from qiskit.synthesis.multi_controlled import (
|
4822
|
+
_apply_cu,
|
4823
|
+
_apply_mcu_graycode,
|
4824
|
+
_mcsu2_real_diagonal,
|
4825
|
+
)
|
4826
|
+
|
4827
|
+
control_qubits = self._qbit_argument_conversion(q_controls)
|
4828
|
+
target_qubit = self._qbit_argument_conversion(q_target)
|
4829
|
+
if len(target_qubit) != 1:
|
4830
|
+
raise QiskitError("The mcry gate needs a single qubit as target.")
|
4831
|
+
ancillary_qubits = [] if q_ancillae is None else self._qbit_argument_conversion(q_ancillae)
|
4832
|
+
all_qubits = control_qubits + target_qubit + ancillary_qubits
|
4833
|
+
target_qubit = target_qubit[0]
|
4834
|
+
self._check_dups(all_qubits)
|
4835
|
+
|
4836
|
+
# auto-select the best mode
|
4837
|
+
if mode is None:
|
4838
|
+
# if enough ancillary qubits are provided, use the 'v-chain' method
|
4839
|
+
additional_vchain = MCXGate.get_num_ancilla_qubits(len(control_qubits), "v-chain")
|
4840
|
+
if len(ancillary_qubits) >= additional_vchain:
|
4841
|
+
mode = "basic"
|
4842
|
+
else:
|
4843
|
+
mode = "noancilla"
|
4844
|
+
|
4845
|
+
if mode == "basic":
|
4846
|
+
self.ry(theta / 2, q_target)
|
4847
|
+
self.mcx(list(q_controls), q_target, q_ancillae, mode="v-chain")
|
4848
|
+
self.ry(-theta / 2, q_target)
|
4849
|
+
self.mcx(list(q_controls), q_target, q_ancillae, mode="v-chain")
|
4850
|
+
elif mode == "noancilla":
|
4851
|
+
n_c = len(control_qubits)
|
4852
|
+
if n_c == 1: # cu
|
4853
|
+
_apply_cu(
|
4854
|
+
self,
|
4855
|
+
theta,
|
4856
|
+
0,
|
4857
|
+
0,
|
4858
|
+
control_qubits[0],
|
4859
|
+
target_qubit,
|
4860
|
+
use_basis_gates=use_basis_gates,
|
4861
|
+
)
|
4862
|
+
elif n_c < 4:
|
4863
|
+
theta_step = theta * (1 / (2 ** (n_c - 1)))
|
4864
|
+
_apply_mcu_graycode(
|
4865
|
+
self,
|
4866
|
+
theta_step,
|
4867
|
+
0,
|
4868
|
+
0,
|
4869
|
+
control_qubits,
|
4870
|
+
target_qubit,
|
4871
|
+
use_basis_gates=use_basis_gates,
|
4872
|
+
)
|
4873
|
+
else:
|
4874
|
+
cgate = _mcsu2_real_diagonal(
|
4875
|
+
RYGate(theta),
|
4876
|
+
num_controls=len(control_qubits),
|
4877
|
+
use_basis_gates=use_basis_gates,
|
4878
|
+
)
|
4879
|
+
self.compose(cgate, control_qubits + [target_qubit], inplace=True)
|
4880
|
+
else:
|
4881
|
+
raise QiskitError(f"Unrecognized mode for building MCRY circuit: {mode}.")
|
4882
|
+
|
4883
|
+
def mcrz(
|
4884
|
+
self,
|
4885
|
+
lam: ParameterValueType,
|
4886
|
+
q_controls: Sequence[QubitSpecifier],
|
4887
|
+
q_target: QubitSpecifier,
|
4888
|
+
use_basis_gates: bool = False,
|
4889
|
+
):
|
4890
|
+
"""
|
4891
|
+
Apply Multiple-Controlled Z rotation gate
|
4892
|
+
|
4893
|
+
Args:
|
4894
|
+
lam: The angle of the rotation.
|
4895
|
+
q_controls: The qubits used as the controls.
|
4896
|
+
q_target: The qubit targeted by the gate.
|
4897
|
+
use_basis_gates: use p, u, cx basis gates.
|
4898
|
+
"""
|
4899
|
+
# pylint: disable=cyclic-import
|
4900
|
+
from .library.standard_gates.rz import CRZGate, RZGate
|
4901
|
+
from qiskit.synthesis.multi_controlled import _mcsu2_real_diagonal
|
4902
|
+
|
4903
|
+
control_qubits = self._qbit_argument_conversion(q_controls)
|
4904
|
+
target_qubit = self._qbit_argument_conversion(q_target)
|
4905
|
+
if len(target_qubit) != 1:
|
4906
|
+
raise QiskitError("The mcrz gate needs a single qubit as target.")
|
4907
|
+
all_qubits = control_qubits + target_qubit
|
4908
|
+
target_qubit = target_qubit[0]
|
4909
|
+
self._check_dups(all_qubits)
|
4910
|
+
|
4911
|
+
n_c = len(control_qubits)
|
4912
|
+
if n_c == 1:
|
4913
|
+
if use_basis_gates:
|
4914
|
+
self.u(0, 0, lam / 2, target_qubit)
|
4915
|
+
self.cx(control_qubits[0], target_qubit)
|
4916
|
+
self.u(0, 0, -lam / 2, target_qubit)
|
4917
|
+
self.cx(control_qubits[0], target_qubit)
|
4918
|
+
else:
|
4919
|
+
self.append(CRZGate(lam), control_qubits + [target_qubit])
|
4920
|
+
else:
|
4921
|
+
cgate = _mcsu2_real_diagonal(
|
4922
|
+
RZGate(lam),
|
4923
|
+
num_controls=len(control_qubits),
|
4924
|
+
use_basis_gates=use_basis_gates,
|
4925
|
+
)
|
4926
|
+
self.compose(cgate, control_qubits + [target_qubit], inplace=True)
|
4927
|
+
|
4663
4928
|
def r(
|
4664
4929
|
self, theta: ParameterValueType, phi: ParameterValueType, qubit: QubitSpecifier
|
4665
4930
|
) -> InstructionSet:
|
@@ -5718,7 +5983,9 @@ class QuantumCircuit:
|
|
5718
5983
|
Examples:
|
5719
5984
|
Prepare a qubit in the state :math:`(|0\rangle - |1\rangle) / \sqrt{2}`.
|
5720
5985
|
|
5721
|
-
..
|
5986
|
+
.. plot::
|
5987
|
+
:include-source:
|
5988
|
+
:nofigs:
|
5722
5989
|
|
5723
5990
|
import numpy as np
|
5724
5991
|
from qiskit import QuantumCircuit
|
@@ -5741,7 +6008,9 @@ class QuantumCircuit:
|
|
5741
6008
|
More information about labels for basis states are in
|
5742
6009
|
:meth:`.Statevector.from_label`.
|
5743
6010
|
|
5744
|
-
..
|
6011
|
+
.. plot::
|
6012
|
+
:include-source:
|
6013
|
+
:nofigs:
|
5745
6014
|
|
5746
6015
|
import numpy as np
|
5747
6016
|
from qiskit import QuantumCircuit
|
@@ -5762,7 +6031,10 @@ class QuantumCircuit:
|
|
5762
6031
|
|
5763
6032
|
|
5764
6033
|
Initialize two qubits from an array of complex amplitudes
|
5765
|
-
|
6034
|
+
|
6035
|
+
.. plot::
|
6036
|
+
:include-source:
|
6037
|
+
:nofigs:
|
5766
6038
|
|
5767
6039
|
import numpy as np
|
5768
6040
|
from qiskit import QuantumCircuit
|
@@ -5833,7 +6105,9 @@ class QuantumCircuit:
|
|
5833
6105
|
Examples:
|
5834
6106
|
Prepare a qubit in the state :math:`(|0\rangle - |1\rangle) / \sqrt{2}`.
|
5835
6107
|
|
5836
|
-
..
|
6108
|
+
.. plot::
|
6109
|
+
:include-source:
|
6110
|
+
:nofigs:
|
5837
6111
|
|
5838
6112
|
import numpy as np
|
5839
6113
|
from qiskit import QuantumCircuit
|
@@ -5856,7 +6130,9 @@ class QuantumCircuit:
|
|
5856
6130
|
More information about labels for basis states are in
|
5857
6131
|
:meth:`.Statevector.from_label`.
|
5858
6132
|
|
5859
|
-
..
|
6133
|
+
.. plot::
|
6134
|
+
:include-source:
|
6135
|
+
:nofigs:
|
5860
6136
|
|
5861
6137
|
import numpy as np
|
5862
6138
|
from qiskit import QuantumCircuit
|
@@ -5877,7 +6153,9 @@ class QuantumCircuit:
|
|
5877
6153
|
|
5878
6154
|
Initialize two qubits from an array of complex amplitudes.
|
5879
6155
|
|
5880
|
-
..
|
6156
|
+
.. plot::
|
6157
|
+
:include-source:
|
6158
|
+
:nofigs:
|
5881
6159
|
|
5882
6160
|
import numpy as np
|
5883
6161
|
from qiskit import QuantumCircuit
|
@@ -5928,7 +6206,9 @@ class QuantumCircuit:
|
|
5928
6206
|
|
5929
6207
|
Apply a gate specified by a unitary matrix to a quantum circuit
|
5930
6208
|
|
5931
|
-
..
|
6209
|
+
.. plot::
|
6210
|
+
:include-source:
|
6211
|
+
:nofigs:
|
5932
6212
|
|
5933
6213
|
from qiskit import QuantumCircuit
|
5934
6214
|
matrix = [[0, 0, 0, 1],
|
@@ -5951,6 +6231,42 @@ class QuantumCircuit:
|
|
5951
6231
|
|
5952
6232
|
return self.append(gate, qubits, [], copy=False)
|
5953
6233
|
|
6234
|
+
def noop(self, *qargs: QubitSpecifier):
|
6235
|
+
"""Mark the given qubit(s) as used within the current scope, without adding an operation.
|
6236
|
+
|
6237
|
+
This has no effect (other than raising an exception on invalid input) when called in the
|
6238
|
+
top scope of a :class:`QuantumCircuit`. Within a control-flow builder, this causes the
|
6239
|
+
qubit to be "used" by the control-flow block, if it wouldn't already be used, without adding
|
6240
|
+
any additional operations on it.
|
6241
|
+
|
6242
|
+
For example::
|
6243
|
+
|
6244
|
+
from qiskit.circuit import QuantumCircuit
|
6245
|
+
|
6246
|
+
qc = QuantumCircuit(3)
|
6247
|
+
with qc.box():
|
6248
|
+
# This control-flow block will only use qubits 0 and 1.
|
6249
|
+
qc.cx(0, 1)
|
6250
|
+
with qc.box():
|
6251
|
+
# This control-flow block will contain only the same operation as the previous
|
6252
|
+
# block, but it will also mark qubit 2 as "used" by the box.
|
6253
|
+
qc.cx(0, 1)
|
6254
|
+
qc.noop(2)
|
6255
|
+
|
6256
|
+
Args:
|
6257
|
+
*qargs: variadic list of valid qubit specifiers. Anything that can be passed as a qubit
|
6258
|
+
or collection of qubits is valid for each argument here.
|
6259
|
+
|
6260
|
+
Raises:
|
6261
|
+
CircuitError: if any requested qubit is not valid for the circuit.
|
6262
|
+
"""
|
6263
|
+
scope = self._current_scope()
|
6264
|
+
for qarg in qargs:
|
6265
|
+
for qubit in self._qbit_argument_conversion(qarg):
|
6266
|
+
# It doesn't matter if we pass duplicates along here, and the inner scope is going
|
6267
|
+
# to have to hash them to check anyway, so no point de-duplicating.
|
6268
|
+
scope.use_qubit(qubit)
|
6269
|
+
|
5954
6270
|
def _current_scope(self) -> CircuitScopeInterface:
|
5955
6271
|
if self._control_flow_scopes:
|
5956
6272
|
return self._control_flow_scopes[-1]
|
@@ -6020,6 +6336,107 @@ class QuantumCircuit:
|
|
6020
6336
|
instruction = self._data.pop()
|
6021
6337
|
return instruction
|
6022
6338
|
|
6339
|
+
def box(
|
6340
|
+
self,
|
6341
|
+
# Forbidding passing `body` by keyword is in anticipation of the constructor expanding to
|
6342
|
+
# allow `annotations` to be passed as the positional argument in the context-manager form.
|
6343
|
+
body: QuantumCircuit | None = None,
|
6344
|
+
/,
|
6345
|
+
qubits: Sequence[QubitSpecifier] | None = None,
|
6346
|
+
clbits: Sequence[ClbitSpecifier] | None = None,
|
6347
|
+
*,
|
6348
|
+
label: str | None = None,
|
6349
|
+
duration: None = None,
|
6350
|
+
unit: Literal["dt", "s", "ms", "us", "ns", "ps"] = "dt",
|
6351
|
+
):
|
6352
|
+
"""Create a ``box`` of operations on this circuit that are treated atomically in the greater
|
6353
|
+
context.
|
6354
|
+
|
6355
|
+
A "box" is a control-flow construct that is entered unconditionally. The contents of the
|
6356
|
+
box behave somewhat as if the start and end of the box were barriers (see :meth:`barrier`),
|
6357
|
+
except it is permissible to commute operations "all the way" through the box. The box is
|
6358
|
+
also an explicit scope for the purposes of variables, stretches and compiler passes.
|
6359
|
+
|
6360
|
+
There are two forms for calling this function:
|
6361
|
+
|
6362
|
+
* Pass a :class:`QuantumCircuit` positionally, and the ``qubits`` and ``clbits`` it acts
|
6363
|
+
on. In this form, a :class:`.BoxOp` is immediately created and appended using the circuit
|
6364
|
+
as the body.
|
6365
|
+
|
6366
|
+
* Use in a ``with`` statement with no ``body``, ``qubits`` or ``clbits``. This is the
|
6367
|
+
"builder-interface form", where you then use other :class:`QuantumCircuit` methods within
|
6368
|
+
the Python ``with`` scope to add instructions to the ``box``. This is the preferred form,
|
6369
|
+
and much less error prone.
|
6370
|
+
|
6371
|
+
Examples:
|
6372
|
+
|
6373
|
+
Using the builder interface to add two boxes in sequence. The two boxes in this circuit
|
6374
|
+
can execute concurrently, and the second explicitly inserts a data-flow dependency on
|
6375
|
+
qubit 8 for the duration of the box, even though the qubit is idle.
|
6376
|
+
|
6377
|
+
.. code-block:: python
|
6378
|
+
|
6379
|
+
from qiskit.circuit import QuantumCircuit
|
6380
|
+
|
6381
|
+
qc = QuantumCircuit(9)
|
6382
|
+
with qc.box():
|
6383
|
+
qc.cz(0, 1)
|
6384
|
+
qc.cz(2, 3)
|
6385
|
+
with qc.box():
|
6386
|
+
qc.cz(4, 5)
|
6387
|
+
qc.cz(6, 7)
|
6388
|
+
qc.noop(8)
|
6389
|
+
|
6390
|
+
Using the explicit construction of box. This creates the same circuit as above, and
|
6391
|
+
should give an indication why the previous form is preferred for interactive use.
|
6392
|
+
|
6393
|
+
.. code-block:: python
|
6394
|
+
|
6395
|
+
from qiskit.circuit import QuantumCircuit, BoxOp
|
6396
|
+
|
6397
|
+
body_0 = QuantumCircuit(4)
|
6398
|
+
body_0.cz(0, 1)
|
6399
|
+
body_0.cz(2, 3)
|
6400
|
+
|
6401
|
+
# Note that the qubit indices inside a body related only to the body. The
|
6402
|
+
# association with qubits in the containing circuit is made by the ``qubits``
|
6403
|
+
# argument to `QuantumCircuit.box`.
|
6404
|
+
body_1 = QuantumCircuit(5)
|
6405
|
+
body_1.cz(0, 1)
|
6406
|
+
body_1.cz(2, 3)
|
6407
|
+
|
6408
|
+
qc = QuantumCircuit(9)
|
6409
|
+
qc.box(body_0, [0, 1, 2, 3], [])
|
6410
|
+
qc.box(body_1, [4, 5, 6, 7, 8], [])
|
6411
|
+
|
6412
|
+
Args:
|
6413
|
+
body: if given, the :class:`QuantumCircuit` to use as the box's body in the explicit
|
6414
|
+
construction. Not given in the context-manager form.
|
6415
|
+
qubits: the qubits to apply the :class:`.BoxOp` to, in the explicit form.
|
6416
|
+
clbits: the qubits to apply the :class:`.BoxOp` to, in the explicit form.
|
6417
|
+
label: an optional string label for the instruction.
|
6418
|
+
duration: an optional explicit duration for the :class:`.BoxOp`. Scheduling passes are
|
6419
|
+
constrained to schedule the contained scope to match a given duration, including
|
6420
|
+
delay insertion if required.
|
6421
|
+
unit: the unit of the ``duration``.
|
6422
|
+
"""
|
6423
|
+
if isinstance(body, QuantumCircuit):
|
6424
|
+
# Explicit-body form.
|
6425
|
+
if qubits is None or clbits is None:
|
6426
|
+
raise CircuitError("When using 'box' with a body, you must pass qubits and clbits.")
|
6427
|
+
return self.append(
|
6428
|
+
BoxOp(body, duration=duration, unit=unit, label=label),
|
6429
|
+
qubits,
|
6430
|
+
clbits,
|
6431
|
+
copy=False,
|
6432
|
+
)
|
6433
|
+
# Context-manager form.
|
6434
|
+
if qubits is not None or clbits is not None:
|
6435
|
+
raise CircuitError(
|
6436
|
+
"When using 'box' as a context manager, you cannot pass qubits or clbits."
|
6437
|
+
)
|
6438
|
+
return BoxContext(self, duration=duration, unit=unit, label=label)
|
6439
|
+
|
6023
6440
|
@typing.overload
|
6024
6441
|
def while_loop(
|
6025
6442
|
self,
|
@@ -6152,7 +6569,8 @@ class QuantumCircuit:
|
|
6152
6569
|
qc.h(0)
|
6153
6570
|
qc.cx(0, 1)
|
6154
6571
|
qc.measure(0, 0)
|
6155
|
-
qc.
|
6572
|
+
with qc.if_test((0, True)):
|
6573
|
+
qc.break_loop()
|
6156
6574
|
|
6157
6575
|
Args:
|
6158
6576
|
indexset (Iterable[int]): A collection of integers to loop over. Always necessary.
|
@@ -6504,57 +6922,6 @@ class QuantumCircuit:
|
|
6504
6922
|
ContinueLoopOp(self.num_qubits, self.num_clbits), self.qubits, self.clbits, copy=False
|
6505
6923
|
)
|
6506
6924
|
|
6507
|
-
@deprecate_pulse_dependency
|
6508
|
-
def add_calibration(
|
6509
|
-
self,
|
6510
|
-
gate: Union[Gate, str],
|
6511
|
-
qubits: Sequence[int],
|
6512
|
-
# Schedule has the type `qiskit.pulse.Schedule`, but `qiskit.pulse` cannot be imported
|
6513
|
-
# while this module is, and so Sphinx will not accept a forward reference to it. Sphinx
|
6514
|
-
# needs the types available at runtime, whereas mypy will accept it, because it handles the
|
6515
|
-
# type checking by static analysis.
|
6516
|
-
schedule,
|
6517
|
-
params: Sequence[ParameterValueType] | None = None,
|
6518
|
-
) -> None:
|
6519
|
-
"""Register a low-level, custom pulse definition for the given gate.
|
6520
|
-
|
6521
|
-
Args:
|
6522
|
-
gate (Union[Gate, str]): Gate information.
|
6523
|
-
qubits (Union[int, Tuple[int]]): List of qubits to be measured.
|
6524
|
-
schedule (Schedule): Schedule information.
|
6525
|
-
params (Optional[List[Union[float, Parameter]]]): A list of parameters.
|
6526
|
-
|
6527
|
-
Raises:
|
6528
|
-
Exception: if the gate is of type string and params is None.
|
6529
|
-
"""
|
6530
|
-
|
6531
|
-
def _format(operand):
|
6532
|
-
try:
|
6533
|
-
# Using float/complex value as a dict key is not good idea.
|
6534
|
-
# This makes the mapping quite sensitive to the rounding error.
|
6535
|
-
# However, the mechanism is already tied to the execution model (i.e. pulse gate)
|
6536
|
-
# and we cannot easily update this rule.
|
6537
|
-
# The same logic exists in DAGCircuit.add_calibration.
|
6538
|
-
evaluated = complex(operand)
|
6539
|
-
if np.isreal(evaluated):
|
6540
|
-
evaluated = float(evaluated.real)
|
6541
|
-
if evaluated.is_integer():
|
6542
|
-
evaluated = int(evaluated)
|
6543
|
-
return evaluated
|
6544
|
-
except TypeError:
|
6545
|
-
# Unassigned parameter
|
6546
|
-
return operand
|
6547
|
-
|
6548
|
-
if isinstance(gate, Gate):
|
6549
|
-
params = gate.params
|
6550
|
-
gate = gate.name
|
6551
|
-
if params is not None:
|
6552
|
-
params = tuple(map(_format, params))
|
6553
|
-
else:
|
6554
|
-
params = ()
|
6555
|
-
|
6556
|
-
self._calibrations[gate][(tuple(qubits), params)] = schedule
|
6557
|
-
|
6558
6925
|
# Functions only for scheduled circuits
|
6559
6926
|
def qubit_duration(self, *qubits: Union[Qubit, int]) -> float:
|
6560
6927
|
"""Return the duration between the start and stop time of the first and last instructions,
|
@@ -6584,7 +6951,7 @@ class QuantumCircuit:
|
|
6584
6951
|
Raises:
|
6585
6952
|
CircuitError: if ``self`` is a not-yet scheduled circuit.
|
6586
6953
|
"""
|
6587
|
-
if self.
|
6954
|
+
if self._duration is None:
|
6588
6955
|
# circuit has only delays, this is kind of scheduled
|
6589
6956
|
for instruction in self._data:
|
6590
6957
|
if not isinstance(instruction.operation, Delay):
|
@@ -6626,7 +6993,7 @@ class QuantumCircuit:
|
|
6626
6993
|
Raises:
|
6627
6994
|
CircuitError: if ``self`` is a not-yet scheduled circuit.
|
6628
6995
|
"""
|
6629
|
-
if self.
|
6996
|
+
if self._duration is None:
|
6630
6997
|
# circuit has only delays, this is kind of scheduled
|
6631
6998
|
for instruction in self._data:
|
6632
6999
|
if not isinstance(instruction.operation, Delay):
|
@@ -6637,7 +7004,7 @@ class QuantumCircuit:
|
|
6637
7004
|
|
6638
7005
|
qubits = [self.qubits[q] if isinstance(q, int) else q for q in qubits]
|
6639
7006
|
|
6640
|
-
stops = {q: self.
|
7007
|
+
stops = {q: self._duration for q in qubits}
|
6641
7008
|
dones = {q: False for q in qubits}
|
6642
7009
|
for instruction in reversed(self._data):
|
6643
7010
|
for q in qubits:
|
@@ -6740,8 +7107,7 @@ class _OuterCircuitScopeInterface(CircuitScopeInterface):
|
|
6740
7107
|
def resolve_classical_resource(self, specifier):
|
6741
7108
|
# This is slightly different to cbit_argument_conversion, because it should not
|
6742
7109
|
# unwrap :obj:`.ClassicalRegister` instances into lists, and in general it should not allow
|
6743
|
-
# iterables or broadcasting.
|
6744
|
-
# :meth:`.InstructionSet.c_if` to check the validity of their arguments.
|
7110
|
+
# iterables or broadcasting.
|
6745
7111
|
if isinstance(specifier, Clbit):
|
6746
7112
|
if specifier not in self.circuit._clbit_indices:
|
6747
7113
|
raise CircuitError(f"Clbit {specifier} is not present in this circuit.")
|
@@ -6765,9 +7131,16 @@ class _OuterCircuitScopeInterface(CircuitScopeInterface):
|
|
6765
7131
|
var = self.circuit._prepare_new_var(var, None)
|
6766
7132
|
self.circuit._vars_local[var.name] = var
|
6767
7133
|
|
7134
|
+
def add_stretch(self, stretch):
|
7135
|
+
stretch = self.circuit._prepare_new_stretch(stretch)
|
7136
|
+
self.circuit._stretches_local[stretch.name] = stretch
|
7137
|
+
|
6768
7138
|
def remove_var(self, var):
|
6769
7139
|
self.circuit._vars_local.pop(var.name)
|
6770
7140
|
|
7141
|
+
def remove_stretch(self, stretch):
|
7142
|
+
self.circuit._stretches_local.pop(stretch.name)
|
7143
|
+
|
6771
7144
|
def get_var(self, name):
|
6772
7145
|
if (out := self.circuit._vars_local.get(name)) is not None:
|
6773
7146
|
return out
|
@@ -6775,97 +7148,45 @@ class _OuterCircuitScopeInterface(CircuitScopeInterface):
|
|
6775
7148
|
return out
|
6776
7149
|
return self.circuit._vars_input.get(name)
|
6777
7150
|
|
7151
|
+
def get_stretch(self, name):
|
7152
|
+
if (out := self.circuit._stretches_local.get(name)) is not None:
|
7153
|
+
return out
|
7154
|
+
return self.circuit._stretches_capture.get(name)
|
7155
|
+
|
6778
7156
|
def use_var(self, var):
|
6779
7157
|
if self.get_var(var.name) != var:
|
6780
7158
|
raise CircuitError(f"'{var}' is not present in this circuit")
|
6781
7159
|
|
7160
|
+
def use_stretch(self, stretch):
|
7161
|
+
if self.get_stretch(stretch.name) != stretch:
|
7162
|
+
raise CircuitError(f"'{stretch}' is not present in this circuit")
|
7163
|
+
|
7164
|
+
def use_qubit(self, qubit):
|
7165
|
+
# Since the qubit is guaranteed valid, there's nothing for us to do.
|
7166
|
+
pass
|
7167
|
+
|
6782
7168
|
|
6783
7169
|
def _validate_expr(circuit_scope: CircuitScopeInterface, node: expr.Expr) -> expr.Expr:
|
6784
7170
|
# This takes the `circuit_scope` object as an argument rather than being a circuit method and
|
6785
7171
|
# inferring it because we may want to call this several times, and we almost invariably already
|
6786
7172
|
# need the interface implementation for something else anyway.
|
6787
|
-
|
6788
|
-
|
6789
|
-
|
7173
|
+
# If we're not in a capturing scope (i.e. we're in the root scope), then the
|
7174
|
+
# `use_{var,stretch}` calls are no-ops.
|
7175
|
+
for ident in set(expr.iter_identifiers(node)):
|
7176
|
+
if isinstance(ident, expr.Stretch):
|
7177
|
+
circuit_scope.use_stretch(ident)
|
6790
7178
|
else:
|
6791
|
-
|
7179
|
+
if ident.standalone:
|
7180
|
+
circuit_scope.use_var(ident)
|
7181
|
+
else:
|
7182
|
+
circuit_scope.resolve_classical_resource(ident.var)
|
6792
7183
|
return node
|
6793
7184
|
|
6794
7185
|
|
6795
|
-
def _bit_argument_conversion(specifier, bit_sequence, bit_set, type_) -> list[Bit]:
|
6796
|
-
"""Get the list of bits referred to by the specifier ``specifier``.
|
6797
|
-
|
6798
|
-
Valid types for ``specifier`` are integers, bits of the correct type (as given in ``type_``), or
|
6799
|
-
iterables of one of those two scalar types. Integers are interpreted as indices into the
|
6800
|
-
sequence ``bit_sequence``. All allowed bits must be in ``bit_set`` (which should implement
|
6801
|
-
fast lookup), which is assumed to contain the same bits as ``bit_sequence``.
|
6802
|
-
|
6803
|
-
Returns:
|
6804
|
-
List[Bit]: a list of the specified bits from ``bits``.
|
6805
|
-
|
6806
|
-
Raises:
|
6807
|
-
CircuitError: if an incorrect type or index is encountered, if the same bit is specified
|
6808
|
-
more than once, or if the specifier is to a bit not in the ``bit_set``.
|
6809
|
-
"""
|
6810
|
-
# The duplication between this function and `_bit_argument_conversion_scalar` is so that fast
|
6811
|
-
# paths return as quickly as possible, and all valid specifiers will resolve without needing to
|
6812
|
-
# try/catch exceptions (which is too slow for inner-loop code).
|
6813
|
-
if isinstance(specifier, type_):
|
6814
|
-
if specifier in bit_set:
|
6815
|
-
return [specifier]
|
6816
|
-
raise CircuitError(f"Bit '{specifier}' is not in the circuit.")
|
6817
|
-
if isinstance(specifier, (int, np.integer)):
|
6818
|
-
try:
|
6819
|
-
return [bit_sequence[specifier]]
|
6820
|
-
except IndexError as ex:
|
6821
|
-
raise CircuitError(
|
6822
|
-
f"Index {specifier} out of range for size {len(bit_sequence)}."
|
6823
|
-
) from ex
|
6824
|
-
# Slices can't raise IndexError - they just return an empty list.
|
6825
|
-
if isinstance(specifier, slice):
|
6826
|
-
return bit_sequence[specifier]
|
6827
|
-
try:
|
6828
|
-
return [
|
6829
|
-
_bit_argument_conversion_scalar(index, bit_sequence, bit_set, type_)
|
6830
|
-
for index in specifier
|
6831
|
-
]
|
6832
|
-
except TypeError as ex:
|
6833
|
-
message = (
|
6834
|
-
f"Incorrect bit type: expected '{type_.__name__}' but got '{type(specifier).__name__}'"
|
6835
|
-
if isinstance(specifier, Bit)
|
6836
|
-
else f"Invalid bit index: '{specifier}' of type '{type(specifier)}'"
|
6837
|
-
)
|
6838
|
-
raise CircuitError(message) from ex
|
6839
|
-
|
6840
|
-
|
6841
|
-
def _bit_argument_conversion_scalar(specifier, bit_sequence, bit_set, type_):
|
6842
|
-
if isinstance(specifier, type_):
|
6843
|
-
if specifier in bit_set:
|
6844
|
-
return specifier
|
6845
|
-
raise CircuitError(f"Bit '{specifier}' is not in the circuit.")
|
6846
|
-
if isinstance(specifier, (int, np.integer)):
|
6847
|
-
try:
|
6848
|
-
return bit_sequence[specifier]
|
6849
|
-
except IndexError as ex:
|
6850
|
-
raise CircuitError(
|
6851
|
-
f"Index {specifier} out of range for size {len(bit_sequence)}."
|
6852
|
-
) from ex
|
6853
|
-
message = (
|
6854
|
-
f"Incorrect bit type: expected '{type_.__name__}' but got '{type(specifier).__name__}'"
|
6855
|
-
if isinstance(specifier, Bit)
|
6856
|
-
else f"Invalid bit index: '{specifier}' of type '{type(specifier)}'"
|
6857
|
-
)
|
6858
|
-
raise CircuitError(message)
|
6859
|
-
|
6860
|
-
|
6861
7186
|
def _copy_metadata(original, cpy, vars_mode):
|
6862
7187
|
# copy registers correctly, in copy.copy they are only copied via reference
|
6863
|
-
cpy.qregs = original.qregs.copy()
|
6864
|
-
cpy.cregs = original.cregs.copy()
|
6865
7188
|
cpy._builder_api = _OuterCircuitScopeInterface(cpy)
|
6866
7189
|
cpy._ancillas = original._ancillas.copy()
|
6867
|
-
cpy._qubit_indices = original._qubit_indices.copy()
|
6868
|
-
cpy._clbit_indices = original._clbit_indices.copy()
|
6869
7190
|
|
6870
7191
|
if vars_mode == "alike":
|
6871
7192
|
# Note that this causes the local variables to be uninitialised, because the stores are
|
@@ -6874,16 +7195,21 @@ def _copy_metadata(original, cpy, vars_mode):
|
|
6874
7195
|
cpy._vars_local = original._vars_local.copy()
|
6875
7196
|
cpy._vars_input = original._vars_input.copy()
|
6876
7197
|
cpy._vars_capture = original._vars_capture.copy()
|
7198
|
+
cpy._stretches_local = original._stretches_local.copy()
|
7199
|
+
cpy._stretches_capture = original._stretches_capture.copy()
|
6877
7200
|
elif vars_mode == "captures":
|
6878
7201
|
cpy._vars_local = {}
|
6879
7202
|
cpy._vars_input = {}
|
6880
7203
|
cpy._vars_capture = {var.name: var for var in original.iter_vars()}
|
7204
|
+
cpy._stretches_local = {}
|
7205
|
+
cpy._stretches_capture = {stretch.name: stretch for stretch in original.iter_stretches()}
|
6881
7206
|
elif vars_mode == "drop":
|
6882
7207
|
cpy._vars_local = {}
|
6883
7208
|
cpy._vars_input = {}
|
6884
7209
|
cpy._vars_capture = {}
|
7210
|
+
cpy._stretches_local = {}
|
7211
|
+
cpy._stretches_capture = {}
|
6885
7212
|
else: # pragma: no cover
|
6886
7213
|
raise ValueError(f"unknown vars_mode: '{vars_mode}'")
|
6887
7214
|
|
6888
|
-
cpy._calibrations = _copy.deepcopy(original._calibrations)
|
6889
7215
|
cpy._metadata = _copy.deepcopy(original._metadata)
|