qiskit 1.0.2__cp38-abi3-win32.whl → 1.1.0rc1__cp38-abi3-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qiskit/VERSION.txt +1 -1
- qiskit/__init__.py +27 -16
- qiskit/_accelerate.pyd +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.pyd +0 -0
- qiskit/_qasm3.pyd +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
qiskit/circuit/quantumcircuit.py
CHANGED
@@ -15,7 +15,8 @@
|
|
15
15
|
"""Quantum circuit object."""
|
16
16
|
|
17
17
|
from __future__ import annotations
|
18
|
-
import copy
|
18
|
+
import copy as _copy
|
19
|
+
import itertools
|
19
20
|
import multiprocessing as mp
|
20
21
|
import typing
|
21
22
|
from collections import OrderedDict, defaultdict, namedtuple
|
@@ -35,7 +36,7 @@ from typing import (
|
|
35
36
|
overload,
|
36
37
|
)
|
37
38
|
import numpy as np
|
38
|
-
from qiskit._accelerate.
|
39
|
+
from qiskit._accelerate.circuit import CircuitData
|
39
40
|
from qiskit.exceptions import QiskitError
|
40
41
|
from qiskit.utils.multiprocessing import is_main_process
|
41
42
|
from qiskit.circuit.instruction import Instruction
|
@@ -44,6 +45,7 @@ from qiskit.circuit.parameter import Parameter
|
|
44
45
|
from qiskit.circuit.exceptions import CircuitError
|
45
46
|
from . import _classical_resource_map
|
46
47
|
from ._utils import sort_parameters
|
48
|
+
from .controlflow import ControlFlowOp
|
47
49
|
from .controlflow.builder import CircuitScopeInterface, ControlFlowBuilderBlock
|
48
50
|
from .controlflow.break_loop import BreakLoopOp, BreakLoopPlaceholder
|
49
51
|
from .controlflow.continue_loop import ContinueLoopOp, ContinueLoopPlaceholder
|
@@ -51,7 +53,7 @@ from .controlflow.for_loop import ForLoopOp, ForLoopContext
|
|
51
53
|
from .controlflow.if_else import IfElseOp, IfContext
|
52
54
|
from .controlflow.switch_case import SwitchCaseOp, SwitchContext
|
53
55
|
from .controlflow.while_loop import WhileLoopOp, WhileLoopContext
|
54
|
-
from .classical import expr
|
56
|
+
from .classical import expr, types
|
55
57
|
from .parameterexpression import ParameterExpression, ParameterValueType
|
56
58
|
from .quantumregister import QuantumRegister, Qubit, AncillaRegister, AncillaQubit
|
57
59
|
from .classicalregister import ClassicalRegister, Clbit
|
@@ -63,6 +65,7 @@ from .register import Register
|
|
63
65
|
from .bit import Bit
|
64
66
|
from .quantumcircuitdata import QuantumCircuitData, CircuitInstruction
|
65
67
|
from .delay import Delay
|
68
|
+
from .store import Store
|
66
69
|
|
67
70
|
if typing.TYPE_CHECKING:
|
68
71
|
import qiskit # pylint: disable=cyclic-import
|
@@ -141,9 +144,27 @@ class QuantumCircuit:
|
|
141
144
|
circuit. This gets stored as free-form data in a dict in the
|
142
145
|
:attr:`~qiskit.circuit.QuantumCircuit.metadata` attribute. It will
|
143
146
|
not be directly used in the circuit.
|
147
|
+
inputs: any variables to declare as ``input`` real-time variables for this circuit. These
|
148
|
+
should already be existing :class:`.expr.Var` nodes that you build from somewhere else;
|
149
|
+
if you need to create the inputs as well, use :meth:`QuantumCircuit.add_input`. The
|
150
|
+
variables given in this argument will be passed directly to :meth:`add_input`. A
|
151
|
+
circuit cannot have both ``inputs`` and ``captures``.
|
152
|
+
captures: any variables that that this circuit scope should capture from a containing scope.
|
153
|
+
The variables given here will be passed directly to :meth:`add_capture`. A circuit
|
154
|
+
cannot have both ``inputs`` and ``captures``.
|
155
|
+
declarations: any variables that this circuit should declare and initialize immediately.
|
156
|
+
You can order this input so that later declarations depend on earlier ones (including
|
157
|
+
inputs or captures). If you need to depend on values that will be computed later at
|
158
|
+
runtime, use :meth:`add_var` at an appropriate point in the circuit execution.
|
159
|
+
|
160
|
+
This argument is intended for convenient circuit initialization when you already have a
|
161
|
+
set of created variables. The variables used here will be directly passed to
|
162
|
+
:meth:`add_var`, which you can use directly if this is the first time you are creating
|
163
|
+
the variable.
|
144
164
|
|
145
165
|
Raises:
|
146
166
|
CircuitError: if the circuit name, if given, is not valid.
|
167
|
+
CircuitError: if both ``inputs`` and ``captures`` are given.
|
147
168
|
|
148
169
|
Examples:
|
149
170
|
|
@@ -203,6 +224,9 @@ class QuantumCircuit:
|
|
203
224
|
name: str | None = None,
|
204
225
|
global_phase: ParameterValueType = 0,
|
205
226
|
metadata: dict | None = None,
|
227
|
+
inputs: Iterable[expr.Var] = (),
|
228
|
+
captures: Iterable[expr.Var] = (),
|
229
|
+
declarations: Mapping[expr.Var, expr.Expr] | Iterable[Tuple[expr.Var, expr.Expr]] = (),
|
206
230
|
):
|
207
231
|
if any(not isinstance(reg, (list, QuantumRegister, ClassicalRegister)) for reg in regs):
|
208
232
|
# check if inputs are integers, but also allow e.g. 2.0
|
@@ -276,6 +300,20 @@ class QuantumCircuit:
|
|
276
300
|
self._global_phase: ParameterValueType = 0
|
277
301
|
self.global_phase = global_phase
|
278
302
|
|
303
|
+
# Add classical variables. Resolve inputs and captures first because they can't depend on
|
304
|
+
# anything, but declarations might depend on them.
|
305
|
+
self._vars_input: dict[str, expr.Var] = {}
|
306
|
+
self._vars_capture: dict[str, expr.Var] = {}
|
307
|
+
self._vars_local: dict[str, expr.Var] = {}
|
308
|
+
for input_ in inputs:
|
309
|
+
self.add_input(input_)
|
310
|
+
for capture in captures:
|
311
|
+
self.add_capture(capture)
|
312
|
+
if isinstance(declarations, Mapping):
|
313
|
+
declarations = declarations.items()
|
314
|
+
for var, initial in declarations:
|
315
|
+
self.add_var(var, initial)
|
316
|
+
|
279
317
|
self.duration = None
|
280
318
|
self.unit = "dt"
|
281
319
|
self.metadata = {} if metadata is None else metadata
|
@@ -387,10 +425,10 @@ class QuantumCircuit:
|
|
387
425
|
return
|
388
426
|
if isinstance(data_input[0], CircuitInstruction):
|
389
427
|
for instruction in data_input:
|
390
|
-
self.append(instruction)
|
428
|
+
self.append(instruction, copy=False)
|
391
429
|
else:
|
392
430
|
for instruction, qargs, cargs in data_input:
|
393
|
-
self.append(instruction, qargs, cargs)
|
431
|
+
self.append(instruction, qargs, cargs, copy=False)
|
394
432
|
|
395
433
|
@property
|
396
434
|
def op_start_times(self) -> list[int]:
|
@@ -497,7 +535,7 @@ class QuantumCircuit:
|
|
497
535
|
cls = self.__class__
|
498
536
|
result = cls.__new__(cls)
|
499
537
|
for k in self.__dict__.keys() - {"_data", "_builder_api"}:
|
500
|
-
setattr(result, k,
|
538
|
+
setattr(result, k, _copy.deepcopy(self.__dict__[k], memo))
|
501
539
|
|
502
540
|
result._builder_api = _OuterCircuitScopeInterface(result)
|
503
541
|
|
@@ -505,10 +543,10 @@ class QuantumCircuit:
|
|
505
543
|
# like we would when pickling.
|
506
544
|
result._data = self._data.copy()
|
507
545
|
result._data.replace_bits(
|
508
|
-
qubits=
|
509
|
-
clbits=
|
546
|
+
qubits=_copy.deepcopy(self._data.qubits, memo),
|
547
|
+
clbits=_copy.deepcopy(self._data.clbits, memo),
|
510
548
|
)
|
511
|
-
result._data.map_ops(lambda op:
|
549
|
+
result._data.map_ops(lambda op: _copy.deepcopy(op, memo))
|
512
550
|
return result
|
513
551
|
|
514
552
|
@classmethod
|
@@ -583,9 +621,7 @@ class QuantumCircuit:
|
|
583
621
|
q_1: ┤ RX(1.57) ├─────
|
584
622
|
└──────────┘
|
585
623
|
"""
|
586
|
-
reverse_circ =
|
587
|
-
self.qubits, self.clbits, *self.qregs, *self.cregs, name=self.name + "_reverse"
|
588
|
-
)
|
624
|
+
reverse_circ = self.copy_empty_like(self.name + "_reverse")
|
589
625
|
|
590
626
|
for instruction in reversed(self.data):
|
591
627
|
reverse_circ._append(instruction.replace(operation=instruction.operation.reverse_ops()))
|
@@ -739,26 +775,38 @@ class QuantumCircuit:
|
|
739
775
|
|
740
776
|
return repeated_circ
|
741
777
|
|
742
|
-
def power(
|
778
|
+
def power(
|
779
|
+
self, power: float, matrix_power: bool = False, annotated: bool = False
|
780
|
+
) -> "QuantumCircuit":
|
743
781
|
"""Raise this circuit to the power of ``power``.
|
744
782
|
|
745
|
-
If ``power`` is a positive integer and ``matrix_power``
|
746
|
-
defaults to calling ``repeat``. Otherwise,
|
747
|
-
|
783
|
+
If ``power`` is a positive integer and both ``matrix_power`` and ``annotated``
|
784
|
+
are ``False``, this implementation defaults to calling ``repeat``. Otherwise,
|
785
|
+
the circuit is converted into a gate, and a new circuit, containing this gate
|
786
|
+
raised to the given power, is returned. The gate raised to the given power is
|
787
|
+
implemented either as a unitary gate if ``annotated`` is ``False`` or as an
|
788
|
+
annotated operation if ``annotated`` is ``True``.
|
748
789
|
|
749
790
|
Args:
|
750
791
|
power (float): The power to raise this circuit to.
|
751
|
-
matrix_power (bool):
|
752
|
-
|
753
|
-
|
792
|
+
matrix_power (bool): indicates whether the inner power gate can be implemented
|
793
|
+
as a unitary gate.
|
794
|
+
annotated (bool): indicates whether the inner power gate can be implemented
|
795
|
+
as an annotated operation.
|
754
796
|
|
755
797
|
Raises:
|
756
|
-
CircuitError: If the circuit needs to be converted to a gate but
|
798
|
+
CircuitError: If the circuit needs to be converted to a unitary gate, but is
|
799
|
+
not unitary.
|
757
800
|
|
758
801
|
Returns:
|
759
802
|
QuantumCircuit: A circuit implementing this circuit raised to the power of ``power``.
|
760
803
|
"""
|
761
|
-
if
|
804
|
+
if (
|
805
|
+
power >= 0
|
806
|
+
and isinstance(power, (int, np.integer))
|
807
|
+
and not matrix_power
|
808
|
+
and not annotated
|
809
|
+
):
|
762
810
|
return self.repeat(power)
|
763
811
|
|
764
812
|
# attempt conversion to gate
|
@@ -774,12 +822,12 @@ class QuantumCircuit:
|
|
774
822
|
except QiskitError as ex:
|
775
823
|
raise CircuitError(
|
776
824
|
"The circuit contains non-unitary operations and cannot be "
|
777
|
-
"
|
778
|
-
"be in the circuit for this operation."
|
825
|
+
"raised to a power. Note that no qiskit.circuit.Instruction "
|
826
|
+
"objects may be in the circuit for this operation."
|
779
827
|
) from ex
|
780
828
|
|
781
829
|
power_circuit = QuantumCircuit(self.qubits, self.clbits, *self.qregs, *self.cregs)
|
782
|
-
power_circuit.append(gate.power(power), list(range(gate.num_qubits)))
|
830
|
+
power_circuit.append(gate.power(power, annotated=annotated), list(range(gate.num_qubits)))
|
783
831
|
return power_circuit
|
784
832
|
|
785
833
|
def control(
|
@@ -831,11 +879,33 @@ class QuantumCircuit:
|
|
831
879
|
front: bool = False,
|
832
880
|
inplace: bool = False,
|
833
881
|
wrap: bool = False,
|
882
|
+
*,
|
883
|
+
copy: bool = True,
|
884
|
+
var_remap: Mapping[str | expr.Var, str | expr.Var] | None = None,
|
885
|
+
inline_captures: bool = False,
|
834
886
|
) -> Optional["QuantumCircuit"]:
|
835
887
|
"""Compose circuit with ``other`` circuit or instruction, optionally permuting wires.
|
836
888
|
|
837
889
|
``other`` can be narrower or of equal width to ``self``.
|
838
890
|
|
891
|
+
When dealing with realtime variables (:class:`.expr.Var` instances), there are two principal
|
892
|
+
strategies for using :meth:`compose`:
|
893
|
+
|
894
|
+
1. The ``other`` circuit is treated as entirely additive, including its variables. The
|
895
|
+
variables in ``other`` must be entirely distinct from those in ``self`` (use
|
896
|
+
``var_remap`` to help with this), and all variables in ``other`` will be declared anew in
|
897
|
+
the output with matching input/capture/local scoping to how they are in ``other``. This
|
898
|
+
is generally what you want if you're joining two unrelated circuits.
|
899
|
+
|
900
|
+
2. The ``other`` circuit was created as an exact extension to ``self`` to be inlined onto
|
901
|
+
it, including acting on the existing variables in their states at the end of ``self``.
|
902
|
+
In this case, ``other`` should be created with all these variables to be inlined declared
|
903
|
+
as "captures", and then you can use ``inline_captures=True`` in this method to link them.
|
904
|
+
This is generally what you want if you're building up a circuit by defining layers
|
905
|
+
on-the-fly, or rebuilding a circuit using layers taken from itself. You might find the
|
906
|
+
``vars_mode="captures"`` argument to :meth:`copy_empty_like` useful to create each
|
907
|
+
layer's base, in this case.
|
908
|
+
|
839
909
|
Args:
|
840
910
|
other (qiskit.circuit.Instruction or QuantumCircuit):
|
841
911
|
(sub)circuit or instruction to compose onto self. If not a :obj:`.QuantumCircuit`,
|
@@ -847,6 +917,30 @@ class QuantumCircuit:
|
|
847
917
|
inplace (bool): If True, modify the object. Otherwise return composed circuit.
|
848
918
|
wrap (bool): If True, wraps the other circuit into a gate (or instruction, depending on
|
849
919
|
whether it contains only unitary instructions) before composing it onto self.
|
920
|
+
copy (bool): If ``True`` (the default), then the input is treated as shared, and any
|
921
|
+
contained instructions will be copied, if they might need to be mutated in the
|
922
|
+
future. You can set this to ``False`` if the input should be considered owned by
|
923
|
+
the base circuit, in order to avoid unnecessary copies; in this case, it is not
|
924
|
+
valid to use ``other`` afterwards, and some instructions may have been mutated in
|
925
|
+
place.
|
926
|
+
var_remap (Mapping): mapping to use to rewrite :class:`.expr.Var` nodes in ``other`` as
|
927
|
+
they are inlined into ``self``. This can be used to avoid naming conflicts.
|
928
|
+
|
929
|
+
Both keys and values can be given as strings or direct :class:`.expr.Var` instances.
|
930
|
+
If a key is a string, it matches any :class:`~.expr.Var` with the same name. If a
|
931
|
+
value is a string, whenever a new key matches a it, a new :class:`~.expr.Var` is
|
932
|
+
created with the correct type. If a value is a :class:`~.expr.Var`, its
|
933
|
+
:class:`~.expr.Expr.type` must exactly match that of the variable it is replacing.
|
934
|
+
inline_captures (bool): if ``True``, then all "captured" :class:`~.expr.Var` nodes in
|
935
|
+
the ``other`` :class:`.QuantumCircuit` are assumed to refer to variables already
|
936
|
+
declared in ``self`` (as any input/capture/local type), and the uses in ``other``
|
937
|
+
will apply to the existing variables. If you want to build up a layer for an
|
938
|
+
existing circuit to use with :meth:`compose`, you might find the
|
939
|
+
``vars_mode="captures"`` argument to :meth:`copy_empty_like` useful. Any remapping
|
940
|
+
in ``vars_remap`` occurs before evaluating this variable inlining.
|
941
|
+
|
942
|
+
If this is ``False`` (the default), then all variables in ``other`` will be required
|
943
|
+
to be distinct from those in ``self``, and new declarations will be made for them.
|
850
944
|
|
851
945
|
Returns:
|
852
946
|
QuantumCircuit: the composed circuit (returns None if inplace==True).
|
@@ -903,6 +997,31 @@ class QuantumCircuit:
|
|
903
997
|
# error that the user might want to correct in an interactive session.
|
904
998
|
dest = self if inplace else self.copy()
|
905
999
|
|
1000
|
+
var_remap = {} if var_remap is None else var_remap
|
1001
|
+
|
1002
|
+
# This doesn't use `functools.cache` so we can access it during the variable remapping of
|
1003
|
+
# instructions. We cache all replacement lookups for a) speed and b) to ensure that
|
1004
|
+
# the same variable _always_ maps to the same replacement even if it's used in different
|
1005
|
+
# places in the recursion tree (such as being a captured variable).
|
1006
|
+
def replace_var(var: expr.Var, cache: Mapping[expr.Var, expr.Var]) -> expr.Var:
|
1007
|
+
# This is closing over an argument to `compose`.
|
1008
|
+
nonlocal var_remap
|
1009
|
+
|
1010
|
+
if out := cache.get(var):
|
1011
|
+
return out
|
1012
|
+
if (replacement := var_remap.get(var)) or (replacement := var_remap.get(var.name)):
|
1013
|
+
if isinstance(replacement, str):
|
1014
|
+
replacement = expr.Var.new(replacement, var.type)
|
1015
|
+
if replacement.type != var.type:
|
1016
|
+
raise CircuitError(
|
1017
|
+
f"mismatched types in replacement for '{var.name}':"
|
1018
|
+
f" '{var.type}' cannot become '{replacement.type}'"
|
1019
|
+
)
|
1020
|
+
else:
|
1021
|
+
replacement = var
|
1022
|
+
cache[var] = replacement
|
1023
|
+
return replacement
|
1024
|
+
|
906
1025
|
# As a special case, allow composing some clbits onto no clbits - normally the destination
|
907
1026
|
# has to be strictly larger. This allows composing final measurements onto unitary circuits.
|
908
1027
|
if isinstance(other, QuantumCircuit):
|
@@ -931,11 +1050,11 @@ class QuantumCircuit:
|
|
931
1050
|
# Need to keep a reference to the data for use after we've emptied it.
|
932
1051
|
old_data = dest._data.copy()
|
933
1052
|
dest.clear()
|
934
|
-
dest.append(other, qubits, clbits)
|
1053
|
+
dest.append(other, qubits, clbits, copy=copy)
|
935
1054
|
for instruction in old_data:
|
936
1055
|
dest._append(instruction)
|
937
1056
|
else:
|
938
|
-
dest.append(other, qargs=qubits, cargs=clbits)
|
1057
|
+
dest.append(other, qargs=qubits, cargs=clbits, copy=copy)
|
939
1058
|
return None if inplace else dest
|
940
1059
|
|
941
1060
|
if other.num_qubits > dest.num_qubits or other.num_clbits > dest.num_clbits:
|
@@ -986,37 +1105,100 @@ class QuantumCircuit:
|
|
986
1105
|
dest.unit = "dt"
|
987
1106
|
dest.global_phase += other.global_phase
|
988
1107
|
|
989
|
-
if
|
990
|
-
|
991
|
-
|
992
|
-
# directly.
|
993
|
-
return None if inplace else dest
|
1108
|
+
# This is required to trigger data builds if the `other` is an unbuilt `BlueprintCircuit`,
|
1109
|
+
# so we can the access the complete `CircuitData` object at `_data`.
|
1110
|
+
_ = other.data
|
994
1111
|
|
995
|
-
|
996
|
-
dest
|
997
|
-
)
|
1112
|
+
def copy_with_remapping(
|
1113
|
+
source, dest, bit_map, var_map, inline_captures, new_qubits=None, new_clbits=None
|
1114
|
+
):
|
1115
|
+
# Copy the instructions from `source` into `dest`, remapping variables in instructions
|
1116
|
+
# according to `var_map`. If `new_qubits` or `new_clbits` are given, the qubits and
|
1117
|
+
# clbits of the source instruction are remapped to those as well.
|
1118
|
+
for var in source.iter_input_vars():
|
1119
|
+
dest.add_input(replace_var(var, var_map))
|
1120
|
+
if inline_captures:
|
1121
|
+
for var in source.iter_captured_vars():
|
1122
|
+
replacement = replace_var(var, var_map)
|
1123
|
+
if not dest.has_var(replace_var(var, var_map)):
|
1124
|
+
if var is replacement:
|
1125
|
+
raise CircuitError(
|
1126
|
+
f"Variable '{var}' to be inlined is not in the base circuit."
|
1127
|
+
" If you wanted it to be automatically added, use"
|
1128
|
+
" `inline_captures=False`."
|
1129
|
+
)
|
1130
|
+
raise CircuitError(
|
1131
|
+
f"Replacement '{replacement}' for variable '{var}' is not in the"
|
1132
|
+
" base circuit. Is the replacement correct?"
|
1133
|
+
)
|
1134
|
+
else:
|
1135
|
+
for var in source.iter_captured_vars():
|
1136
|
+
dest.add_capture(replace_var(var, var_map))
|
1137
|
+
for var in source.iter_declared_vars():
|
1138
|
+
dest.add_uninitialized_var(replace_var(var, var_map))
|
1139
|
+
|
1140
|
+
def recurse_block(block):
|
1141
|
+
# Recurse the remapping into a control-flow block. Note that this doesn't remap the
|
1142
|
+
# clbits within; the story around nested classical-register-based control-flow
|
1143
|
+
# doesn't really work in the current data model, and we hope to replace it with
|
1144
|
+
# `Expr`-based control-flow everywhere.
|
1145
|
+
new_block = block.copy_empty_like()
|
1146
|
+
new_block._vars_input = {}
|
1147
|
+
new_block._vars_capture = {}
|
1148
|
+
new_block._vars_local = {}
|
1149
|
+
# For the recursion, we never want to inline captured variables because we're not
|
1150
|
+
# copying onto a base that has variables.
|
1151
|
+
copy_with_remapping(block, new_block, bit_map, var_map, inline_captures=False)
|
1152
|
+
return new_block
|
1153
|
+
|
1154
|
+
variable_mapper = _classical_resource_map.VariableMapper(
|
1155
|
+
dest.cregs, bit_map, var_map, add_register=dest.add_register
|
1156
|
+
)
|
998
1157
|
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1158
|
+
def map_vars(op):
|
1159
|
+
n_op = op
|
1160
|
+
is_control_flow = isinstance(n_op, ControlFlowOp)
|
1161
|
+
if (
|
1162
|
+
not is_control_flow
|
1163
|
+
and (condition := getattr(n_op, "condition", None)) is not None
|
1164
|
+
):
|
1165
|
+
n_op = n_op.copy() if n_op is op and copy else n_op
|
1166
|
+
n_op.condition = variable_mapper.map_condition(condition)
|
1167
|
+
elif is_control_flow:
|
1168
|
+
n_op = n_op.replace_blocks(recurse_block(block) for block in n_op.blocks)
|
1169
|
+
if isinstance(n_op, (IfElseOp, WhileLoopOp)):
|
1170
|
+
n_op.condition = variable_mapper.map_condition(n_op.condition)
|
1171
|
+
elif isinstance(n_op, SwitchCaseOp):
|
1172
|
+
n_op.target = variable_mapper.map_target(n_op.target)
|
1173
|
+
elif isinstance(n_op, Store):
|
1174
|
+
n_op = Store(
|
1175
|
+
variable_mapper.map_expr(n_op.lvalue), variable_mapper.map_expr(n_op.rvalue)
|
1176
|
+
)
|
1177
|
+
return n_op.copy() if n_op is op and copy else n_op
|
1006
1178
|
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1179
|
+
instructions = source._data.copy()
|
1180
|
+
instructions.replace_bits(qubits=new_qubits, clbits=new_clbits)
|
1181
|
+
instructions.map_ops(map_vars)
|
1182
|
+
dest._current_scope().extend(instructions)
|
1010
1183
|
|
1011
1184
|
append_existing = None
|
1012
1185
|
if front:
|
1013
1186
|
append_existing = dest._data.copy()
|
1014
1187
|
dest.clear()
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1188
|
+
copy_with_remapping(
|
1189
|
+
other,
|
1190
|
+
dest,
|
1191
|
+
bit_map=edge_map,
|
1192
|
+
# The actual `Var: Var` map gets built up from the more freeform user input as we
|
1193
|
+
# encounter the variables, since the user might be using string keys to refer to more
|
1194
|
+
# than one variable in separated scopes of control-flow operations.
|
1195
|
+
var_map={},
|
1196
|
+
inline_captures=inline_captures,
|
1197
|
+
new_qubits=mapped_qubits,
|
1198
|
+
new_clbits=mapped_clbits,
|
1199
|
+
)
|
1018
1200
|
if append_existing:
|
1019
|
-
|
1201
|
+
dest._current_scope().extend(append_existing)
|
1020
1202
|
|
1021
1203
|
return None if inplace else dest
|
1022
1204
|
|
@@ -1131,6 +1313,74 @@ class QuantumCircuit:
|
|
1131
1313
|
"""
|
1132
1314
|
return self._ancillas
|
1133
1315
|
|
1316
|
+
@property
|
1317
|
+
def num_vars(self) -> int:
|
1318
|
+
"""The number of real-time classical variables in the circuit.
|
1319
|
+
|
1320
|
+
This is the length of the :meth:`iter_vars` iterable."""
|
1321
|
+
return self.num_input_vars + self.num_captured_vars + self.num_declared_vars
|
1322
|
+
|
1323
|
+
@property
|
1324
|
+
def num_input_vars(self) -> int:
|
1325
|
+
"""The number of real-time classical variables in the circuit marked as circuit inputs.
|
1326
|
+
|
1327
|
+
This is the length of the :meth:`iter_input_vars` iterable. If this is non-zero,
|
1328
|
+
:attr:`num_captured_vars` must be zero."""
|
1329
|
+
return len(self._vars_input)
|
1330
|
+
|
1331
|
+
@property
|
1332
|
+
def num_captured_vars(self) -> int:
|
1333
|
+
"""The number of real-time classical variables in the circuit marked as captured from an
|
1334
|
+
enclosing scope.
|
1335
|
+
|
1336
|
+
This is the length of the :meth:`iter_captured_vars` iterable. If this is non-zero,
|
1337
|
+
:attr:`num_input_vars` must be zero."""
|
1338
|
+
return len(self._vars_capture)
|
1339
|
+
|
1340
|
+
@property
|
1341
|
+
def num_declared_vars(self) -> int:
|
1342
|
+
"""The number of real-time classical variables in the circuit that are declared by this
|
1343
|
+
circuit scope, excluding inputs or captures.
|
1344
|
+
|
1345
|
+
This is the length of the :meth:`iter_declared_vars` iterable."""
|
1346
|
+
return len(self._vars_local)
|
1347
|
+
|
1348
|
+
def iter_vars(self) -> typing.Iterable[expr.Var]:
|
1349
|
+
"""Get an iterable over all real-time classical variables in scope within this circuit.
|
1350
|
+
|
1351
|
+
This method will iterate over all variables in scope. For more fine-grained iterators, see
|
1352
|
+
:meth:`iter_declared_vars`, :meth:`iter_input_vars` and :meth:`iter_captured_vars`."""
|
1353
|
+
if self._control_flow_scopes:
|
1354
|
+
builder = self._control_flow_scopes[-1]
|
1355
|
+
return itertools.chain(builder.iter_captured_vars(), builder.iter_local_vars())
|
1356
|
+
return itertools.chain(
|
1357
|
+
self._vars_input.values(), self._vars_capture.values(), self._vars_local.values()
|
1358
|
+
)
|
1359
|
+
|
1360
|
+
def iter_declared_vars(self) -> typing.Iterable[expr.Var]:
|
1361
|
+
"""Get an iterable over all real-time classical variables that are declared with automatic
|
1362
|
+
storage duration in this scope. This excludes input variables (see :meth:`iter_input_vars`)
|
1363
|
+
and captured variables (see :meth:`iter_captured_vars`)."""
|
1364
|
+
if self._control_flow_scopes:
|
1365
|
+
return self._control_flow_scopes[-1].iter_local_vars()
|
1366
|
+
return self._vars_local.values()
|
1367
|
+
|
1368
|
+
def iter_input_vars(self) -> typing.Iterable[expr.Var]:
|
1369
|
+
"""Get an iterable over all real-time classical variables that are declared as inputs to
|
1370
|
+
this circuit scope. This excludes locally declared variables (see
|
1371
|
+
:meth:`iter_declared_vars`) and captured variables (see :meth:`iter_captured_vars`)."""
|
1372
|
+
if self._control_flow_scopes:
|
1373
|
+
return ()
|
1374
|
+
return self._vars_input.values()
|
1375
|
+
|
1376
|
+
def iter_captured_vars(self) -> typing.Iterable[expr.Var]:
|
1377
|
+
"""Get an iterable over all real-time classical variables that are captured by this circuit
|
1378
|
+
scope from a containing scope. This excludes input variables (see :meth:`iter_input_vars`)
|
1379
|
+
and locally declared variables (see :meth:`iter_declared_vars`)."""
|
1380
|
+
if self._control_flow_scopes:
|
1381
|
+
return self._control_flow_scopes[-1].iter_captured_vars()
|
1382
|
+
return self._vars_capture.values()
|
1383
|
+
|
1134
1384
|
def __and__(self, rhs: "QuantumCircuit") -> "QuantumCircuit":
|
1135
1385
|
"""Overload & to implement self.compose."""
|
1136
1386
|
return self.compose(rhs)
|
@@ -1206,6 +1456,8 @@ class QuantumCircuit:
|
|
1206
1456
|
instruction: Operation | CircuitInstruction,
|
1207
1457
|
qargs: Sequence[QubitSpecifier] | None = None,
|
1208
1458
|
cargs: Sequence[ClbitSpecifier] | None = None,
|
1459
|
+
*,
|
1460
|
+
copy: bool = True,
|
1209
1461
|
) -> InstructionSet:
|
1210
1462
|
"""Append one or more instructions to the end of the circuit, modifying the circuit in
|
1211
1463
|
place.
|
@@ -1223,6 +1475,11 @@ class QuantumCircuit:
|
|
1223
1475
|
:class:`.CircuitInstruction` with all its context.
|
1224
1476
|
qargs: specifiers of the :class:`~.circuit.Qubit`\\ s to attach instruction to.
|
1225
1477
|
cargs: specifiers of the :class:`.Clbit`\\ s to attach instruction to.
|
1478
|
+
copy: if ``True`` (the default), then the incoming ``instruction`` is copied before
|
1479
|
+
adding it to the circuit if it contains symbolic parameters, so it can be safely
|
1480
|
+
mutated without affecting other circuits the same instruction might be in. If you
|
1481
|
+
are sure this instruction will not be in other circuits, you can set this ``False``
|
1482
|
+
for a small speedup.
|
1226
1483
|
|
1227
1484
|
Returns:
|
1228
1485
|
qiskit.circuit.InstructionSet: a handle to the :class:`.CircuitInstruction`\\ s that
|
@@ -1261,11 +1518,25 @@ class QuantumCircuit:
|
|
1261
1518
|
if params := getattr(operation, "params", ()):
|
1262
1519
|
is_parameter = False
|
1263
1520
|
for param in params:
|
1264
|
-
is_parameter = is_parameter or isinstance(param,
|
1521
|
+
is_parameter = is_parameter or isinstance(param, ParameterExpression)
|
1265
1522
|
if isinstance(param, expr.Expr):
|
1266
1523
|
param = _validate_expr(circuit_scope, param)
|
1267
|
-
if is_parameter:
|
1268
|
-
operation =
|
1524
|
+
if copy and is_parameter:
|
1525
|
+
operation = _copy.deepcopy(operation)
|
1526
|
+
if isinstance(operation, ControlFlowOp):
|
1527
|
+
# Verify that any variable bindings are valid. Control-flow ops are already enforced
|
1528
|
+
# by the class not to contain 'input' variables.
|
1529
|
+
if bad_captures := {
|
1530
|
+
var
|
1531
|
+
for var in itertools.chain.from_iterable(
|
1532
|
+
block.iter_captured_vars() for block in operation.blocks
|
1533
|
+
)
|
1534
|
+
if not self.has_var(var)
|
1535
|
+
}:
|
1536
|
+
raise CircuitError(
|
1537
|
+
f"Control-flow op attempts to capture '{bad_captures}'"
|
1538
|
+
" which are not in this circuit"
|
1539
|
+
)
|
1269
1540
|
|
1270
1541
|
expanded_qargs = [self.qbit_argument_conversion(qarg) for qarg in qargs or []]
|
1271
1542
|
expanded_cargs = [self.cbit_argument_conversion(carg) for carg in cargs or []]
|
@@ -1412,6 +1683,11 @@ class QuantumCircuit:
|
|
1412
1683
|
|
1413
1684
|
assert qc.get_parameter("my_param", None) is my_param
|
1414
1685
|
assert qc.get_parameter("unknown_param", None) is None
|
1686
|
+
|
1687
|
+
See also:
|
1688
|
+
:meth:`get_var`
|
1689
|
+
A similar method, but for :class:`.expr.Var` run-time variables instead of
|
1690
|
+
:class:`.Parameter` compile-time parameters.
|
1415
1691
|
"""
|
1416
1692
|
if (parameter := self._parameter_table.parameter_from_name(name, None)) is None:
|
1417
1693
|
if default is Ellipsis:
|
@@ -1433,11 +1709,314 @@ class QuantumCircuit:
|
|
1433
1709
|
See also:
|
1434
1710
|
:meth:`QuantumCircuit.get_parameter`
|
1435
1711
|
Retrieve the :class:`.Parameter` instance from this circuit by name.
|
1712
|
+
:meth:`QuantumCircuit.has_var`
|
1713
|
+
A similar method to this, but for run-time :class:`.expr.Var` variables instead of
|
1714
|
+
compile-time :class:`.Parameter`\\ s.
|
1436
1715
|
"""
|
1437
1716
|
if isinstance(name_or_param, str):
|
1438
1717
|
return self.get_parameter(name_or_param, None) is not None
|
1439
1718
|
return self.get_parameter(name_or_param.name) == name_or_param
|
1440
1719
|
|
1720
|
+
@typing.overload
|
1721
|
+
def get_var(self, name: str, default: T) -> Union[expr.Var, T]: ...
|
1722
|
+
|
1723
|
+
# The builtin `types` module has `EllipsisType`, but only from 3.10+!
|
1724
|
+
@typing.overload
|
1725
|
+
def get_var(self, name: str, default: type(...) = ...) -> expr.Var: ...
|
1726
|
+
|
1727
|
+
# We use a _literal_ `Ellipsis` as the marker value to leave `None` available as a default.
|
1728
|
+
def get_var(self, name: str, default: typing.Any = ...):
|
1729
|
+
"""Retrieve a variable that is accessible in this circuit scope by name.
|
1730
|
+
|
1731
|
+
Args:
|
1732
|
+
name: the name of the variable to retrieve.
|
1733
|
+
default: if given, this value will be returned if the variable is not present. If it
|
1734
|
+
is not given, a :exc:`KeyError` is raised instead.
|
1735
|
+
|
1736
|
+
Returns:
|
1737
|
+
The corresponding variable.
|
1738
|
+
|
1739
|
+
Raises:
|
1740
|
+
KeyError: if no default is given, but the variable does not exist.
|
1741
|
+
|
1742
|
+
Examples:
|
1743
|
+
Retrieve a variable by name from a circuit::
|
1744
|
+
|
1745
|
+
from qiskit.circuit import QuantumCircuit
|
1746
|
+
|
1747
|
+
# Create a circuit and create a variable in it.
|
1748
|
+
qc = QuantumCircuit()
|
1749
|
+
my_var = qc.add_var("my_var", False)
|
1750
|
+
|
1751
|
+
# We can use 'my_var' as a variable, but let's say we've lost the Python object and
|
1752
|
+
# need to retrieve it.
|
1753
|
+
my_var_again = qc.get_var("my_var")
|
1754
|
+
|
1755
|
+
assert my_var is my_var_again
|
1756
|
+
|
1757
|
+
Get a variable from a circuit by name, returning some default if it is not present::
|
1758
|
+
|
1759
|
+
assert qc.get_var("my_var", None) is my_var
|
1760
|
+
assert qc.get_var("unknown_variable", None) is None
|
1761
|
+
|
1762
|
+
See also:
|
1763
|
+
:meth:`get_parameter`
|
1764
|
+
A similar method, but for :class:`.Parameter` compile-time parameters instead of
|
1765
|
+
:class:`.expr.Var` run-time variables.
|
1766
|
+
"""
|
1767
|
+
if (out := self._current_scope().get_var(name)) is not None:
|
1768
|
+
return out
|
1769
|
+
if default is Ellipsis:
|
1770
|
+
raise KeyError(f"no variable named '{name}' is present")
|
1771
|
+
return default
|
1772
|
+
|
1773
|
+
def has_var(self, name_or_var: str | expr.Var, /) -> bool:
|
1774
|
+
"""Check whether a variable is accessible in this scope.
|
1775
|
+
|
1776
|
+
Args:
|
1777
|
+
name_or_var: the variable, or name of a variable to check. If this is a
|
1778
|
+
:class:`.expr.Var` node, the variable must be exactly the given one for this
|
1779
|
+
function to return ``True``.
|
1780
|
+
|
1781
|
+
Returns:
|
1782
|
+
whether a matching variable is accessible.
|
1783
|
+
|
1784
|
+
See also:
|
1785
|
+
:meth:`QuantumCircuit.get_var`
|
1786
|
+
Retrieve the :class:`.expr.Var` instance from this circuit by name.
|
1787
|
+
:meth:`QuantumCircuit.has_parameter`
|
1788
|
+
A similar method to this, but for compile-time :class:`.Parameter`\\ s instead of
|
1789
|
+
run-time :class:`.expr.Var` variables.
|
1790
|
+
"""
|
1791
|
+
if isinstance(name_or_var, str):
|
1792
|
+
return self.get_var(name_or_var, None) is not None
|
1793
|
+
return self.get_var(name_or_var.name, None) == name_or_var
|
1794
|
+
|
1795
|
+
def _prepare_new_var(
|
1796
|
+
self, name_or_var: str | expr.Var, type_: types.Type | None, /
|
1797
|
+
) -> expr.Var:
|
1798
|
+
"""The common logic for preparing and validating a new :class:`~.expr.Var` for the circuit.
|
1799
|
+
|
1800
|
+
The given ``type_`` can be ``None`` if the variable specifier is already a :class:`.Var`,
|
1801
|
+
and must be a :class:`~.types.Type` if it is a string. The argument is ignored if the given
|
1802
|
+
first argument is a :class:`.Var` already.
|
1803
|
+
|
1804
|
+
Returns the validated variable, which is guaranteed to be safe to add to the circuit."""
|
1805
|
+
if isinstance(name_or_var, str):
|
1806
|
+
if type_ is None:
|
1807
|
+
raise CircuitError("the type must be known when creating a 'Var' from a string")
|
1808
|
+
var = expr.Var.new(name_or_var, type_)
|
1809
|
+
else:
|
1810
|
+
var = name_or_var
|
1811
|
+
if not var.standalone:
|
1812
|
+
raise CircuitError(
|
1813
|
+
"cannot add variables that wrap `Clbit` or `ClassicalRegister` instances."
|
1814
|
+
" Use `add_bits` or `add_register` as appropriate."
|
1815
|
+
)
|
1816
|
+
|
1817
|
+
# The `var` is guaranteed to have a name because we already excluded the cases where it's
|
1818
|
+
# wrapping a bit/register.
|
1819
|
+
if (previous := self.get_var(var.name, default=None)) is not None:
|
1820
|
+
if previous == var:
|
1821
|
+
raise CircuitError(f"'{var}' is already present in the circuit")
|
1822
|
+
raise CircuitError(f"cannot add '{var}' as its name shadows the existing '{previous}'")
|
1823
|
+
return var
|
1824
|
+
|
1825
|
+
def add_var(self, name_or_var: str | expr.Var, /, initial: typing.Any) -> expr.Var:
|
1826
|
+
"""Add a classical variable with automatic storage and scope to this circuit.
|
1827
|
+
|
1828
|
+
The variable is considered to have been "declared" at the beginning of the circuit, but it
|
1829
|
+
only becomes initialized at the point of the circuit that you call this method, so it can
|
1830
|
+
depend on variables defined before it.
|
1831
|
+
|
1832
|
+
Args:
|
1833
|
+
name_or_var: either a string of the variable name, or an existing instance of
|
1834
|
+
:class:`~.expr.Var` to re-use. Variables cannot shadow names that are already in
|
1835
|
+
use within the circuit.
|
1836
|
+
initial: the value to initialize this variable with. If the first argument was given
|
1837
|
+
as a string name, the type of the resulting variable is inferred from the initial
|
1838
|
+
expression; to control this more manually, either use :meth:`.Var.new` to manually
|
1839
|
+
construct a new variable with the desired type, or use :func:`.expr.cast` to cast
|
1840
|
+
the initializer to the desired type.
|
1841
|
+
|
1842
|
+
This must be either a :class:`~.expr.Expr` node, or a value that can be lifted to
|
1843
|
+
one using :class:`.expr.lift`.
|
1844
|
+
|
1845
|
+
Returns:
|
1846
|
+
The created variable. If a :class:`~.expr.Var` instance was given, the exact same
|
1847
|
+
object will be returned.
|
1848
|
+
|
1849
|
+
Raises:
|
1850
|
+
CircuitError: if the variable cannot be created due to shadowing an existing variable.
|
1851
|
+
|
1852
|
+
Examples:
|
1853
|
+
Define a new variable given just a name and an initializer expression::
|
1854
|
+
|
1855
|
+
from qiskit.circuit import QuantumCircuit
|
1856
|
+
|
1857
|
+
qc = QuantumCircuit(2)
|
1858
|
+
my_var = qc.add_var("my_var", False)
|
1859
|
+
|
1860
|
+
Reuse a variable that may have been taken from a related circuit, or otherwise
|
1861
|
+
constructed manually, and initialize it to some more complicated expression::
|
1862
|
+
|
1863
|
+
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
|
1864
|
+
from qiskit.circuit.classical import expr, types
|
1865
|
+
|
1866
|
+
my_var = expr.Var.new("my_var", types.Uint(8))
|
1867
|
+
|
1868
|
+
cr1 = ClassicalRegister(8, "cr1")
|
1869
|
+
cr2 = ClassicalRegister(8, "cr2")
|
1870
|
+
qc = QuantumCircuit(QuantumRegister(8), cr1, cr2)
|
1871
|
+
|
1872
|
+
# Get some measurement results into each register.
|
1873
|
+
qc.h(0)
|
1874
|
+
for i in range(1, 8):
|
1875
|
+
qc.cx(0, i)
|
1876
|
+
qc.measure(range(8), cr1)
|
1877
|
+
|
1878
|
+
qc.reset(range(8))
|
1879
|
+
qc.h(0)
|
1880
|
+
for i in range(1, 8):
|
1881
|
+
qc.cx(0, i)
|
1882
|
+
qc.measure(range(8), cr2)
|
1883
|
+
|
1884
|
+
# Now when we add the variable, it is initialized using the real-time state of the
|
1885
|
+
# two classical registers we measured into above.
|
1886
|
+
qc.add_var(my_var, expr.bit_and(cr1, cr2))
|
1887
|
+
"""
|
1888
|
+
# Validate the initialiser first to catch cases where the variable to be declared is being
|
1889
|
+
# used in the initialiser.
|
1890
|
+
circuit_scope = self._current_scope()
|
1891
|
+
# Convenience method to widen Python integer literals to the right width during the initial
|
1892
|
+
# lift, if the type is already known via the variable.
|
1893
|
+
if (
|
1894
|
+
isinstance(name_or_var, expr.Var)
|
1895
|
+
and name_or_var.type.kind is types.Uint
|
1896
|
+
and isinstance(initial, int)
|
1897
|
+
and not isinstance(initial, bool)
|
1898
|
+
):
|
1899
|
+
coerce_type = name_or_var.type
|
1900
|
+
else:
|
1901
|
+
coerce_type = None
|
1902
|
+
initial = _validate_expr(circuit_scope, expr.lift(initial, coerce_type))
|
1903
|
+
if isinstance(name_or_var, str):
|
1904
|
+
var = expr.Var.new(name_or_var, initial.type)
|
1905
|
+
elif not name_or_var.standalone:
|
1906
|
+
raise CircuitError(
|
1907
|
+
"cannot add variables that wrap `Clbit` or `ClassicalRegister` instances."
|
1908
|
+
)
|
1909
|
+
else:
|
1910
|
+
var = name_or_var
|
1911
|
+
circuit_scope.add_uninitialized_var(var)
|
1912
|
+
try:
|
1913
|
+
# Store is responsible for ensuring the type safety of the initialisation.
|
1914
|
+
store = Store(var, initial)
|
1915
|
+
except CircuitError:
|
1916
|
+
circuit_scope.remove_var(var)
|
1917
|
+
raise
|
1918
|
+
circuit_scope.append(CircuitInstruction(store, (), ()))
|
1919
|
+
return var
|
1920
|
+
|
1921
|
+
def add_uninitialized_var(self, var: expr.Var, /):
|
1922
|
+
"""Add a variable with no initializer.
|
1923
|
+
|
1924
|
+
In most cases, you should use :meth:`add_var` to initialize the variable. To use this
|
1925
|
+
function, you must already hold a :class:`~.expr.Var` instance, as the use of the function
|
1926
|
+
typically only makes sense in copying contexts.
|
1927
|
+
|
1928
|
+
.. warning::
|
1929
|
+
|
1930
|
+
Qiskit makes no assertions about what an uninitialized variable will evaluate to at
|
1931
|
+
runtime, and some hardware may reject this as an error.
|
1932
|
+
|
1933
|
+
You should treat this function with caution, and as a low-level primitive that is useful
|
1934
|
+
only in special cases of programmatically rebuilding two like circuits.
|
1935
|
+
|
1936
|
+
Args:
|
1937
|
+
var: the variable to add.
|
1938
|
+
"""
|
1939
|
+
# This function is deliberately meant to be a bit harder to find, to have a long descriptive
|
1940
|
+
# name, and to be a bit less ergonomic than `add_var` (i.e. not allowing the (name, type)
|
1941
|
+
# overload) to discourage people from using it when they should use `add_var`.
|
1942
|
+
#
|
1943
|
+
# This function exists so that there is a method to emulate `copy_empty_like`'s behaviour of
|
1944
|
+
# adding uninitialised variables, which there's no obvious way around. We need to be sure
|
1945
|
+
# that _some_ sort of handling of uninitialised variables is taken into account in our
|
1946
|
+
# structures, so that doesn't become a huge edge case, even though we make no assertions
|
1947
|
+
# about the _meaning_ if such an expression was run on hardware.
|
1948
|
+
if self._control_flow_scopes:
|
1949
|
+
raise CircuitError("cannot add an uninitialized variable in a control-flow scope")
|
1950
|
+
if not var.standalone:
|
1951
|
+
raise CircuitError("cannot add a variable wrapping a bit or register to a circuit")
|
1952
|
+
self._builder_api.add_uninitialized_var(var)
|
1953
|
+
|
1954
|
+
def add_capture(self, var: expr.Var):
|
1955
|
+
"""Add a variable to the circuit that it should capture from a scope it will be contained
|
1956
|
+
within.
|
1957
|
+
|
1958
|
+
This method requires a :class:`~.expr.Var` node to enforce that you've got a handle to one,
|
1959
|
+
because you will need to declare the same variable using the same object into the outer
|
1960
|
+
circuit.
|
1961
|
+
|
1962
|
+
This is a low-level method, which is only really useful if you are manually constructing
|
1963
|
+
control-flow operations. You typically will not need to call this method, assuming you
|
1964
|
+
are using the builder interface for control-flow scopes (``with`` context-manager statements
|
1965
|
+
for :meth:`if_test` and the other scoping constructs). The builder interface will
|
1966
|
+
automatically make the inner scopes closures on your behalf by capturing any variables that
|
1967
|
+
are used within them.
|
1968
|
+
|
1969
|
+
Args:
|
1970
|
+
var: the variable to capture from an enclosing scope.
|
1971
|
+
|
1972
|
+
Raises:
|
1973
|
+
CircuitError: if the variable cannot be created due to shadowing an existing variable.
|
1974
|
+
"""
|
1975
|
+
if self._control_flow_scopes:
|
1976
|
+
# Allow manual capturing. Not sure why it'd be useful, but there's a clear expected
|
1977
|
+
# behaviour here.
|
1978
|
+
self._control_flow_scopes[-1].use_var(var)
|
1979
|
+
return
|
1980
|
+
if self._vars_input:
|
1981
|
+
raise CircuitError(
|
1982
|
+
"circuits with input variables cannot be enclosed, so cannot be closures"
|
1983
|
+
)
|
1984
|
+
self._vars_capture[var.name] = self._prepare_new_var(var, None)
|
1985
|
+
|
1986
|
+
@typing.overload
|
1987
|
+
def add_input(self, name_or_var: str, type_: types.Type, /) -> expr.Var: ...
|
1988
|
+
|
1989
|
+
@typing.overload
|
1990
|
+
def add_input(self, name_or_var: expr.Var, type_: None = None, /) -> expr.Var: ...
|
1991
|
+
|
1992
|
+
def add_input( # pylint: disable=missing-raises-doc
|
1993
|
+
self, name_or_var: str | expr.Var, type_: types.Type | None = None, /
|
1994
|
+
) -> expr.Var:
|
1995
|
+
"""Register a variable as an input to the circuit.
|
1996
|
+
|
1997
|
+
Args:
|
1998
|
+
name_or_var: either a string name, or an existing :class:`~.expr.Var` node to use as the
|
1999
|
+
input variable.
|
2000
|
+
type_: if the name is given as a string, then this must be a :class:`~.types.Type` to
|
2001
|
+
use for the variable. If the variable is given as an existing :class:`~.expr.Var`,
|
2002
|
+
then this must not be given, and will instead be read from the object itself.
|
2003
|
+
|
2004
|
+
Returns:
|
2005
|
+
the variable created, or the same variable as was passed in.
|
2006
|
+
|
2007
|
+
Raises:
|
2008
|
+
CircuitError: if the variable cannot be created due to shadowing an existing variable.
|
2009
|
+
"""
|
2010
|
+
if self._control_flow_scopes:
|
2011
|
+
raise CircuitError("cannot add an input variable in a control-flow scope")
|
2012
|
+
if self._vars_capture:
|
2013
|
+
raise CircuitError("circuits to be enclosed with captures cannot have input variables")
|
2014
|
+
if isinstance(name_or_var, expr.Var) and type_ is not None:
|
2015
|
+
raise ValueError("cannot give an explicit type with an existing Var")
|
2016
|
+
var = self._prepare_new_var(name_or_var, type_)
|
2017
|
+
self._vars_input[var.name] = var
|
2018
|
+
return var
|
2019
|
+
|
1441
2020
|
def add_register(self, *regs: Register | int | Sequence[Bit]) -> None:
|
1442
2021
|
"""Add registers."""
|
1443
2022
|
if not regs:
|
@@ -2064,7 +2643,7 @@ class QuantumCircuit:
|
|
2064
2643
|
"""
|
2065
2644
|
return self.num_unitary_factors()
|
2066
2645
|
|
2067
|
-
def copy(self, name: str | None = None) ->
|
2646
|
+
def copy(self, name: str | None = None) -> typing.Self:
|
2068
2647
|
"""Copy the circuit.
|
2069
2648
|
|
2070
2649
|
Args:
|
@@ -2100,16 +2679,47 @@ class QuantumCircuit:
|
|
2100
2679
|
)
|
2101
2680
|
return cpy
|
2102
2681
|
|
2103
|
-
def copy_empty_like(
|
2682
|
+
def copy_empty_like(
|
2683
|
+
self,
|
2684
|
+
name: str | None = None,
|
2685
|
+
*,
|
2686
|
+
vars_mode: Literal["alike", "captures", "drop"] = "alike",
|
2687
|
+
) -> typing.Self:
|
2104
2688
|
"""Return a copy of self with the same structure but empty.
|
2105
2689
|
|
2106
2690
|
That structure includes:
|
2107
|
-
|
2108
|
-
|
2109
|
-
|
2691
|
+
|
2692
|
+
* name, calibrations and other metadata
|
2693
|
+
* global phase
|
2694
|
+
* all the qubits and clbits, including the registers
|
2695
|
+
* the realtime variables defined in the circuit, handled according to the ``vars`` keyword
|
2696
|
+
argument.
|
2697
|
+
|
2698
|
+
.. warning::
|
2699
|
+
|
2700
|
+
If the circuit contains any local variable declarations (those added by the
|
2701
|
+
``declarations`` argument to the circuit constructor, or using :meth:`add_var`), they
|
2702
|
+
may be **uninitialized** in the output circuit. You will need to manually add store
|
2703
|
+
instructions for them (see :class:`.Store` and :meth:`.QuantumCircuit.store`) to
|
2704
|
+
initialize them.
|
2110
2705
|
|
2111
2706
|
Args:
|
2112
|
-
name
|
2707
|
+
name: Name for the copied circuit. If None, then the name stays the same.
|
2708
|
+
vars_mode: The mode to handle realtime variables in.
|
2709
|
+
|
2710
|
+
alike
|
2711
|
+
The variables in the output circuit will have the same declaration semantics as
|
2712
|
+
in the original circuit. For example, ``input`` variables in the source will be
|
2713
|
+
``input`` variables in the output circuit.
|
2714
|
+
|
2715
|
+
captures
|
2716
|
+
All variables will be converted to captured variables. This is useful when you
|
2717
|
+
are building a new layer for an existing circuit that you will want to
|
2718
|
+
:meth:`compose` onto the base, since :meth:`compose` can inline captures onto
|
2719
|
+
the base circuit (but not other variables).
|
2720
|
+
|
2721
|
+
drop
|
2722
|
+
The output circuit will have no variables defined.
|
2113
2723
|
|
2114
2724
|
Returns:
|
2115
2725
|
QuantumCircuit: An empty copy of self.
|
@@ -2118,7 +2728,7 @@ class QuantumCircuit:
|
|
2118
2728
|
raise TypeError(
|
2119
2729
|
f"invalid name for a circuit: '{name}'. The name must be a string or 'None'."
|
2120
2730
|
)
|
2121
|
-
cpy =
|
2731
|
+
cpy = _copy.copy(self)
|
2122
2732
|
# copy registers correctly, in copy.copy they are only copied via reference
|
2123
2733
|
cpy.qregs = self.qregs.copy()
|
2124
2734
|
cpy.cregs = self.cregs.copy()
|
@@ -2127,6 +2737,24 @@ class QuantumCircuit:
|
|
2127
2737
|
cpy._qubit_indices = self._qubit_indices.copy()
|
2128
2738
|
cpy._clbit_indices = self._clbit_indices.copy()
|
2129
2739
|
|
2740
|
+
if vars_mode == "alike":
|
2741
|
+
# Note that this causes the local variables to be uninitialised, because the stores are
|
2742
|
+
# not copied. This can leave the circuit in a potentially dangerous state for users if
|
2743
|
+
# they don't re-add initialiser stores.
|
2744
|
+
cpy._vars_local = self._vars_local.copy()
|
2745
|
+
cpy._vars_input = self._vars_input.copy()
|
2746
|
+
cpy._vars_capture = self._vars_capture.copy()
|
2747
|
+
elif vars_mode == "captures":
|
2748
|
+
cpy._vars_local = {}
|
2749
|
+
cpy._vars_input = {}
|
2750
|
+
cpy._vars_capture = {var.name: var for var in self.iter_vars()}
|
2751
|
+
elif vars_mode == "drop":
|
2752
|
+
cpy._vars_local = {}
|
2753
|
+
cpy._vars_input = {}
|
2754
|
+
cpy._vars_capture = {}
|
2755
|
+
else: # pragma: no cover
|
2756
|
+
raise ValueError(f"unknown vars_mode: '{vars_mode}'")
|
2757
|
+
|
2130
2758
|
cpy._parameter_table = ParameterTable()
|
2131
2759
|
for parameter in getattr(cpy.global_phase, "parameters", ()):
|
2132
2760
|
cpy._parameter_table[parameter] = ParameterReferences(
|
@@ -2134,8 +2762,8 @@ class QuantumCircuit:
|
|
2134
2762
|
)
|
2135
2763
|
cpy._data = CircuitData(self._data.qubits, self._data.clbits)
|
2136
2764
|
|
2137
|
-
cpy._calibrations =
|
2138
|
-
cpy._metadata =
|
2765
|
+
cpy._calibrations = _copy.deepcopy(self._calibrations)
|
2766
|
+
cpy._metadata = _copy.deepcopy(self._metadata)
|
2139
2767
|
|
2140
2768
|
if name:
|
2141
2769
|
cpy.name = name
|
@@ -2184,7 +2812,38 @@ class QuantumCircuit:
|
|
2184
2812
|
"""
|
2185
2813
|
from .reset import Reset
|
2186
2814
|
|
2187
|
-
return self.append(Reset(), [qubit], [])
|
2815
|
+
return self.append(Reset(), [qubit], [], copy=False)
|
2816
|
+
|
2817
|
+
def store(self, lvalue: typing.Any, rvalue: typing.Any, /) -> InstructionSet:
|
2818
|
+
"""Store the result of the given real-time classical expression ``rvalue`` in the memory
|
2819
|
+
location defined by ``lvalue``.
|
2820
|
+
|
2821
|
+
Typically ``lvalue`` will be a :class:`~.expr.Var` node and ``rvalue`` will be some
|
2822
|
+
:class:`~.expr.Expr` to write into it, but anything that :func:`.expr.lift` can raise to an
|
2823
|
+
:class:`~.expr.Expr` is permissible in both places, and it will be called on them.
|
2824
|
+
|
2825
|
+
Args:
|
2826
|
+
lvalue: a valid specifier for a memory location in the circuit. This will typically be
|
2827
|
+
a :class:`~.expr.Var` node, but you can also write to :class:`.Clbit` or
|
2828
|
+
:class:`.ClassicalRegister` memory locations if your hardware supports it. The
|
2829
|
+
memory location must already be present in the circuit.
|
2830
|
+
rvalue: a real-time classical expression whose result should be written into the given
|
2831
|
+
memory location.
|
2832
|
+
|
2833
|
+
.. seealso::
|
2834
|
+
:class:`~.circuit.Store`
|
2835
|
+
The backing :class:`~.circuit.Instruction` class that represents this operation.
|
2836
|
+
|
2837
|
+
:meth:`add_var`
|
2838
|
+
Create a new variable in the circuit that can be written to with this method.
|
2839
|
+
"""
|
2840
|
+
# As a convenience, lift integer-literal rvalues to the matching width.
|
2841
|
+
lvalue = expr.lift(lvalue)
|
2842
|
+
rvalue_type = (
|
2843
|
+
lvalue.type if isinstance(rvalue, int) and not isinstance(rvalue, bool) else None
|
2844
|
+
)
|
2845
|
+
rvalue = expr.lift(rvalue, rvalue_type)
|
2846
|
+
return self.append(Store(lvalue, rvalue), (), (), copy=False)
|
2188
2847
|
|
2189
2848
|
def measure(self, qubit: QubitSpecifier, cbit: ClbitSpecifier) -> InstructionSet:
|
2190
2849
|
r"""Measure a quantum bit (``qubit``) in the Z basis into a classical bit (``cbit``).
|
@@ -2261,7 +2920,7 @@ class QuantumCircuit:
|
|
2261
2920
|
"""
|
2262
2921
|
from .measure import Measure
|
2263
2922
|
|
2264
|
-
return self.append(Measure(), [qubit], [cbit])
|
2923
|
+
return self.append(Measure(), [qubit], [cbit], copy=False)
|
2265
2924
|
|
2266
2925
|
def measure_active(self, inplace: bool = True) -> Optional["QuantumCircuit"]:
|
2267
2926
|
"""Adds measurement to all non-idle qubits. Creates a new ClassicalRegister with
|
@@ -2837,7 +3496,9 @@ class QuantumCircuit:
|
|
2837
3496
|
if qargs:
|
2838
3497
|
# This uses a `dict` not a `set` to guarantee a deterministic order to the arguments.
|
2839
3498
|
qubits = tuple({q: None for qarg in qargs for q in self.qbit_argument_conversion(qarg)})
|
2840
|
-
return self.append(
|
3499
|
+
return self.append(
|
3500
|
+
CircuitInstruction(Barrier(len(qubits), label=label), qubits, ()), copy=False
|
3501
|
+
)
|
2841
3502
|
else:
|
2842
3503
|
qubits = self.qubits.copy()
|
2843
3504
|
return self._current_scope().append(
|
@@ -2868,7 +3529,7 @@ class QuantumCircuit:
|
|
2868
3529
|
"""
|
2869
3530
|
if qarg is None:
|
2870
3531
|
qarg = self.qubits
|
2871
|
-
return self.append(Delay(duration, unit=unit), [qarg], [])
|
3532
|
+
return self.append(Delay(duration, unit=unit), [qarg], [], copy=False)
|
2872
3533
|
|
2873
3534
|
def h(self, qubit: QubitSpecifier) -> InstructionSet:
|
2874
3535
|
"""Apply :class:`~qiskit.circuit.library.HGate`.
|
@@ -2883,7 +3544,7 @@ class QuantumCircuit:
|
|
2883
3544
|
"""
|
2884
3545
|
from .library.standard_gates.h import HGate
|
2885
3546
|
|
2886
|
-
return self.append(HGate(), [qubit], [])
|
3547
|
+
return self.append(HGate(), [qubit], [], copy=False)
|
2887
3548
|
|
2888
3549
|
def ch(
|
2889
3550
|
self,
|
@@ -2910,7 +3571,10 @@ class QuantumCircuit:
|
|
2910
3571
|
from .library.standard_gates.h import CHGate
|
2911
3572
|
|
2912
3573
|
return self.append(
|
2913
|
-
CHGate(label=label, ctrl_state=ctrl_state),
|
3574
|
+
CHGate(label=label, ctrl_state=ctrl_state),
|
3575
|
+
[control_qubit, target_qubit],
|
3576
|
+
[],
|
3577
|
+
copy=False,
|
2914
3578
|
)
|
2915
3579
|
|
2916
3580
|
def id(self, qubit: QubitSpecifier) -> InstructionSet: # pylint: disable=invalid-name
|
@@ -2926,7 +3590,7 @@ class QuantumCircuit:
|
|
2926
3590
|
"""
|
2927
3591
|
from .library.standard_gates.i import IGate
|
2928
3592
|
|
2929
|
-
return self.append(IGate(), [qubit], [])
|
3593
|
+
return self.append(IGate(), [qubit], [], copy=False)
|
2930
3594
|
|
2931
3595
|
def ms(self, theta: ParameterValueType, qubits: Sequence[QubitSpecifier]) -> InstructionSet:
|
2932
3596
|
"""Apply :class:`~qiskit.circuit.library.MSGate`.
|
@@ -2943,7 +3607,7 @@ class QuantumCircuit:
|
|
2943
3607
|
# pylint: disable=cyclic-import
|
2944
3608
|
from .library.generalized_gates.gms import MSGate
|
2945
3609
|
|
2946
|
-
return self.append(MSGate(len(qubits), theta), qubits)
|
3610
|
+
return self.append(MSGate(len(qubits), theta), qubits, copy=False)
|
2947
3611
|
|
2948
3612
|
def p(self, theta: ParameterValueType, qubit: QubitSpecifier) -> InstructionSet:
|
2949
3613
|
"""Apply :class:`~qiskit.circuit.library.PhaseGate`.
|
@@ -2959,7 +3623,7 @@ class QuantumCircuit:
|
|
2959
3623
|
"""
|
2960
3624
|
from .library.standard_gates.p import PhaseGate
|
2961
3625
|
|
2962
|
-
return self.append(PhaseGate(theta), [qubit], [])
|
3626
|
+
return self.append(PhaseGate(theta), [qubit], [], copy=False)
|
2963
3627
|
|
2964
3628
|
def cp(
|
2965
3629
|
self,
|
@@ -2988,7 +3652,10 @@ class QuantumCircuit:
|
|
2988
3652
|
from .library.standard_gates.p import CPhaseGate
|
2989
3653
|
|
2990
3654
|
return self.append(
|
2991
|
-
CPhaseGate(theta, label=label, ctrl_state=ctrl_state),
|
3655
|
+
CPhaseGate(theta, label=label, ctrl_state=ctrl_state),
|
3656
|
+
[control_qubit, target_qubit],
|
3657
|
+
[],
|
3658
|
+
copy=False,
|
2992
3659
|
)
|
2993
3660
|
|
2994
3661
|
def mcp(
|
@@ -2996,6 +3663,7 @@ class QuantumCircuit:
|
|
2996
3663
|
lam: ParameterValueType,
|
2997
3664
|
control_qubits: Sequence[QubitSpecifier],
|
2998
3665
|
target_qubit: QubitSpecifier,
|
3666
|
+
ctrl_state: str | int | None = None,
|
2999
3667
|
) -> InstructionSet:
|
3000
3668
|
"""Apply :class:`~qiskit.circuit.library.MCPhaseGate`.
|
3001
3669
|
|
@@ -3005,6 +3673,9 @@ class QuantumCircuit:
|
|
3005
3673
|
lam: The angle of the rotation.
|
3006
3674
|
control_qubits: The qubits used as the controls.
|
3007
3675
|
target_qubit: The qubit(s) targeted by the gate.
|
3676
|
+
ctrl_state:
|
3677
|
+
The control state in decimal, or as a bitstring (e.g. '1'). Defaults to controlling
|
3678
|
+
on the '1' state.
|
3008
3679
|
|
3009
3680
|
Returns:
|
3010
3681
|
A handle to the instructions created.
|
@@ -3013,7 +3684,10 @@ class QuantumCircuit:
|
|
3013
3684
|
|
3014
3685
|
num_ctrl_qubits = len(control_qubits)
|
3015
3686
|
return self.append(
|
3016
|
-
MCPhaseGate(lam, num_ctrl_qubits
|
3687
|
+
MCPhaseGate(lam, num_ctrl_qubits, ctrl_state=ctrl_state),
|
3688
|
+
control_qubits[:] + [target_qubit],
|
3689
|
+
[],
|
3690
|
+
copy=False,
|
3017
3691
|
)
|
3018
3692
|
|
3019
3693
|
def r(
|
@@ -3033,7 +3707,7 @@ class QuantumCircuit:
|
|
3033
3707
|
"""
|
3034
3708
|
from .library.standard_gates.r import RGate
|
3035
3709
|
|
3036
|
-
return self.append(RGate(theta, phi), [qubit], [])
|
3710
|
+
return self.append(RGate(theta, phi), [qubit], [], copy=False)
|
3037
3711
|
|
3038
3712
|
def rv(
|
3039
3713
|
self,
|
@@ -3060,7 +3734,7 @@ class QuantumCircuit:
|
|
3060
3734
|
"""
|
3061
3735
|
from .library.generalized_gates.rv import RVGate
|
3062
3736
|
|
3063
|
-
return self.append(RVGate(vx, vy, vz), [qubit], [])
|
3737
|
+
return self.append(RVGate(vx, vy, vz), [qubit], [], copy=False)
|
3064
3738
|
|
3065
3739
|
def rccx(
|
3066
3740
|
self,
|
@@ -3082,7 +3756,9 @@ class QuantumCircuit:
|
|
3082
3756
|
"""
|
3083
3757
|
from .library.standard_gates.x import RCCXGate
|
3084
3758
|
|
3085
|
-
return self.append(
|
3759
|
+
return self.append(
|
3760
|
+
RCCXGate(), [control_qubit1, control_qubit2, target_qubit], [], copy=False
|
3761
|
+
)
|
3086
3762
|
|
3087
3763
|
def rcccx(
|
3088
3764
|
self,
|
@@ -3107,7 +3783,10 @@ class QuantumCircuit:
|
|
3107
3783
|
from .library.standard_gates.x import RC3XGate
|
3108
3784
|
|
3109
3785
|
return self.append(
|
3110
|
-
RC3XGate(),
|
3786
|
+
RC3XGate(),
|
3787
|
+
[control_qubit1, control_qubit2, control_qubit3, target_qubit],
|
3788
|
+
[],
|
3789
|
+
copy=False,
|
3111
3790
|
)
|
3112
3791
|
|
3113
3792
|
def rx(
|
@@ -3127,7 +3806,7 @@ class QuantumCircuit:
|
|
3127
3806
|
"""
|
3128
3807
|
from .library.standard_gates.rx import RXGate
|
3129
3808
|
|
3130
|
-
return self.append(RXGate(theta, label=label), [qubit], [])
|
3809
|
+
return self.append(RXGate(theta, label=label), [qubit], [], copy=False)
|
3131
3810
|
|
3132
3811
|
def crx(
|
3133
3812
|
self,
|
@@ -3156,7 +3835,10 @@ class QuantumCircuit:
|
|
3156
3835
|
from .library.standard_gates.rx import CRXGate
|
3157
3836
|
|
3158
3837
|
return self.append(
|
3159
|
-
CRXGate(theta, label=label, ctrl_state=ctrl_state),
|
3838
|
+
CRXGate(theta, label=label, ctrl_state=ctrl_state),
|
3839
|
+
[control_qubit, target_qubit],
|
3840
|
+
[],
|
3841
|
+
copy=False,
|
3160
3842
|
)
|
3161
3843
|
|
3162
3844
|
def rxx(
|
@@ -3176,7 +3858,7 @@ class QuantumCircuit:
|
|
3176
3858
|
"""
|
3177
3859
|
from .library.standard_gates.rxx import RXXGate
|
3178
3860
|
|
3179
|
-
return self.append(RXXGate(theta), [qubit1, qubit2], [])
|
3861
|
+
return self.append(RXXGate(theta), [qubit1, qubit2], [], copy=False)
|
3180
3862
|
|
3181
3863
|
def ry(
|
3182
3864
|
self, theta: ParameterValueType, qubit: QubitSpecifier, label: str | None = None
|
@@ -3195,7 +3877,7 @@ class QuantumCircuit:
|
|
3195
3877
|
"""
|
3196
3878
|
from .library.standard_gates.ry import RYGate
|
3197
3879
|
|
3198
|
-
return self.append(RYGate(theta, label=label), [qubit], [])
|
3880
|
+
return self.append(RYGate(theta, label=label), [qubit], [], copy=False)
|
3199
3881
|
|
3200
3882
|
def cry(
|
3201
3883
|
self,
|
@@ -3224,7 +3906,10 @@ class QuantumCircuit:
|
|
3224
3906
|
from .library.standard_gates.ry import CRYGate
|
3225
3907
|
|
3226
3908
|
return self.append(
|
3227
|
-
CRYGate(theta, label=label, ctrl_state=ctrl_state),
|
3909
|
+
CRYGate(theta, label=label, ctrl_state=ctrl_state),
|
3910
|
+
[control_qubit, target_qubit],
|
3911
|
+
[],
|
3912
|
+
copy=False,
|
3228
3913
|
)
|
3229
3914
|
|
3230
3915
|
def ryy(
|
@@ -3244,7 +3929,7 @@ class QuantumCircuit:
|
|
3244
3929
|
"""
|
3245
3930
|
from .library.standard_gates.ryy import RYYGate
|
3246
3931
|
|
3247
|
-
return self.append(RYYGate(theta), [qubit1, qubit2], [])
|
3932
|
+
return self.append(RYYGate(theta), [qubit1, qubit2], [], copy=False)
|
3248
3933
|
|
3249
3934
|
def rz(self, phi: ParameterValueType, qubit: QubitSpecifier) -> InstructionSet:
|
3250
3935
|
"""Apply :class:`~qiskit.circuit.library.RZGate`.
|
@@ -3260,7 +3945,7 @@ class QuantumCircuit:
|
|
3260
3945
|
"""
|
3261
3946
|
from .library.standard_gates.rz import RZGate
|
3262
3947
|
|
3263
|
-
return self.append(RZGate(phi), [qubit], [])
|
3948
|
+
return self.append(RZGate(phi), [qubit], [], copy=False)
|
3264
3949
|
|
3265
3950
|
def crz(
|
3266
3951
|
self,
|
@@ -3289,7 +3974,10 @@ class QuantumCircuit:
|
|
3289
3974
|
from .library.standard_gates.rz import CRZGate
|
3290
3975
|
|
3291
3976
|
return self.append(
|
3292
|
-
CRZGate(theta, label=label, ctrl_state=ctrl_state),
|
3977
|
+
CRZGate(theta, label=label, ctrl_state=ctrl_state),
|
3978
|
+
[control_qubit, target_qubit],
|
3979
|
+
[],
|
3980
|
+
copy=False,
|
3293
3981
|
)
|
3294
3982
|
|
3295
3983
|
def rzx(
|
@@ -3309,7 +3997,7 @@ class QuantumCircuit:
|
|
3309
3997
|
"""
|
3310
3998
|
from .library.standard_gates.rzx import RZXGate
|
3311
3999
|
|
3312
|
-
return self.append(RZXGate(theta), [qubit1, qubit2], [])
|
4000
|
+
return self.append(RZXGate(theta), [qubit1, qubit2], [], copy=False)
|
3313
4001
|
|
3314
4002
|
def rzz(
|
3315
4003
|
self, theta: ParameterValueType, qubit1: QubitSpecifier, qubit2: QubitSpecifier
|
@@ -3328,7 +4016,7 @@ class QuantumCircuit:
|
|
3328
4016
|
"""
|
3329
4017
|
from .library.standard_gates.rzz import RZZGate
|
3330
4018
|
|
3331
|
-
return self.append(RZZGate(theta), [qubit1, qubit2], [])
|
4019
|
+
return self.append(RZZGate(theta), [qubit1, qubit2], [], copy=False)
|
3332
4020
|
|
3333
4021
|
def ecr(self, qubit1: QubitSpecifier, qubit2: QubitSpecifier) -> InstructionSet:
|
3334
4022
|
"""Apply :class:`~qiskit.circuit.library.ECRGate`.
|
@@ -3343,7 +4031,7 @@ class QuantumCircuit:
|
|
3343
4031
|
"""
|
3344
4032
|
from .library.standard_gates.ecr import ECRGate
|
3345
4033
|
|
3346
|
-
return self.append(ECRGate(), [qubit1, qubit2], [])
|
4034
|
+
return self.append(ECRGate(), [qubit1, qubit2], [], copy=False)
|
3347
4035
|
|
3348
4036
|
def s(self, qubit: QubitSpecifier) -> InstructionSet:
|
3349
4037
|
"""Apply :class:`~qiskit.circuit.library.SGate`.
|
@@ -3358,7 +4046,7 @@ class QuantumCircuit:
|
|
3358
4046
|
"""
|
3359
4047
|
from .library.standard_gates.s import SGate
|
3360
4048
|
|
3361
|
-
return self.append(SGate(), [qubit], [])
|
4049
|
+
return self.append(SGate(), [qubit], [], copy=False)
|
3362
4050
|
|
3363
4051
|
def sdg(self, qubit: QubitSpecifier) -> InstructionSet:
|
3364
4052
|
"""Apply :class:`~qiskit.circuit.library.SdgGate`.
|
@@ -3373,7 +4061,7 @@ class QuantumCircuit:
|
|
3373
4061
|
"""
|
3374
4062
|
from .library.standard_gates.s import SdgGate
|
3375
4063
|
|
3376
|
-
return self.append(SdgGate(), [qubit], [])
|
4064
|
+
return self.append(SdgGate(), [qubit], [], copy=False)
|
3377
4065
|
|
3378
4066
|
def cs(
|
3379
4067
|
self,
|
@@ -3403,6 +4091,7 @@ class QuantumCircuit:
|
|
3403
4091
|
CSGate(label=label, ctrl_state=ctrl_state),
|
3404
4092
|
[control_qubit, target_qubit],
|
3405
4093
|
[],
|
4094
|
+
copy=False,
|
3406
4095
|
)
|
3407
4096
|
|
3408
4097
|
def csdg(
|
@@ -3433,6 +4122,7 @@ class QuantumCircuit:
|
|
3433
4122
|
CSdgGate(label=label, ctrl_state=ctrl_state),
|
3434
4123
|
[control_qubit, target_qubit],
|
3435
4124
|
[],
|
4125
|
+
copy=False,
|
3436
4126
|
)
|
3437
4127
|
|
3438
4128
|
def swap(self, qubit1: QubitSpecifier, qubit2: QubitSpecifier) -> InstructionSet:
|
@@ -3448,7 +4138,7 @@ class QuantumCircuit:
|
|
3448
4138
|
"""
|
3449
4139
|
from .library.standard_gates.swap import SwapGate
|
3450
4140
|
|
3451
|
-
return self.append(SwapGate(), [qubit1, qubit2], [])
|
4141
|
+
return self.append(SwapGate(), [qubit1, qubit2], [], copy=False)
|
3452
4142
|
|
3453
4143
|
def iswap(self, qubit1: QubitSpecifier, qubit2: QubitSpecifier) -> InstructionSet:
|
3454
4144
|
"""Apply :class:`~qiskit.circuit.library.iSwapGate`.
|
@@ -3463,7 +4153,7 @@ class QuantumCircuit:
|
|
3463
4153
|
"""
|
3464
4154
|
from .library.standard_gates.iswap import iSwapGate
|
3465
4155
|
|
3466
|
-
return self.append(iSwapGate(), [qubit1, qubit2], [])
|
4156
|
+
return self.append(iSwapGate(), [qubit1, qubit2], [], copy=False)
|
3467
4157
|
|
3468
4158
|
def cswap(
|
3469
4159
|
self,
|
@@ -3495,6 +4185,7 @@ class QuantumCircuit:
|
|
3495
4185
|
CSwapGate(label=label, ctrl_state=ctrl_state),
|
3496
4186
|
[control_qubit, target_qubit1, target_qubit2],
|
3497
4187
|
[],
|
4188
|
+
copy=False,
|
3498
4189
|
)
|
3499
4190
|
|
3500
4191
|
def sx(self, qubit: QubitSpecifier) -> InstructionSet:
|
@@ -3510,7 +4201,7 @@ class QuantumCircuit:
|
|
3510
4201
|
"""
|
3511
4202
|
from .library.standard_gates.sx import SXGate
|
3512
4203
|
|
3513
|
-
return self.append(SXGate(), [qubit], [])
|
4204
|
+
return self.append(SXGate(), [qubit], [], copy=False)
|
3514
4205
|
|
3515
4206
|
def sxdg(self, qubit: QubitSpecifier) -> InstructionSet:
|
3516
4207
|
"""Apply :class:`~qiskit.circuit.library.SXdgGate`.
|
@@ -3525,7 +4216,7 @@ class QuantumCircuit:
|
|
3525
4216
|
"""
|
3526
4217
|
from .library.standard_gates.sx import SXdgGate
|
3527
4218
|
|
3528
|
-
return self.append(SXdgGate(), [qubit], [])
|
4219
|
+
return self.append(SXdgGate(), [qubit], [], copy=False)
|
3529
4220
|
|
3530
4221
|
def csx(
|
3531
4222
|
self,
|
@@ -3555,6 +4246,7 @@ class QuantumCircuit:
|
|
3555
4246
|
CSXGate(label=label, ctrl_state=ctrl_state),
|
3556
4247
|
[control_qubit, target_qubit],
|
3557
4248
|
[],
|
4249
|
+
copy=False,
|
3558
4250
|
)
|
3559
4251
|
|
3560
4252
|
def t(self, qubit: QubitSpecifier) -> InstructionSet:
|
@@ -3570,7 +4262,7 @@ class QuantumCircuit:
|
|
3570
4262
|
"""
|
3571
4263
|
from .library.standard_gates.t import TGate
|
3572
4264
|
|
3573
|
-
return self.append(TGate(), [qubit], [])
|
4265
|
+
return self.append(TGate(), [qubit], [], copy=False)
|
3574
4266
|
|
3575
4267
|
def tdg(self, qubit: QubitSpecifier) -> InstructionSet:
|
3576
4268
|
"""Apply :class:`~qiskit.circuit.library.TdgGate`.
|
@@ -3585,7 +4277,7 @@ class QuantumCircuit:
|
|
3585
4277
|
"""
|
3586
4278
|
from .library.standard_gates.t import TdgGate
|
3587
4279
|
|
3588
|
-
return self.append(TdgGate(), [qubit], [])
|
4280
|
+
return self.append(TdgGate(), [qubit], [], copy=False)
|
3589
4281
|
|
3590
4282
|
def u(
|
3591
4283
|
self,
|
@@ -3609,7 +4301,7 @@ class QuantumCircuit:
|
|
3609
4301
|
"""
|
3610
4302
|
from .library.standard_gates.u import UGate
|
3611
4303
|
|
3612
|
-
return self.append(UGate(theta, phi, lam), [qubit], [])
|
4304
|
+
return self.append(UGate(theta, phi, lam), [qubit], [], copy=False)
|
3613
4305
|
|
3614
4306
|
def cu(
|
3615
4307
|
self,
|
@@ -3647,6 +4339,7 @@ class QuantumCircuit:
|
|
3647
4339
|
CUGate(theta, phi, lam, gamma, label=label, ctrl_state=ctrl_state),
|
3648
4340
|
[control_qubit, target_qubit],
|
3649
4341
|
[],
|
4342
|
+
copy=False,
|
3650
4343
|
)
|
3651
4344
|
|
3652
4345
|
def x(self, qubit: QubitSpecifier, label: str | None = None) -> InstructionSet:
|
@@ -3663,7 +4356,7 @@ class QuantumCircuit:
|
|
3663
4356
|
"""
|
3664
4357
|
from .library.standard_gates.x import XGate
|
3665
4358
|
|
3666
|
-
return self.append(XGate(label=label), [qubit], [])
|
4359
|
+
return self.append(XGate(label=label), [qubit], [], copy=False)
|
3667
4360
|
|
3668
4361
|
def cx(
|
3669
4362
|
self,
|
@@ -3691,7 +4384,10 @@ class QuantumCircuit:
|
|
3691
4384
|
from .library.standard_gates.x import CXGate
|
3692
4385
|
|
3693
4386
|
return self.append(
|
3694
|
-
CXGate(label=label, ctrl_state=ctrl_state),
|
4387
|
+
CXGate(label=label, ctrl_state=ctrl_state),
|
4388
|
+
[control_qubit, target_qubit],
|
4389
|
+
[],
|
4390
|
+
copy=False,
|
3695
4391
|
)
|
3696
4392
|
|
3697
4393
|
def dcx(self, qubit1: QubitSpecifier, qubit2: QubitSpecifier) -> InstructionSet:
|
@@ -3708,7 +4404,7 @@ class QuantumCircuit:
|
|
3708
4404
|
"""
|
3709
4405
|
from .library.standard_gates.dcx import DCXGate
|
3710
4406
|
|
3711
|
-
return self.append(DCXGate(), [qubit1, qubit2], [])
|
4407
|
+
return self.append(DCXGate(), [qubit1, qubit2], [], copy=False)
|
3712
4408
|
|
3713
4409
|
def ccx(
|
3714
4410
|
self,
|
@@ -3738,6 +4434,7 @@ class QuantumCircuit:
|
|
3738
4434
|
CCXGate(ctrl_state=ctrl_state),
|
3739
4435
|
[control_qubit1, control_qubit2, target_qubit],
|
3740
4436
|
[],
|
4437
|
+
copy=False,
|
3741
4438
|
)
|
3742
4439
|
|
3743
4440
|
def mcx(
|
@@ -3746,6 +4443,7 @@ class QuantumCircuit:
|
|
3746
4443
|
target_qubit: QubitSpecifier,
|
3747
4444
|
ancilla_qubits: QubitSpecifier | Sequence[QubitSpecifier] | None = None,
|
3748
4445
|
mode: str = "noancilla",
|
4446
|
+
ctrl_state: str | int | None = None,
|
3749
4447
|
) -> InstructionSet:
|
3750
4448
|
"""Apply :class:`~qiskit.circuit.library.MCXGate`.
|
3751
4449
|
|
@@ -3764,6 +4462,9 @@ class QuantumCircuit:
|
|
3764
4462
|
target_qubit: The qubit(s) targeted by the gate.
|
3765
4463
|
ancilla_qubits: The qubits used as the ancillae, if the mode requires them.
|
3766
4464
|
mode: The choice of mode, explained further above.
|
4465
|
+
ctrl_state:
|
4466
|
+
The control state in decimal, or as a bitstring (e.g. '1'). Defaults to controlling
|
4467
|
+
on the '1' state.
|
3767
4468
|
|
3768
4469
|
Returns:
|
3769
4470
|
A handle to the instructions created.
|
@@ -3777,14 +4478,16 @@ class QuantumCircuit:
|
|
3777
4478
|
num_ctrl_qubits = len(control_qubits)
|
3778
4479
|
|
3779
4480
|
available_implementations = {
|
3780
|
-
"noancilla": MCXGrayCode(num_ctrl_qubits),
|
3781
|
-
"recursion": MCXRecursive(num_ctrl_qubits),
|
3782
|
-
"v-chain": MCXVChain(num_ctrl_qubits, False),
|
3783
|
-
"v-chain-dirty": MCXVChain(num_ctrl_qubits, dirty_ancillas=True),
|
4481
|
+
"noancilla": MCXGrayCode(num_ctrl_qubits, ctrl_state=ctrl_state),
|
4482
|
+
"recursion": MCXRecursive(num_ctrl_qubits, ctrl_state=ctrl_state),
|
4483
|
+
"v-chain": MCXVChain(num_ctrl_qubits, False, ctrl_state=ctrl_state),
|
4484
|
+
"v-chain-dirty": MCXVChain(num_ctrl_qubits, dirty_ancillas=True, ctrl_state=ctrl_state),
|
3784
4485
|
# outdated, previous names
|
3785
|
-
"advanced": MCXRecursive(num_ctrl_qubits),
|
3786
|
-
"basic": MCXVChain(num_ctrl_qubits, dirty_ancillas=False),
|
3787
|
-
"basic-dirty-ancilla": MCXVChain(
|
4486
|
+
"advanced": MCXRecursive(num_ctrl_qubits, ctrl_state=ctrl_state),
|
4487
|
+
"basic": MCXVChain(num_ctrl_qubits, dirty_ancillas=False, ctrl_state=ctrl_state),
|
4488
|
+
"basic-dirty-ancilla": MCXVChain(
|
4489
|
+
num_ctrl_qubits, dirty_ancillas=True, ctrl_state=ctrl_state
|
4490
|
+
),
|
3788
4491
|
}
|
3789
4492
|
|
3790
4493
|
# check ancilla input
|
@@ -3831,7 +4534,7 @@ class QuantumCircuit:
|
|
3831
4534
|
"""
|
3832
4535
|
from .library.standard_gates.y import YGate
|
3833
4536
|
|
3834
|
-
return self.append(YGate(), [qubit], [])
|
4537
|
+
return self.append(YGate(), [qubit], [], copy=False)
|
3835
4538
|
|
3836
4539
|
def cy(
|
3837
4540
|
self,
|
@@ -3858,7 +4561,10 @@ class QuantumCircuit:
|
|
3858
4561
|
from .library.standard_gates.y import CYGate
|
3859
4562
|
|
3860
4563
|
return self.append(
|
3861
|
-
CYGate(label=label, ctrl_state=ctrl_state),
|
4564
|
+
CYGate(label=label, ctrl_state=ctrl_state),
|
4565
|
+
[control_qubit, target_qubit],
|
4566
|
+
[],
|
4567
|
+
copy=False,
|
3862
4568
|
)
|
3863
4569
|
|
3864
4570
|
def z(self, qubit: QubitSpecifier) -> InstructionSet:
|
@@ -3874,7 +4580,7 @@ class QuantumCircuit:
|
|
3874
4580
|
"""
|
3875
4581
|
from .library.standard_gates.z import ZGate
|
3876
4582
|
|
3877
|
-
return self.append(ZGate(), [qubit], [])
|
4583
|
+
return self.append(ZGate(), [qubit], [], copy=False)
|
3878
4584
|
|
3879
4585
|
def cz(
|
3880
4586
|
self,
|
@@ -3901,7 +4607,10 @@ class QuantumCircuit:
|
|
3901
4607
|
from .library.standard_gates.z import CZGate
|
3902
4608
|
|
3903
4609
|
return self.append(
|
3904
|
-
CZGate(label=label, ctrl_state=ctrl_state),
|
4610
|
+
CZGate(label=label, ctrl_state=ctrl_state),
|
4611
|
+
[control_qubit, target_qubit],
|
4612
|
+
[],
|
4613
|
+
copy=False,
|
3905
4614
|
)
|
3906
4615
|
|
3907
4616
|
def ccz(
|
@@ -3934,6 +4643,7 @@ class QuantumCircuit:
|
|
3934
4643
|
CCZGate(label=label, ctrl_state=ctrl_state),
|
3935
4644
|
[control_qubit1, control_qubit2, target_qubit],
|
3936
4645
|
[],
|
4646
|
+
copy=False,
|
3937
4647
|
)
|
3938
4648
|
|
3939
4649
|
def pauli(
|
@@ -3952,7 +4662,7 @@ class QuantumCircuit:
|
|
3952
4662
|
"""
|
3953
4663
|
from qiskit.circuit.library.generalized_gates.pauli import PauliGate
|
3954
4664
|
|
3955
|
-
return self.append(PauliGate(pauli_string), qubits, [])
|
4665
|
+
return self.append(PauliGate(pauli_string), qubits, [], copy=False)
|
3956
4666
|
|
3957
4667
|
def prepare_state(
|
3958
4668
|
self,
|
@@ -4063,7 +4773,9 @@ class QuantumCircuit:
|
|
4063
4773
|
num_qubits = len(qubits) if isinstance(state, int) else None
|
4064
4774
|
|
4065
4775
|
return self.append(
|
4066
|
-
StatePreparation(state, num_qubits, label=label, normalize=normalize),
|
4776
|
+
StatePreparation(state, num_qubits, label=label, normalize=normalize),
|
4777
|
+
qubits,
|
4778
|
+
copy=False,
|
4067
4779
|
)
|
4068
4780
|
|
4069
4781
|
def initialize(
|
@@ -4175,7 +4887,7 @@ class QuantumCircuit:
|
|
4175
4887
|
|
4176
4888
|
num_qubits = len(qubits) if isinstance(params, int) else None
|
4177
4889
|
|
4178
|
-
return self.append(Initialize(params, num_qubits, normalize), qubits)
|
4890
|
+
return self.append(Initialize(params, num_qubits, normalize), qubits, copy=False)
|
4179
4891
|
|
4180
4892
|
def unitary(
|
4181
4893
|
self,
|
@@ -4218,7 +4930,7 @@ class QuantumCircuit:
|
|
4218
4930
|
if isinstance(qubits, (int, Qubit)) or len(qubits) > 1:
|
4219
4931
|
qubits = [qubits]
|
4220
4932
|
|
4221
|
-
return self.append(gate, qubits, [])
|
4933
|
+
return self.append(gate, qubits, [], copy=False)
|
4222
4934
|
|
4223
4935
|
def _current_scope(self) -> CircuitScopeInterface:
|
4224
4936
|
if self._control_flow_scopes:
|
@@ -4400,7 +5112,7 @@ class QuantumCircuit:
|
|
4400
5112
|
"When using 'while_loop' with a body, you must pass qubits and clbits."
|
4401
5113
|
)
|
4402
5114
|
|
4403
|
-
return self.append(WhileLoopOp(condition, body, label), qubits, clbits)
|
5115
|
+
return self.append(WhileLoopOp(condition, body, label), qubits, clbits, copy=False)
|
4404
5116
|
|
4405
5117
|
@typing.overload
|
4406
5118
|
def for_loop(
|
@@ -4489,7 +5201,9 @@ class QuantumCircuit:
|
|
4489
5201
|
"When using 'for_loop' with a body, you must pass qubits and clbits."
|
4490
5202
|
)
|
4491
5203
|
|
4492
|
-
return self.append(
|
5204
|
+
return self.append(
|
5205
|
+
ForLoopOp(indexset, loop_parameter, body, label), qubits, clbits, copy=False
|
5206
|
+
)
|
4493
5207
|
|
4494
5208
|
@typing.overload
|
4495
5209
|
def if_test(
|
@@ -4554,11 +5268,11 @@ class QuantumCircuit:
|
|
4554
5268
|
qc.z(2)
|
4555
5269
|
|
4556
5270
|
Args:
|
4557
|
-
condition (Tuple[Union[ClassicalRegister, Clbit], int]): A condition to be evaluated
|
4558
|
-
circuit
|
4559
|
-
specified as either a tuple of a ``ClassicalRegister`` to be
|
4560
|
-
with a given ``int``, or as a tuple of a ``Clbit`` to be
|
4561
|
-
``bool`` or an ``int``.
|
5271
|
+
condition (Tuple[Union[ClassicalRegister, Clbit], int]): A condition to be evaluated in
|
5272
|
+
real time during circuit execution, which, if true, will trigger the evaluation of
|
5273
|
+
``true_body``. Can be specified as either a tuple of a ``ClassicalRegister`` to be
|
5274
|
+
tested for equality with a given ``int``, or as a tuple of a ``Clbit`` to be
|
5275
|
+
compared to either a ``bool`` or an ``int``.
|
4562
5276
|
true_body (Optional[QuantumCircuit]): The circuit body to be run if ``condition`` is
|
4563
5277
|
true.
|
4564
5278
|
qubits (Optional[Sequence[QubitSpecifier]]): The circuit qubits over which the if/else
|
@@ -4599,7 +5313,7 @@ class QuantumCircuit:
|
|
4599
5313
|
elif qubits is None or clbits is None:
|
4600
5314
|
raise CircuitError("When using 'if_test' with a body, you must pass qubits and clbits.")
|
4601
5315
|
|
4602
|
-
return self.append(IfElseOp(condition, true_body, None, label), qubits, clbits)
|
5316
|
+
return self.append(IfElseOp(condition, true_body, None, label), qubits, clbits, copy=False)
|
4603
5317
|
|
4604
5318
|
def if_else(
|
4605
5319
|
self,
|
@@ -4630,7 +5344,7 @@ class QuantumCircuit:
|
|
4630
5344
|
qc.x(0)
|
4631
5345
|
|
4632
5346
|
Args:
|
4633
|
-
condition: A condition to be evaluated at circuit
|
5347
|
+
condition: A condition to be evaluated in real time at circuit execution, which,
|
4634
5348
|
if true, will trigger the evaluation of ``true_body``. Can be
|
4635
5349
|
specified as either a tuple of a ``ClassicalRegister`` to be
|
4636
5350
|
tested for equality with a given ``int``, or as a tuple of a
|
@@ -4654,7 +5368,9 @@ class QuantumCircuit:
|
|
4654
5368
|
else:
|
4655
5369
|
condition = (circuit_scope.resolve_classical_resource(condition[0]), condition[1])
|
4656
5370
|
|
4657
|
-
return self.append(
|
5371
|
+
return self.append(
|
5372
|
+
IfElseOp(condition, true_body, false_body, label), qubits, clbits, copy=False
|
5373
|
+
)
|
4658
5374
|
|
4659
5375
|
@typing.overload
|
4660
5376
|
def switch(
|
@@ -4745,7 +5461,7 @@ class QuantumCircuit:
|
|
4745
5461
|
|
4746
5462
|
if qubits is None or clbits is None:
|
4747
5463
|
raise CircuitError("When using 'switch' with cases, you must pass qubits and clbits.")
|
4748
|
-
return self.append(SwitchCaseOp(target, cases, label=label), qubits, clbits)
|
5464
|
+
return self.append(SwitchCaseOp(target, cases, label=label), qubits, clbits, copy=False)
|
4749
5465
|
|
4750
5466
|
def break_loop(self) -> InstructionSet:
|
4751
5467
|
"""Apply :class:`~qiskit.circuit.BreakLoopOp`.
|
@@ -4771,8 +5487,10 @@ class QuantumCircuit:
|
|
4771
5487
|
if self._control_flow_scopes:
|
4772
5488
|
operation = BreakLoopPlaceholder()
|
4773
5489
|
resources = operation.placeholder_resources()
|
4774
|
-
return self.append(operation, resources.qubits, resources.clbits)
|
4775
|
-
return self.append(
|
5490
|
+
return self.append(operation, resources.qubits, resources.clbits, copy=False)
|
5491
|
+
return self.append(
|
5492
|
+
BreakLoopOp(self.num_qubits, self.num_clbits), self.qubits, self.clbits, copy=False
|
5493
|
+
)
|
4776
5494
|
|
4777
5495
|
def continue_loop(self) -> InstructionSet:
|
4778
5496
|
"""Apply :class:`~qiskit.circuit.ContinueLoopOp`.
|
@@ -4798,9 +5516,9 @@ class QuantumCircuit:
|
|
4798
5516
|
if self._control_flow_scopes:
|
4799
5517
|
operation = ContinueLoopPlaceholder()
|
4800
5518
|
resources = operation.placeholder_resources()
|
4801
|
-
return self.append(operation, resources.qubits, resources.clbits)
|
5519
|
+
return self.append(operation, resources.qubits, resources.clbits, copy=False)
|
4802
5520
|
return self.append(
|
4803
|
-
ContinueLoopOp(self.num_qubits, self.num_clbits), self.qubits, self.clbits
|
5521
|
+
ContinueLoopOp(self.num_qubits, self.num_clbits), self.qubits, self.clbits, copy=False
|
4804
5522
|
)
|
4805
5523
|
|
4806
5524
|
def add_calibration(
|
@@ -4996,6 +5714,24 @@ class _OuterCircuitScopeInterface(CircuitScopeInterface):
|
|
4996
5714
|
raise CircuitError(f"Classical bit index {specifier} is out-of-range.") from None
|
4997
5715
|
raise CircuitError(f"Unknown classical resource specifier: '{specifier}'.")
|
4998
5716
|
|
5717
|
+
def add_uninitialized_var(self, var):
|
5718
|
+
var = self.circuit._prepare_new_var(var, None)
|
5719
|
+
self.circuit._vars_local[var.name] = var
|
5720
|
+
|
5721
|
+
def remove_var(self, var):
|
5722
|
+
self.circuit._vars_local.pop(var.name)
|
5723
|
+
|
5724
|
+
def get_var(self, name):
|
5725
|
+
if (out := self.circuit._vars_local.get(name)) is not None:
|
5726
|
+
return out
|
5727
|
+
if (out := self.circuit._vars_capture.get(name)) is not None:
|
5728
|
+
return out
|
5729
|
+
return self.circuit._vars_input.get(name)
|
5730
|
+
|
5731
|
+
def use_var(self, var):
|
5732
|
+
if self.get_var(var.name) != var:
|
5733
|
+
raise CircuitError(f"'{var}' is not present in this circuit")
|
5734
|
+
|
4999
5735
|
|
5000
5736
|
def _validate_expr(circuit_scope: CircuitScopeInterface, node: expr.Expr) -> expr.Expr:
|
5001
5737
|
# This takes the `circuit_scope` object as an argument rather than being a circuit method and
|