qiskit 1.0.2__cp38-abi3-macosx_11_0_arm64.whl → 1.1.0rc1__cp38-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 +27 -16
- qiskit/_accelerate.abi3.so +0 -0
- qiskit/_numpy_compat.py +73 -0
- qiskit/assembler/disassemble.py +5 -6
- qiskit/circuit/__init__.py +1131 -169
- qiskit/circuit/_classical_resource_map.py +7 -6
- qiskit/circuit/_utils.py +18 -8
- qiskit/circuit/annotated_operation.py +21 -0
- qiskit/circuit/barrier.py +10 -13
- qiskit/circuit/bit.py +0 -1
- qiskit/circuit/classical/__init__.py +2 -2
- qiskit/circuit/classical/expr/__init__.py +39 -5
- qiskit/circuit/classical/expr/constructors.py +84 -1
- qiskit/circuit/classical/expr/expr.py +83 -13
- qiskit/circuit/classical/expr/visitors.py +83 -0
- qiskit/circuit/commutation_checker.py +86 -51
- qiskit/circuit/controlflow/_builder_utils.py +9 -1
- qiskit/circuit/controlflow/break_loop.py +8 -22
- qiskit/circuit/controlflow/builder.py +116 -1
- qiskit/circuit/controlflow/continue_loop.py +8 -22
- qiskit/circuit/controlflow/control_flow.py +47 -8
- qiskit/circuit/controlflow/for_loop.py +8 -23
- qiskit/circuit/controlflow/if_else.py +13 -27
- qiskit/circuit/controlflow/switch_case.py +14 -21
- qiskit/circuit/controlflow/while_loop.py +9 -23
- qiskit/circuit/controlledgate.py +2 -2
- qiskit/circuit/delay.py +7 -5
- qiskit/circuit/gate.py +20 -7
- qiskit/circuit/instruction.py +31 -30
- qiskit/circuit/instructionset.py +9 -22
- qiskit/circuit/library/__init__.py +8 -2
- qiskit/circuit/library/arithmetic/integer_comparator.py +2 -2
- qiskit/circuit/library/arithmetic/quadratic_form.py +3 -2
- qiskit/circuit/library/blueprintcircuit.py +29 -7
- qiskit/circuit/library/data_preparation/state_preparation.py +6 -5
- qiskit/circuit/library/generalized_gates/diagonal.py +5 -4
- qiskit/circuit/library/generalized_gates/isometry.py +51 -254
- qiskit/circuit/library/generalized_gates/pauli.py +2 -2
- qiskit/circuit/library/generalized_gates/permutation.py +4 -1
- qiskit/circuit/library/generalized_gates/rv.py +15 -11
- qiskit/circuit/library/generalized_gates/uc.py +2 -98
- qiskit/circuit/library/generalized_gates/unitary.py +9 -4
- qiskit/circuit/library/hamiltonian_gate.py +11 -5
- qiskit/circuit/library/n_local/efficient_su2.py +5 -5
- qiskit/circuit/library/n_local/n_local.py +100 -49
- qiskit/circuit/library/n_local/two_local.py +3 -59
- qiskit/circuit/library/overlap.py +3 -3
- qiskit/circuit/library/phase_oracle.py +1 -1
- qiskit/circuit/library/quantum_volume.py +39 -38
- qiskit/circuit/library/standard_gates/equivalence_library.py +50 -0
- qiskit/circuit/library/standard_gates/global_phase.py +4 -2
- qiskit/circuit/library/standard_gates/i.py +1 -2
- qiskit/circuit/library/standard_gates/iswap.py +1 -2
- qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +11 -5
- qiskit/circuit/library/standard_gates/p.py +31 -15
- qiskit/circuit/library/standard_gates/r.py +4 -3
- qiskit/circuit/library/standard_gates/rx.py +7 -4
- qiskit/circuit/library/standard_gates/rxx.py +4 -3
- qiskit/circuit/library/standard_gates/ry.py +7 -4
- qiskit/circuit/library/standard_gates/ryy.py +4 -3
- qiskit/circuit/library/standard_gates/rz.py +7 -4
- qiskit/circuit/library/standard_gates/rzx.py +4 -3
- qiskit/circuit/library/standard_gates/rzz.py +4 -3
- qiskit/circuit/library/standard_gates/s.py +4 -8
- qiskit/circuit/library/standard_gates/t.py +2 -4
- qiskit/circuit/library/standard_gates/u.py +16 -11
- qiskit/circuit/library/standard_gates/u1.py +6 -2
- qiskit/circuit/library/standard_gates/u2.py +4 -2
- qiskit/circuit/library/standard_gates/u3.py +9 -5
- qiskit/circuit/library/standard_gates/x.py +22 -11
- qiskit/circuit/library/standard_gates/xx_minus_yy.py +4 -3
- qiskit/circuit/library/standard_gates/xx_plus_yy.py +7 -5
- qiskit/circuit/library/standard_gates/z.py +1 -2
- qiskit/circuit/measure.py +4 -1
- qiskit/circuit/operation.py +13 -8
- qiskit/circuit/parameter.py +11 -6
- qiskit/circuit/quantumcircuit.py +864 -128
- qiskit/circuit/quantumcircuitdata.py +2 -2
- qiskit/circuit/reset.py +5 -2
- qiskit/circuit/store.py +95 -0
- qiskit/compiler/assembler.py +22 -22
- qiskit/compiler/transpiler.py +63 -112
- qiskit/converters/circuit_to_dag.py +7 -0
- qiskit/converters/circuit_to_dagdependency_v2.py +47 -0
- qiskit/converters/circuit_to_gate.py +2 -0
- qiskit/converters/circuit_to_instruction.py +22 -0
- qiskit/converters/dag_to_circuit.py +4 -0
- qiskit/converters/dag_to_dagdependency_v2.py +44 -0
- qiskit/dagcircuit/collect_blocks.py +15 -10
- qiskit/dagcircuit/dagcircuit.py +434 -124
- qiskit/dagcircuit/dagdependency.py +19 -12
- qiskit/dagcircuit/dagdependency_v2.py +641 -0
- qiskit/dagcircuit/dagdepnode.py +19 -16
- qiskit/dagcircuit/dagnode.py +14 -4
- qiskit/primitives/__init__.py +12 -8
- qiskit/primitives/backend_estimator.py +3 -5
- qiskit/primitives/backend_estimator_v2.py +410 -0
- qiskit/primitives/backend_sampler_v2.py +287 -0
- qiskit/primitives/base/base_estimator.py +4 -9
- qiskit/primitives/base/base_sampler.py +2 -2
- qiskit/primitives/containers/__init__.py +5 -4
- qiskit/primitives/containers/bit_array.py +292 -2
- qiskit/primitives/containers/data_bin.py +123 -50
- qiskit/primitives/containers/estimator_pub.py +10 -3
- qiskit/primitives/containers/observables_array.py +2 -2
- qiskit/primitives/containers/pub_result.py +1 -1
- qiskit/primitives/containers/sampler_pub.py +19 -3
- qiskit/primitives/containers/sampler_pub_result.py +74 -0
- qiskit/primitives/containers/shape.py +1 -1
- qiskit/primitives/statevector_estimator.py +4 -4
- qiskit/primitives/statevector_sampler.py +7 -12
- qiskit/providers/__init__.py +17 -18
- qiskit/providers/backend.py +2 -2
- qiskit/providers/backend_compat.py +8 -10
- qiskit/providers/basic_provider/basic_provider_tools.py +67 -31
- qiskit/providers/basic_provider/basic_simulator.py +81 -21
- qiskit/providers/fake_provider/fake_1q.py +1 -1
- qiskit/providers/fake_provider/fake_backend.py +3 -408
- qiskit/providers/fake_provider/generic_backend_v2.py +26 -14
- qiskit/providers/provider.py +16 -0
- qiskit/pulse/builder.py +4 -1
- qiskit/pulse/parameter_manager.py +60 -4
- qiskit/pulse/schedule.py +29 -13
- qiskit/pulse/utils.py +61 -20
- qiskit/qasm2/__init__.py +1 -5
- qiskit/qasm2/parse.py +1 -4
- qiskit/qasm3/__init__.py +42 -5
- qiskit/qasm3/ast.py +19 -0
- qiskit/qasm3/exporter.py +178 -106
- qiskit/qasm3/printer.py +27 -5
- qiskit/qpy/__init__.py +247 -13
- qiskit/qpy/binary_io/circuits.py +216 -47
- qiskit/qpy/binary_io/schedules.py +42 -36
- qiskit/qpy/binary_io/value.py +201 -22
- qiskit/qpy/common.py +1 -1
- qiskit/qpy/exceptions.py +20 -0
- qiskit/qpy/formats.py +29 -0
- qiskit/qpy/type_keys.py +21 -0
- qiskit/quantum_info/analysis/distance.py +3 -3
- qiskit/quantum_info/analysis/make_observable.py +2 -1
- qiskit/quantum_info/analysis/z2_symmetries.py +2 -1
- qiskit/quantum_info/operators/channel/chi.py +9 -8
- qiskit/quantum_info/operators/channel/choi.py +10 -9
- qiskit/quantum_info/operators/channel/kraus.py +2 -1
- qiskit/quantum_info/operators/channel/ptm.py +10 -9
- qiskit/quantum_info/operators/channel/quantum_channel.py +2 -1
- qiskit/quantum_info/operators/channel/stinespring.py +2 -1
- qiskit/quantum_info/operators/channel/superop.py +12 -11
- qiskit/quantum_info/operators/channel/transformations.py +12 -11
- qiskit/quantum_info/operators/dihedral/dihedral.py +5 -4
- qiskit/quantum_info/operators/operator.py +43 -30
- qiskit/quantum_info/operators/scalar_op.py +10 -9
- qiskit/quantum_info/operators/symplectic/base_pauli.py +70 -59
- qiskit/quantum_info/operators/symplectic/clifford.py +36 -9
- qiskit/quantum_info/operators/symplectic/pauli.py +48 -4
- qiskit/quantum_info/operators/symplectic/pauli_list.py +36 -14
- qiskit/quantum_info/operators/symplectic/random.py +3 -2
- qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +54 -33
- qiskit/quantum_info/states/densitymatrix.py +13 -13
- qiskit/quantum_info/states/stabilizerstate.py +3 -3
- qiskit/quantum_info/states/statevector.py +14 -13
- qiskit/quantum_info/states/utils.py +5 -3
- qiskit/result/mitigation/correlated_readout_mitigator.py +3 -2
- qiskit/result/mitigation/local_readout_mitigator.py +2 -1
- qiskit/result/mitigation/utils.py +3 -2
- qiskit/synthesis/__init__.py +2 -0
- qiskit/synthesis/discrete_basis/commutator_decompose.py +2 -2
- qiskit/synthesis/evolution/lie_trotter.py +7 -14
- qiskit/synthesis/evolution/qdrift.py +3 -4
- qiskit/synthesis/linear/cnot_synth.py +1 -3
- qiskit/synthesis/linear/linear_circuits_utils.py +1 -1
- qiskit/synthesis/linear_phase/cz_depth_lnn.py +4 -18
- qiskit/synthesis/permutation/__init__.py +1 -0
- qiskit/synthesis/permutation/permutation_reverse_lnn.py +90 -0
- qiskit/synthesis/qft/qft_decompose_lnn.py +2 -6
- qiskit/synthesis/two_qubit/two_qubit_decompose.py +165 -954
- qiskit/synthesis/two_qubit/xx_decompose/circuits.py +13 -12
- qiskit/synthesis/two_qubit/xx_decompose/decomposer.py +7 -1
- qiskit/synthesis/unitary/aqc/__init__.py +1 -1
- qiskit/synthesis/unitary/aqc/cnot_structures.py +2 -1
- qiskit/synthesis/unitary/aqc/fast_gradient/fast_gradient.py +2 -1
- qiskit/synthesis/unitary/qsd.py +3 -2
- qiskit/transpiler/__init__.py +7 -3
- qiskit/transpiler/layout.py +140 -61
- qiskit/transpiler/passes/__init__.py +6 -0
- qiskit/transpiler/passes/basis/basis_translator.py +7 -2
- qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
- qiskit/transpiler/passes/basis/unroll_custom_definitions.py +1 -1
- qiskit/transpiler/passes/calibration/rzx_builder.py +2 -1
- qiskit/transpiler/passes/layout/apply_layout.py +8 -3
- qiskit/transpiler/passes/layout/sabre_layout.py +15 -3
- qiskit/transpiler/passes/layout/set_layout.py +1 -1
- qiskit/transpiler/passes/optimization/__init__.py +2 -0
- qiskit/transpiler/passes/optimization/commutation_analysis.py +2 -2
- qiskit/transpiler/passes/optimization/commutative_cancellation.py +1 -1
- qiskit/transpiler/passes/optimization/consolidate_blocks.py +1 -1
- qiskit/transpiler/passes/optimization/cx_cancellation.py +10 -0
- qiskit/transpiler/passes/optimization/elide_permutations.py +114 -0
- qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +9 -3
- qiskit/transpiler/passes/optimization/optimize_annotated.py +248 -12
- qiskit/transpiler/passes/optimization/remove_final_reset.py +37 -0
- qiskit/transpiler/passes/optimization/template_matching/forward_match.py +1 -3
- qiskit/transpiler/passes/routing/__init__.py +1 -0
- qiskit/transpiler/passes/routing/basic_swap.py +13 -2
- qiskit/transpiler/passes/routing/lookahead_swap.py +7 -1
- qiskit/transpiler/passes/routing/sabre_swap.py +10 -6
- qiskit/transpiler/passes/routing/star_prerouting.py +417 -0
- qiskit/transpiler/passes/routing/stochastic_swap.py +24 -8
- qiskit/transpiler/passes/scheduling/__init__.py +1 -1
- qiskit/transpiler/passes/scheduling/alap.py +1 -2
- qiskit/transpiler/passes/scheduling/alignments/align_measures.py +1 -2
- qiskit/transpiler/passes/scheduling/alignments/check_durations.py +9 -6
- qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +8 -0
- qiskit/transpiler/passes/scheduling/alignments/reschedule.py +13 -4
- qiskit/transpiler/passes/scheduling/asap.py +1 -2
- qiskit/transpiler/passes/scheduling/base_scheduler.py +21 -2
- qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +26 -4
- qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +24 -2
- qiskit/transpiler/passes/scheduling/time_unit_conversion.py +28 -4
- qiskit/transpiler/passes/synthesis/aqc_plugin.py +2 -2
- qiskit/transpiler/passes/synthesis/high_level_synthesis.py +120 -13
- qiskit/transpiler/passes/synthesis/unitary_synthesis.py +162 -55
- qiskit/transpiler/passes/utils/gates_basis.py +3 -3
- qiskit/transpiler/passmanager.py +44 -1
- qiskit/transpiler/preset_passmanagers/__init__.py +3 -3
- qiskit/transpiler/preset_passmanagers/builtin_plugins.py +34 -16
- qiskit/transpiler/preset_passmanagers/common.py +4 -6
- qiskit/transpiler/preset_passmanagers/plugin.py +9 -1
- qiskit/utils/optionals.py +6 -2
- qiskit/visualization/array.py +1 -1
- qiskit/visualization/bloch.py +2 -3
- qiskit/visualization/circuit/matplotlib.py +44 -14
- qiskit/visualization/circuit/text.py +38 -18
- qiskit/visualization/counts_visualization.py +3 -6
- qiskit/visualization/dag_visualization.py +6 -7
- qiskit/visualization/pulse_v2/interface.py +8 -3
- qiskit/visualization/state_visualization.py +3 -2
- qiskit/visualization/timeline/interface.py +18 -8
- {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/METADATA +12 -8
- {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/RECORD +245 -235
- {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/WHEEL +1 -1
- qiskit/_qasm2.abi3.so +0 -0
- qiskit/_qasm3.abi3.so +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/LICENSE.txt +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/entry_points.txt +0 -0
- {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/top_level.txt +0 -0
@@ -16,11 +16,15 @@ from functools import lru_cache
|
|
16
16
|
from typing import List, Union
|
17
17
|
import numpy as np
|
18
18
|
|
19
|
+
from qiskit import QiskitError
|
19
20
|
from qiskit.circuit import Qubit
|
20
21
|
from qiskit.circuit.operation import Operation
|
21
|
-
from qiskit.circuit.controlflow import
|
22
|
+
from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES
|
22
23
|
from qiskit.quantum_info.operators import Operator
|
23
24
|
|
25
|
+
_skipped_op_names = {"measure", "reset", "delay", "initialize"}
|
26
|
+
_no_cache_op_names = {"annotated"}
|
27
|
+
|
24
28
|
|
25
29
|
@lru_cache(maxsize=None)
|
26
30
|
def _identity_op(num_qubits):
|
@@ -94,8 +98,11 @@ class CommutationChecker:
|
|
94
98
|
)
|
95
99
|
first_op, first_qargs, _ = first_op_tuple
|
96
100
|
second_op, second_qargs, _ = second_op_tuple
|
97
|
-
|
98
|
-
|
101
|
+
|
102
|
+
skip_cache = first_op.name in _no_cache_op_names or second_op.name in _no_cache_op_names
|
103
|
+
|
104
|
+
if skip_cache:
|
105
|
+
return _commute_matmul(first_op, first_qargs, second_op, second_qargs)
|
99
106
|
|
100
107
|
commutation_lookup = self.check_commutation_entries(
|
101
108
|
first_op, first_qargs, second_op, second_qargs
|
@@ -113,6 +120,8 @@ class CommutationChecker:
|
|
113
120
|
if self._current_cache_entries >= self._cache_max_entries:
|
114
121
|
self.clear_cached_commutations()
|
115
122
|
|
123
|
+
first_params = getattr(first_op, "params", [])
|
124
|
+
second_params = getattr(second_op, "params", [])
|
116
125
|
if len(first_params) > 0 or len(second_params) > 0:
|
117
126
|
self._cached_commutations.setdefault((first_op.name, second_op.name), {}).setdefault(
|
118
127
|
_get_relative_placement(first_qargs, second_qargs), {}
|
@@ -184,7 +193,11 @@ class CommutationChecker:
|
|
184
193
|
|
185
194
|
|
186
195
|
def _hashable_parameters(params):
|
187
|
-
"""Convert the parameters of a gate into a hashable format for lookup in a dictionary.
|
196
|
+
"""Convert the parameters of a gate into a hashable format for lookup in a dictionary.
|
197
|
+
|
198
|
+
This aims to be fast in common cases, and is not intended to work outside of the lifetime of a
|
199
|
+
single commutation pass; it does not handle mutable state correctly if the state is actually
|
200
|
+
changed."""
|
188
201
|
try:
|
189
202
|
hash(params)
|
190
203
|
return params
|
@@ -201,7 +214,53 @@ def _hashable_parameters(params):
|
|
201
214
|
return ("fallback", str(params))
|
202
215
|
|
203
216
|
|
204
|
-
|
217
|
+
def is_commutation_supported(op):
|
218
|
+
"""
|
219
|
+
Filter operations whose commutation is not supported due to bugs in transpiler passes invoking
|
220
|
+
commutation analysis.
|
221
|
+
Args:
|
222
|
+
op (Operation): operation to be checked for commutation relation
|
223
|
+
Return:
|
224
|
+
True if determining the commutation of op is currently supported
|
225
|
+
"""
|
226
|
+
# Bug in CommutativeCancellation, e.g. see gh-8553
|
227
|
+
if getattr(op, "condition", False):
|
228
|
+
return False
|
229
|
+
|
230
|
+
# Commutation of ControlFlow gates also not supported yet. This may be pending a control flow graph.
|
231
|
+
if op.name in CONTROL_FLOW_OP_NAMES:
|
232
|
+
return False
|
233
|
+
|
234
|
+
return True
|
235
|
+
|
236
|
+
|
237
|
+
def is_commutation_skipped(op, qargs, max_num_qubits):
|
238
|
+
"""
|
239
|
+
Filter operations whose commutation will not be determined.
|
240
|
+
Args:
|
241
|
+
op (Operation): operation to be checked for commutation relation
|
242
|
+
qargs (List): operation qubits
|
243
|
+
max_num_qubits (int): the maximum number of qubits to consider, the check may be skipped if
|
244
|
+
the number of qubits for either operation exceeds this amount.
|
245
|
+
Return:
|
246
|
+
True if determining the commutation of op is currently not supported
|
247
|
+
"""
|
248
|
+
if (
|
249
|
+
len(qargs) > max_num_qubits
|
250
|
+
or getattr(op, "_directive", False)
|
251
|
+
or op.name in _skipped_op_names
|
252
|
+
):
|
253
|
+
return True
|
254
|
+
|
255
|
+
if getattr(op, "is_parameterized", False) and op.is_parameterized():
|
256
|
+
return True
|
257
|
+
|
258
|
+
# we can proceed if op has defined: to_operator, to_matrix and __array__, or if its definition can be
|
259
|
+
# recursively resolved by operations that have a matrix. We check this by constructing an Operator.
|
260
|
+
if (hasattr(op, "to_matrix") and hasattr(op, "__array__")) or hasattr(op, "to_operator"):
|
261
|
+
return False
|
262
|
+
|
263
|
+
return False
|
205
264
|
|
206
265
|
|
207
266
|
def _commutation_precheck(
|
@@ -213,43 +272,14 @@ def _commutation_precheck(
|
|
213
272
|
cargs2: List,
|
214
273
|
max_num_qubits,
|
215
274
|
):
|
216
|
-
|
217
|
-
|
218
|
-
# We don't support commutation of conditional gates for now due to bugs in
|
219
|
-
# CommutativeCancellation. See gh-8553.
|
220
|
-
if getattr(op1, "condition", None) is not None or getattr(op2, "condition", None) is not None:
|
275
|
+
if not is_commutation_supported(op1) or not is_commutation_supported(op2):
|
221
276
|
return False
|
222
277
|
|
223
|
-
|
224
|
-
# pending a control flow graph.
|
225
|
-
if isinstance(op1, ControlFlowOp) or isinstance(op2, ControlFlowOp):
|
226
|
-
return False
|
227
|
-
|
228
|
-
# These lines are adapted from dag_dependency and say that two gates over
|
229
|
-
# different quantum and classical bits necessarily commute. This is more
|
230
|
-
# permissive that the check from commutation_analysis, as for example it
|
231
|
-
# allows to commute X(1) and Measure(0, 0).
|
232
|
-
# Presumably this check was not present in commutation_analysis as
|
233
|
-
# it was only called on pairs of connected nodes from DagCircuit.
|
234
|
-
intersection_q = set(qargs1).intersection(set(qargs2))
|
235
|
-
intersection_c = set(cargs1).intersection(set(cargs2))
|
236
|
-
if not (intersection_q or intersection_c):
|
278
|
+
if set(qargs1).isdisjoint(qargs2) and set(cargs1).isdisjoint(cargs2):
|
237
279
|
return True
|
238
280
|
|
239
|
-
|
240
|
-
|
241
|
-
return False
|
242
|
-
|
243
|
-
# These lines are adapted from commutation_analysis, which is more restrictive than the
|
244
|
-
# check from dag_dependency when considering nodes with "_directive". It would be nice to
|
245
|
-
# think which optimizations from dag_dependency can indeed be used.
|
246
|
-
if op1.name in _skipped_op_names or op2.name in _skipped_op_names:
|
247
|
-
return False
|
248
|
-
|
249
|
-
if getattr(op1, "_directive", False) or getattr(op2, "_directive", False):
|
250
|
-
return False
|
251
|
-
if (getattr(op1, "is_parameterized", False) and op1.is_parameterized()) or (
|
252
|
-
getattr(op2, "is_parameterized", False) and op2.is_parameterized()
|
281
|
+
if is_commutation_skipped(op1, qargs1, max_num_qubits) or is_commutation_skipped(
|
282
|
+
op2, qargs2, max_num_qubits
|
253
283
|
):
|
254
284
|
return False
|
255
285
|
|
@@ -264,13 +294,11 @@ def _get_relative_placement(first_qargs: List[Qubit], second_qargs: List[Qubit])
|
|
264
294
|
second_qargs (DAGOpNode): second gate
|
265
295
|
|
266
296
|
Return:
|
267
|
-
A tuple that describes the relative qubit placement.
|
268
|
-
gate qubit arrangements as q2^{-1}[q1[i]] where q1[i] is the ith qubit of the first gate and
|
269
|
-
q2^{-1}[q] returns the qubit index of qubit q in the second gate (possibly 'None'). E.g.
|
297
|
+
A tuple that describes the relative qubit placement: E.g.
|
270
298
|
_get_relative_placement(CX(0, 1), CX(1, 2)) would return (None, 0) as there is no overlap on
|
271
299
|
the first qubit of the first gate but there is an overlap on the second qubit of the first gate,
|
272
|
-
i.e. qubit 0 of the second gate. Likewise,
|
273
|
-
return (1, None)
|
300
|
+
i.e. qubit 0 of the second gate. Likewise,
|
301
|
+
_get_relative_placement(CX(1, 2), CX(0, 1)) would return (1, None)
|
274
302
|
"""
|
275
303
|
qubits_g2 = {q_g1: i_g1 for i_g1, q_g1 in enumerate(second_qargs)}
|
276
304
|
return tuple(qubits_g2.get(q_g0, None) for q_g0 in first_qargs)
|
@@ -285,7 +313,7 @@ def _persistent_id(op_name: str) -> int:
|
|
285
313
|
Return:
|
286
314
|
The integer id of the input string.
|
287
315
|
"""
|
288
|
-
return int.from_bytes(bytes(op_name, encoding="
|
316
|
+
return int.from_bytes(bytes(op_name, encoding="utf-8"), byteorder="big", signed=True)
|
289
317
|
|
290
318
|
|
291
319
|
def _order_operations(
|
@@ -355,8 +383,10 @@ def _query_commutation(
|
|
355
383
|
# if we have another dict in commutation_after_placement, commutation depends on params
|
356
384
|
if isinstance(commutation_after_placement, dict):
|
357
385
|
# Param commutation entry exists and must be a dict
|
386
|
+
first_params = getattr(first_op, "params", [])
|
387
|
+
second_params = getattr(second_op, "params", [])
|
358
388
|
return commutation_after_placement.get(
|
359
|
-
(_hashable_parameters(
|
389
|
+
(_hashable_parameters(first_params), _hashable_parameters(second_params)),
|
360
390
|
None,
|
361
391
|
)
|
362
392
|
else:
|
@@ -379,12 +409,17 @@ def _commute_matmul(
|
|
379
409
|
first_qarg = tuple(qarg[q] for q in first_qargs)
|
380
410
|
second_qarg = tuple(qarg[q] for q in second_qargs)
|
381
411
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
412
|
+
# try to generate an Operator out of op, if this succeeds we can determine commutativity, otherwise
|
413
|
+
# return false
|
414
|
+
try:
|
415
|
+
operator_1 = Operator(
|
416
|
+
first_ops, input_dims=(2,) * len(first_qarg), output_dims=(2,) * len(first_qarg)
|
417
|
+
)
|
418
|
+
operator_2 = Operator(
|
419
|
+
second_op, input_dims=(2,) * len(second_qarg), output_dims=(2,) * len(second_qarg)
|
420
|
+
)
|
421
|
+
except QiskitError:
|
422
|
+
return False
|
388
423
|
|
389
424
|
if first_qarg == second_qarg:
|
390
425
|
# Use full composition if possible to get the fastest matmul paths.
|
@@ -174,8 +174,16 @@ def _unify_circuit_resources_rebuild( # pylint: disable=invalid-name # (it's t
|
|
174
174
|
out_circuits = []
|
175
175
|
for circuit in circuits:
|
176
176
|
out = QuantumCircuit(
|
177
|
-
qubits,
|
177
|
+
qubits,
|
178
|
+
clbits,
|
179
|
+
*circuit.qregs,
|
180
|
+
*circuit.cregs,
|
181
|
+
global_phase=circuit.global_phase,
|
182
|
+
inputs=circuit.iter_input_vars(),
|
183
|
+
captures=circuit.iter_captured_vars(),
|
178
184
|
)
|
185
|
+
for var in circuit.iter_declared_vars():
|
186
|
+
out.add_uninitialized_var(var)
|
179
187
|
for instruction in circuit.data:
|
180
188
|
out._append(instruction)
|
181
189
|
out_circuits.append(out)
|
@@ -19,31 +19,17 @@ from .builder import InstructionPlaceholder, InstructionResources
|
|
19
19
|
|
20
20
|
|
21
21
|
class BreakLoopOp(Instruction):
|
22
|
-
"""A circuit operation which, when encountered, jumps to the end of
|
23
|
-
|
24
|
-
|
25
|
-
.. note:
|
26
|
-
|
27
|
-
Can be inserted only within the body of a loop op, and must span
|
28
|
-
the full width of that block.
|
29
|
-
|
30
|
-
**Circuit symbol:**
|
31
|
-
|
32
|
-
.. parsed-literal::
|
33
|
-
|
34
|
-
┌──────────────┐
|
35
|
-
q_0: ┤0 ├
|
36
|
-
│ │
|
37
|
-
q_1: ┤1 ├
|
38
|
-
│ break_loop │
|
39
|
-
q_2: ┤2 ├
|
40
|
-
│ │
|
41
|
-
c_0: ╡0 ╞
|
42
|
-
└──────────────┘
|
43
|
-
|
22
|
+
"""A circuit operation which, when encountered, jumps to the end of the nearest enclosing loop.
|
23
|
+
Can only be used inside loops.
|
44
24
|
"""
|
45
25
|
|
46
26
|
def __init__(self, num_qubits: int, num_clbits: int, label: Optional[str] = None):
|
27
|
+
"""
|
28
|
+
Args:
|
29
|
+
num_qubits: the number of qubits this affects.
|
30
|
+
num_clbits: the number of qubits this affects.
|
31
|
+
label: an optional string label for the instruction.
|
32
|
+
"""
|
47
33
|
super().__init__("break_loop", num_qubits, num_clbits, [], label=label)
|
48
34
|
|
49
35
|
|
@@ -24,7 +24,8 @@ import itertools
|
|
24
24
|
import typing
|
25
25
|
from typing import Collection, Iterable, FrozenSet, Tuple, Union, Optional, Sequence
|
26
26
|
|
27
|
-
from qiskit._accelerate.
|
27
|
+
from qiskit._accelerate.circuit import CircuitData
|
28
|
+
from qiskit.circuit.classical import expr
|
28
29
|
from qiskit.circuit.classicalregister import Clbit, ClassicalRegister
|
29
30
|
from qiskit.circuit.exceptions import CircuitError
|
30
31
|
from qiskit.circuit.instruction import Instruction
|
@@ -103,6 +104,66 @@ class CircuitScopeInterface(abc.ABC):
|
|
103
104
|
or a :class:`.Clbit` that isn't actually in the circuit.
|
104
105
|
"""
|
105
106
|
|
107
|
+
@abc.abstractmethod
|
108
|
+
def add_uninitialized_var(self, var: expr.Var):
|
109
|
+
"""Add an uninitialized variable to the circuit scope.
|
110
|
+
|
111
|
+
The general circuit context is responsible for ensuring the variable is initialized. These
|
112
|
+
uninitialized variables are guaranteed to be standalone.
|
113
|
+
|
114
|
+
Args:
|
115
|
+
var: the variable to add, if valid.
|
116
|
+
|
117
|
+
Raises:
|
118
|
+
CircuitError: if the variable cannot be added, such as because it invalidly shadows or
|
119
|
+
redefines an existing name.
|
120
|
+
"""
|
121
|
+
|
122
|
+
@abc.abstractmethod
|
123
|
+
def remove_var(self, var: expr.Var):
|
124
|
+
"""Remove a variable from the locals of this scope.
|
125
|
+
|
126
|
+
This is only called in the case that an exception occurred while initializing the variable,
|
127
|
+
and is not exposed to users.
|
128
|
+
|
129
|
+
Args:
|
130
|
+
var: the variable to remove. It can be assumed that this was already the subject of an
|
131
|
+
:meth:`add_uninitialized_var` call.
|
132
|
+
"""
|
133
|
+
|
134
|
+
@abc.abstractmethod
|
135
|
+
def use_var(self, var: expr.Var):
|
136
|
+
"""Called for every standalone classical real-time variable being used by some circuit
|
137
|
+
instruction.
|
138
|
+
|
139
|
+
The given variable is guaranteed to be a stand-alone variable; bit-like resource-wrapping
|
140
|
+
variables will have been filtered out and their resources given to
|
141
|
+
:meth:`resolve_classical_resource`.
|
142
|
+
|
143
|
+
Args:
|
144
|
+
var: the variable to validate.
|
145
|
+
|
146
|
+
Returns:
|
147
|
+
the same variable.
|
148
|
+
|
149
|
+
Raises:
|
150
|
+
CircuitError: if the variable is not valid for this scope.
|
151
|
+
"""
|
152
|
+
|
153
|
+
@abc.abstractmethod
|
154
|
+
def get_var(self, name: str) -> Optional[expr.Var]:
|
155
|
+
"""Get the variable (if any) in scope with the given name.
|
156
|
+
|
157
|
+
This should call up to the parent scope if in a control-flow builder scope, in case the
|
158
|
+
variable exists in an outer scope.
|
159
|
+
|
160
|
+
Args:
|
161
|
+
name: the name of the symbol to lookup.
|
162
|
+
|
163
|
+
Returns:
|
164
|
+
the variable if it is found, otherwise ``None``.
|
165
|
+
"""
|
166
|
+
|
106
167
|
|
107
168
|
class InstructionResources(typing.NamedTuple):
|
108
169
|
"""The quantum and classical resources used within a particular instruction.
|
@@ -271,6 +332,8 @@ class ControlFlowBuilderBlock(CircuitScopeInterface):
|
|
271
332
|
"_parent",
|
272
333
|
"_built",
|
273
334
|
"_forbidden_message",
|
335
|
+
"_vars_local",
|
336
|
+
"_vars_capture",
|
274
337
|
)
|
275
338
|
|
276
339
|
def __init__(
|
@@ -311,6 +374,8 @@ class ControlFlowBuilderBlock(CircuitScopeInterface):
|
|
311
374
|
self._instructions = CircuitData(qubits, clbits)
|
312
375
|
self.registers = set(registers)
|
313
376
|
self.global_phase = 0.0
|
377
|
+
self._vars_local = {}
|
378
|
+
self._vars_capture = {}
|
314
379
|
self._allow_jumps = allow_jumps
|
315
380
|
self._parent = parent
|
316
381
|
self._built = False
|
@@ -393,6 +458,49 @@ class ControlFlowBuilderBlock(CircuitScopeInterface):
|
|
393
458
|
self.add_register(resource)
|
394
459
|
return resource
|
395
460
|
|
461
|
+
def add_uninitialized_var(self, var: expr.Var):
|
462
|
+
if self._built:
|
463
|
+
raise CircuitError("Cannot add resources after the scope has been built.")
|
464
|
+
# We can shadow a name if it was declared in an outer scope, but only if we haven't already
|
465
|
+
# captured it ourselves yet.
|
466
|
+
if (previous := self._vars_local.get(var.name)) is not None:
|
467
|
+
if previous == var:
|
468
|
+
raise CircuitError(f"'{var}' is already present in the scope")
|
469
|
+
raise CircuitError(f"cannot add '{var}' as its name shadows the existing '{previous}'")
|
470
|
+
if var.name in self._vars_capture:
|
471
|
+
raise CircuitError(f"cannot add '{var}' as its name shadows the existing '{previous}'")
|
472
|
+
self._vars_local[var.name] = var
|
473
|
+
|
474
|
+
def remove_var(self, var: expr.Var):
|
475
|
+
if self._built:
|
476
|
+
raise RuntimeError("exception handler 'remove_var' called after scope built")
|
477
|
+
self._vars_local.pop(var.name)
|
478
|
+
|
479
|
+
def get_var(self, name: str):
|
480
|
+
if (out := self._vars_local.get(name)) is not None:
|
481
|
+
return out
|
482
|
+
return self._parent.get_var(name)
|
483
|
+
|
484
|
+
def use_var(self, var: expr.Var):
|
485
|
+
if (local := self._vars_local.get(var.name)) is not None:
|
486
|
+
if local == var:
|
487
|
+
return
|
488
|
+
raise CircuitError(f"cannot use '{var}' which is shadowed by the local '{local}'")
|
489
|
+
if self._vars_capture.get(var.name) == var:
|
490
|
+
return
|
491
|
+
if self._parent.get_var(var.name) != var:
|
492
|
+
raise CircuitError(f"cannot close over '{var}', which is not in scope")
|
493
|
+
self._parent.use_var(var)
|
494
|
+
self._vars_capture[var.name] = var
|
495
|
+
|
496
|
+
def iter_local_vars(self):
|
497
|
+
"""Iterator over the variables currently declared in this scope."""
|
498
|
+
return self._vars_local.values()
|
499
|
+
|
500
|
+
def iter_captured_vars(self):
|
501
|
+
"""Iterator over the variables currently captured in this scope."""
|
502
|
+
return self._vars_capture.values()
|
503
|
+
|
396
504
|
def peek(self) -> CircuitInstruction:
|
397
505
|
"""Get the value of the most recent instruction tuple in this scope."""
|
398
506
|
if not self._instructions:
|
@@ -493,7 +601,12 @@ class ControlFlowBuilderBlock(CircuitScopeInterface):
|
|
493
601
|
self._instructions.clbits,
|
494
602
|
*self.registers,
|
495
603
|
global_phase=self.global_phase,
|
604
|
+
captures=self._vars_capture.values(),
|
496
605
|
)
|
606
|
+
for var in self._vars_local.values():
|
607
|
+
# The requisite `Store` instruction to initialise the variable will have been appended
|
608
|
+
# into the instructions.
|
609
|
+
out.add_uninitialized_var(var)
|
497
610
|
|
498
611
|
# Maps placeholder index to the newly concrete instruction.
|
499
612
|
placeholder_to_concrete = {}
|
@@ -566,6 +679,8 @@ class ControlFlowBuilderBlock(CircuitScopeInterface):
|
|
566
679
|
out._instructions = self._instructions.copy()
|
567
680
|
out.registers = self.registers.copy()
|
568
681
|
out.global_phase = self.global_phase
|
682
|
+
out._vars_local = self._vars_local.copy()
|
683
|
+
out._vars_capture = self._vars_capture.copy()
|
569
684
|
out._parent = self._parent
|
570
685
|
out._allow_jumps = self._allow_jumps
|
571
686
|
out._forbidden_message = self._forbidden_message
|
@@ -19,31 +19,17 @@ from .builder import InstructionPlaceholder, InstructionResources
|
|
19
19
|
|
20
20
|
|
21
21
|
class ContinueLoopOp(Instruction):
|
22
|
-
"""A circuit operation which, when encountered, moves to the next iteration of
|
23
|
-
|
24
|
-
|
25
|
-
.. note::
|
26
|
-
|
27
|
-
Can be inserted only within the body of a loop op, and must span the full
|
28
|
-
width of that block.
|
29
|
-
|
30
|
-
**Circuit symbol:**
|
31
|
-
|
32
|
-
.. parsed-literal::
|
33
|
-
|
34
|
-
┌─────────────────┐
|
35
|
-
q_0: ┤0 ├
|
36
|
-
│ │
|
37
|
-
q_1: ┤1 ├
|
38
|
-
│ continue_loop │
|
39
|
-
q_2: ┤2 ├
|
40
|
-
│ │
|
41
|
-
c_0: ╡0 ╞
|
42
|
-
└─────────────────┘
|
43
|
-
|
22
|
+
"""A circuit operation which, when encountered, moves to the next iteration of the nearest
|
23
|
+
enclosing loop. Can only be used inside loops.
|
44
24
|
"""
|
45
25
|
|
46
26
|
def __init__(self, num_qubits: int, num_clbits: int, label: Optional[str] = None):
|
27
|
+
"""
|
28
|
+
Args:
|
29
|
+
num_qubits: the number of qubits this affects.
|
30
|
+
num_clbits: the number of qubits this affects.
|
31
|
+
label: an optional string label for the instruction.
|
32
|
+
"""
|
47
33
|
super().__init__("continue_loop", num_qubits, num_clbits, [], label=label)
|
48
34
|
|
49
35
|
|
@@ -18,28 +18,67 @@ import typing
|
|
18
18
|
from abc import ABC, abstractmethod
|
19
19
|
|
20
20
|
from qiskit.circuit.instruction import Instruction
|
21
|
+
from qiskit.circuit.exceptions import CircuitError
|
21
22
|
|
22
23
|
if typing.TYPE_CHECKING:
|
23
24
|
from qiskit.circuit import QuantumCircuit
|
25
|
+
from qiskit.circuit.classical import expr
|
24
26
|
|
25
27
|
|
26
28
|
class ControlFlowOp(Instruction, ABC):
|
27
|
-
"""Abstract class to encapsulate all control flow operations.
|
29
|
+
"""Abstract class to encapsulate all control flow operations.
|
30
|
+
|
31
|
+
All subclasses of :class:`ControlFlowOp` have an internal attribute,
|
32
|
+
:attr:`~ControlFlowOp.blocks`, which exposes the inner subcircuits used in the different blocks
|
33
|
+
of the control flow.
|
34
|
+
"""
|
35
|
+
|
36
|
+
def __init__(self, *args, **kwargs):
|
37
|
+
super().__init__(*args, **kwargs)
|
38
|
+
for block in self.blocks:
|
39
|
+
if block.num_input_vars:
|
40
|
+
raise CircuitError("control-flow blocks cannot contain input variables")
|
28
41
|
|
29
42
|
@property
|
30
43
|
@abstractmethod
|
31
44
|
def blocks(self) -> tuple[QuantumCircuit, ...]:
|
32
|
-
"""Tuple of
|
33
|
-
execution of this ControlFlowOp
|
34
|
-
parameter to be resolved at run time.
|
35
|
-
"""
|
45
|
+
"""Tuple of :class:`.QuantumCircuit`\\ s which may be executed as part of the
|
46
|
+
execution of this :class:`ControlFlowOp`."""
|
36
47
|
|
37
48
|
@abstractmethod
|
38
49
|
def replace_blocks(self, blocks: typing.Iterable[QuantumCircuit]) -> ControlFlowOp:
|
39
|
-
"""
|
50
|
+
"""Return a new version of this control-flow operations with the :attr:`blocks` mapped to
|
51
|
+
the given new ones.
|
52
|
+
|
53
|
+
Typically this is used in a workflow such as::
|
54
|
+
|
55
|
+
existing_op = ...
|
56
|
+
|
57
|
+
def map_block(block: QuantumCircuit) -> QuantumCircuit:
|
58
|
+
new_block = block.copy_empty_like()
|
59
|
+
# ... do something to `new_block` ...
|
60
|
+
return new_block
|
61
|
+
|
62
|
+
new_op = existing_op.replace_blocks(
|
63
|
+
map_block(block) for block in existing_op.blocks
|
64
|
+
)
|
65
|
+
|
66
|
+
It is the caller's responsibility to ensure that the mapped blocks are defined over a
|
67
|
+
unified set of circuit resources, much like constructing a :class:`ControlFlowOp` using its
|
68
|
+
default constructor.
|
69
|
+
|
40
70
|
Args:
|
41
|
-
blocks:
|
71
|
+
blocks: the new subcircuit blocks to use.
|
42
72
|
|
43
73
|
Returns:
|
44
|
-
New ControlFlowOp with replaced blocks.
|
74
|
+
New :class:`ControlFlowOp` with replaced blocks.
|
45
75
|
"""
|
76
|
+
|
77
|
+
def iter_captured_vars(self) -> typing.Iterable[expr.Var]:
|
78
|
+
"""Get an iterator over the unique captured variables in all blocks of this construct."""
|
79
|
+
seen = set()
|
80
|
+
for block in self.blocks:
|
81
|
+
for var in block.iter_captured_vars():
|
82
|
+
if var not in seen:
|
83
|
+
seen.add(var)
|
84
|
+
yield var
|
@@ -29,28 +29,6 @@ class ForLoopOp(ControlFlowOp):
|
|
29
29
|
"""A circuit operation which repeatedly executes a subcircuit
|
30
30
|
(``body``) parameterized by a parameter ``loop_parameter`` through
|
31
31
|
the set of integer values provided in ``indexset``.
|
32
|
-
|
33
|
-
Parameters:
|
34
|
-
indexset: A collection of integers to loop over.
|
35
|
-
loop_parameter: The placeholder parameterizing ``body`` to which
|
36
|
-
the values from ``indexset`` will be assigned.
|
37
|
-
body: The loop body to be repeatedly executed.
|
38
|
-
label: An optional label for identifying the instruction.
|
39
|
-
|
40
|
-
**Circuit symbol:**
|
41
|
-
|
42
|
-
.. parsed-literal::
|
43
|
-
|
44
|
-
┌───────────┐
|
45
|
-
q_0: ┤0 ├
|
46
|
-
│ │
|
47
|
-
q_1: ┤1 ├
|
48
|
-
│ for_loop │
|
49
|
-
q_2: ┤2 ├
|
50
|
-
│ │
|
51
|
-
c_0: ╡0 ╞
|
52
|
-
└───────────┘
|
53
|
-
|
54
32
|
"""
|
55
33
|
|
56
34
|
def __init__(
|
@@ -60,9 +38,16 @@ class ForLoopOp(ControlFlowOp):
|
|
60
38
|
body: QuantumCircuit,
|
61
39
|
label: Optional[str] = None,
|
62
40
|
):
|
41
|
+
"""
|
42
|
+
Args:
|
43
|
+
indexset: A collection of integers to loop over.
|
44
|
+
loop_parameter: The placeholder parameterizing ``body`` to which
|
45
|
+
the values from ``indexset`` will be assigned.
|
46
|
+
body: The loop body to be repeatedly executed.
|
47
|
+
label: An optional label for identifying the instruction.
|
48
|
+
"""
|
63
49
|
num_qubits = body.num_qubits
|
64
50
|
num_clbits = body.num_clbits
|
65
|
-
|
66
51
|
super().__init__(
|
67
52
|
"for_loop", num_qubits, num_clbits, [indexset, loop_parameter, body], label=label
|
68
53
|
)
|
@@ -44,38 +44,11 @@ class IfElseOp(ControlFlowOp):
|
|
44
44
|
provided condition (``condition``) evaluates to true, and
|
45
45
|
optionally evaluates another program (``false_body``) otherwise.
|
46
46
|
|
47
|
-
Parameters:
|
48
|
-
condition: A condition to be evaluated at circuit runtime which,
|
49
|
-
if true, will trigger the evaluation of ``true_body``. Can be
|
50
|
-
specified as either a tuple of a ``ClassicalRegister`` to be
|
51
|
-
tested for equality with a given ``int``, or as a tuple of a
|
52
|
-
``Clbit`` to be compared to either a ``bool`` or an ``int``.
|
53
|
-
true_body: A program to be executed if ``condition`` evaluates
|
54
|
-
to true.
|
55
|
-
false_body: A optional program to be executed if ``condition``
|
56
|
-
evaluates to false.
|
57
|
-
label: An optional label for identifying the instruction.
|
58
|
-
|
59
47
|
If provided, ``false_body`` must be of the same ``num_qubits`` and
|
60
48
|
``num_clbits`` as ``true_body``.
|
61
49
|
|
62
50
|
The classical bits used in ``condition`` must be a subset of those attached
|
63
51
|
to the circuit on which this ``IfElseOp`` will be appended.
|
64
|
-
|
65
|
-
**Circuit symbol:**
|
66
|
-
|
67
|
-
.. parsed-literal::
|
68
|
-
|
69
|
-
┌───────────┐
|
70
|
-
q_0: ┤0 ├
|
71
|
-
│ │
|
72
|
-
q_1: ┤1 ├
|
73
|
-
│ if_else │
|
74
|
-
q_2: ┤2 ├
|
75
|
-
│ │
|
76
|
-
c_0: ╡0 ╞
|
77
|
-
└───────────┘
|
78
|
-
|
79
52
|
"""
|
80
53
|
|
81
54
|
def __init__(
|
@@ -85,6 +58,19 @@ class IfElseOp(ControlFlowOp):
|
|
85
58
|
false_body: QuantumCircuit | None = None,
|
86
59
|
label: str | None = None,
|
87
60
|
):
|
61
|
+
"""
|
62
|
+
Args:
|
63
|
+
condition: A condition to be evaluated in real time during circuit execution which,
|
64
|
+
if true, will trigger the evaluation of ``true_body``. Can be
|
65
|
+
specified as either a tuple of a ``ClassicalRegister`` to be
|
66
|
+
tested for equality with a given ``int``, or as a tuple of a
|
67
|
+
``Clbit`` to be compared to either a ``bool`` or an ``int``.
|
68
|
+
true_body: A program to be executed if ``condition`` evaluates
|
69
|
+
to true.
|
70
|
+
false_body: A optional program to be executed if ``condition``
|
71
|
+
evaluates to false.
|
72
|
+
label: An optional label for identifying the instruction.
|
73
|
+
"""
|
88
74
|
# pylint: disable=cyclic-import
|
89
75
|
from qiskit.circuit import QuantumCircuit
|
90
76
|
|