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.
Files changed (247) hide show
  1. qiskit/VERSION.txt +1 -1
  2. qiskit/__init__.py +27 -16
  3. qiskit/_accelerate.pyd +0 -0
  4. qiskit/_numpy_compat.py +73 -0
  5. qiskit/assembler/disassemble.py +5 -6
  6. qiskit/circuit/__init__.py +1131 -169
  7. qiskit/circuit/_classical_resource_map.py +7 -6
  8. qiskit/circuit/_utils.py +18 -8
  9. qiskit/circuit/annotated_operation.py +21 -0
  10. qiskit/circuit/barrier.py +10 -13
  11. qiskit/circuit/bit.py +0 -1
  12. qiskit/circuit/classical/__init__.py +2 -2
  13. qiskit/circuit/classical/expr/__init__.py +39 -5
  14. qiskit/circuit/classical/expr/constructors.py +84 -1
  15. qiskit/circuit/classical/expr/expr.py +83 -13
  16. qiskit/circuit/classical/expr/visitors.py +83 -0
  17. qiskit/circuit/commutation_checker.py +86 -51
  18. qiskit/circuit/controlflow/_builder_utils.py +9 -1
  19. qiskit/circuit/controlflow/break_loop.py +8 -22
  20. qiskit/circuit/controlflow/builder.py +116 -1
  21. qiskit/circuit/controlflow/continue_loop.py +8 -22
  22. qiskit/circuit/controlflow/control_flow.py +47 -8
  23. qiskit/circuit/controlflow/for_loop.py +8 -23
  24. qiskit/circuit/controlflow/if_else.py +13 -27
  25. qiskit/circuit/controlflow/switch_case.py +14 -21
  26. qiskit/circuit/controlflow/while_loop.py +9 -23
  27. qiskit/circuit/controlledgate.py +2 -2
  28. qiskit/circuit/delay.py +7 -5
  29. qiskit/circuit/gate.py +20 -7
  30. qiskit/circuit/instruction.py +31 -30
  31. qiskit/circuit/instructionset.py +9 -22
  32. qiskit/circuit/library/__init__.py +8 -2
  33. qiskit/circuit/library/arithmetic/integer_comparator.py +2 -2
  34. qiskit/circuit/library/arithmetic/quadratic_form.py +3 -2
  35. qiskit/circuit/library/blueprintcircuit.py +29 -7
  36. qiskit/circuit/library/data_preparation/state_preparation.py +6 -5
  37. qiskit/circuit/library/generalized_gates/diagonal.py +5 -4
  38. qiskit/circuit/library/generalized_gates/isometry.py +51 -254
  39. qiskit/circuit/library/generalized_gates/pauli.py +2 -2
  40. qiskit/circuit/library/generalized_gates/permutation.py +4 -1
  41. qiskit/circuit/library/generalized_gates/rv.py +15 -11
  42. qiskit/circuit/library/generalized_gates/uc.py +2 -98
  43. qiskit/circuit/library/generalized_gates/unitary.py +9 -4
  44. qiskit/circuit/library/hamiltonian_gate.py +11 -5
  45. qiskit/circuit/library/n_local/efficient_su2.py +5 -5
  46. qiskit/circuit/library/n_local/n_local.py +100 -49
  47. qiskit/circuit/library/n_local/two_local.py +3 -59
  48. qiskit/circuit/library/overlap.py +3 -3
  49. qiskit/circuit/library/phase_oracle.py +1 -1
  50. qiskit/circuit/library/quantum_volume.py +39 -38
  51. qiskit/circuit/library/standard_gates/equivalence_library.py +50 -0
  52. qiskit/circuit/library/standard_gates/global_phase.py +4 -2
  53. qiskit/circuit/library/standard_gates/i.py +1 -2
  54. qiskit/circuit/library/standard_gates/iswap.py +1 -2
  55. qiskit/circuit/library/standard_gates/multi_control_rotation_gates.py +11 -5
  56. qiskit/circuit/library/standard_gates/p.py +31 -15
  57. qiskit/circuit/library/standard_gates/r.py +4 -3
  58. qiskit/circuit/library/standard_gates/rx.py +7 -4
  59. qiskit/circuit/library/standard_gates/rxx.py +4 -3
  60. qiskit/circuit/library/standard_gates/ry.py +7 -4
  61. qiskit/circuit/library/standard_gates/ryy.py +4 -3
  62. qiskit/circuit/library/standard_gates/rz.py +7 -4
  63. qiskit/circuit/library/standard_gates/rzx.py +4 -3
  64. qiskit/circuit/library/standard_gates/rzz.py +4 -3
  65. qiskit/circuit/library/standard_gates/s.py +4 -8
  66. qiskit/circuit/library/standard_gates/t.py +2 -4
  67. qiskit/circuit/library/standard_gates/u.py +16 -11
  68. qiskit/circuit/library/standard_gates/u1.py +6 -2
  69. qiskit/circuit/library/standard_gates/u2.py +4 -2
  70. qiskit/circuit/library/standard_gates/u3.py +9 -5
  71. qiskit/circuit/library/standard_gates/x.py +22 -11
  72. qiskit/circuit/library/standard_gates/xx_minus_yy.py +4 -3
  73. qiskit/circuit/library/standard_gates/xx_plus_yy.py +7 -5
  74. qiskit/circuit/library/standard_gates/z.py +1 -2
  75. qiskit/circuit/measure.py +4 -1
  76. qiskit/circuit/operation.py +13 -8
  77. qiskit/circuit/parameter.py +11 -6
  78. qiskit/circuit/quantumcircuit.py +864 -128
  79. qiskit/circuit/quantumcircuitdata.py +2 -2
  80. qiskit/circuit/reset.py +5 -2
  81. qiskit/circuit/store.py +95 -0
  82. qiskit/compiler/assembler.py +22 -22
  83. qiskit/compiler/transpiler.py +63 -112
  84. qiskit/converters/circuit_to_dag.py +7 -0
  85. qiskit/converters/circuit_to_dagdependency_v2.py +47 -0
  86. qiskit/converters/circuit_to_gate.py +2 -0
  87. qiskit/converters/circuit_to_instruction.py +22 -0
  88. qiskit/converters/dag_to_circuit.py +4 -0
  89. qiskit/converters/dag_to_dagdependency_v2.py +44 -0
  90. qiskit/dagcircuit/collect_blocks.py +15 -10
  91. qiskit/dagcircuit/dagcircuit.py +434 -124
  92. qiskit/dagcircuit/dagdependency.py +19 -12
  93. qiskit/dagcircuit/dagdependency_v2.py +641 -0
  94. qiskit/dagcircuit/dagdepnode.py +19 -16
  95. qiskit/dagcircuit/dagnode.py +14 -4
  96. qiskit/primitives/__init__.py +12 -8
  97. qiskit/primitives/backend_estimator.py +3 -5
  98. qiskit/primitives/backend_estimator_v2.py +410 -0
  99. qiskit/primitives/backend_sampler_v2.py +287 -0
  100. qiskit/primitives/base/base_estimator.py +4 -9
  101. qiskit/primitives/base/base_sampler.py +2 -2
  102. qiskit/primitives/containers/__init__.py +5 -4
  103. qiskit/primitives/containers/bit_array.py +292 -2
  104. qiskit/primitives/containers/data_bin.py +123 -50
  105. qiskit/primitives/containers/estimator_pub.py +10 -3
  106. qiskit/primitives/containers/observables_array.py +2 -2
  107. qiskit/primitives/containers/pub_result.py +1 -1
  108. qiskit/primitives/containers/sampler_pub.py +19 -3
  109. qiskit/primitives/containers/sampler_pub_result.py +74 -0
  110. qiskit/primitives/containers/shape.py +1 -1
  111. qiskit/primitives/statevector_estimator.py +4 -4
  112. qiskit/primitives/statevector_sampler.py +7 -12
  113. qiskit/providers/__init__.py +17 -18
  114. qiskit/providers/backend.py +2 -2
  115. qiskit/providers/backend_compat.py +8 -10
  116. qiskit/providers/basic_provider/basic_provider_tools.py +67 -31
  117. qiskit/providers/basic_provider/basic_simulator.py +81 -21
  118. qiskit/providers/fake_provider/fake_1q.py +1 -1
  119. qiskit/providers/fake_provider/fake_backend.py +3 -408
  120. qiskit/providers/fake_provider/generic_backend_v2.py +26 -14
  121. qiskit/providers/provider.py +16 -0
  122. qiskit/pulse/builder.py +4 -1
  123. qiskit/pulse/parameter_manager.py +60 -4
  124. qiskit/pulse/schedule.py +29 -13
  125. qiskit/pulse/utils.py +61 -20
  126. qiskit/qasm2/__init__.py +1 -5
  127. qiskit/qasm2/parse.py +1 -4
  128. qiskit/qasm3/__init__.py +42 -5
  129. qiskit/qasm3/ast.py +19 -0
  130. qiskit/qasm3/exporter.py +178 -106
  131. qiskit/qasm3/printer.py +27 -5
  132. qiskit/qpy/__init__.py +247 -13
  133. qiskit/qpy/binary_io/circuits.py +216 -47
  134. qiskit/qpy/binary_io/schedules.py +42 -36
  135. qiskit/qpy/binary_io/value.py +201 -22
  136. qiskit/qpy/common.py +1 -1
  137. qiskit/qpy/exceptions.py +20 -0
  138. qiskit/qpy/formats.py +29 -0
  139. qiskit/qpy/type_keys.py +21 -0
  140. qiskit/quantum_info/analysis/distance.py +3 -3
  141. qiskit/quantum_info/analysis/make_observable.py +2 -1
  142. qiskit/quantum_info/analysis/z2_symmetries.py +2 -1
  143. qiskit/quantum_info/operators/channel/chi.py +9 -8
  144. qiskit/quantum_info/operators/channel/choi.py +10 -9
  145. qiskit/quantum_info/operators/channel/kraus.py +2 -1
  146. qiskit/quantum_info/operators/channel/ptm.py +10 -9
  147. qiskit/quantum_info/operators/channel/quantum_channel.py +2 -1
  148. qiskit/quantum_info/operators/channel/stinespring.py +2 -1
  149. qiskit/quantum_info/operators/channel/superop.py +12 -11
  150. qiskit/quantum_info/operators/channel/transformations.py +12 -11
  151. qiskit/quantum_info/operators/dihedral/dihedral.py +5 -4
  152. qiskit/quantum_info/operators/operator.py +43 -30
  153. qiskit/quantum_info/operators/scalar_op.py +10 -9
  154. qiskit/quantum_info/operators/symplectic/base_pauli.py +70 -59
  155. qiskit/quantum_info/operators/symplectic/clifford.py +36 -9
  156. qiskit/quantum_info/operators/symplectic/pauli.py +48 -4
  157. qiskit/quantum_info/operators/symplectic/pauli_list.py +36 -14
  158. qiskit/quantum_info/operators/symplectic/random.py +3 -2
  159. qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py +54 -33
  160. qiskit/quantum_info/states/densitymatrix.py +13 -13
  161. qiskit/quantum_info/states/stabilizerstate.py +3 -3
  162. qiskit/quantum_info/states/statevector.py +14 -13
  163. qiskit/quantum_info/states/utils.py +5 -3
  164. qiskit/result/mitigation/correlated_readout_mitigator.py +3 -2
  165. qiskit/result/mitigation/local_readout_mitigator.py +2 -1
  166. qiskit/result/mitigation/utils.py +3 -2
  167. qiskit/synthesis/__init__.py +2 -0
  168. qiskit/synthesis/discrete_basis/commutator_decompose.py +2 -2
  169. qiskit/synthesis/evolution/lie_trotter.py +7 -14
  170. qiskit/synthesis/evolution/qdrift.py +3 -4
  171. qiskit/synthesis/linear/cnot_synth.py +1 -3
  172. qiskit/synthesis/linear/linear_circuits_utils.py +1 -1
  173. qiskit/synthesis/linear_phase/cz_depth_lnn.py +4 -18
  174. qiskit/synthesis/permutation/__init__.py +1 -0
  175. qiskit/synthesis/permutation/permutation_reverse_lnn.py +90 -0
  176. qiskit/synthesis/qft/qft_decompose_lnn.py +2 -6
  177. qiskit/synthesis/two_qubit/two_qubit_decompose.py +165 -954
  178. qiskit/synthesis/two_qubit/xx_decompose/circuits.py +13 -12
  179. qiskit/synthesis/two_qubit/xx_decompose/decomposer.py +7 -1
  180. qiskit/synthesis/unitary/aqc/__init__.py +1 -1
  181. qiskit/synthesis/unitary/aqc/cnot_structures.py +2 -1
  182. qiskit/synthesis/unitary/aqc/fast_gradient/fast_gradient.py +2 -1
  183. qiskit/synthesis/unitary/qsd.py +3 -2
  184. qiskit/transpiler/__init__.py +7 -3
  185. qiskit/transpiler/layout.py +140 -61
  186. qiskit/transpiler/passes/__init__.py +6 -0
  187. qiskit/transpiler/passes/basis/basis_translator.py +7 -2
  188. qiskit/transpiler/passes/basis/unroll_3q_or_more.py +1 -1
  189. qiskit/transpiler/passes/basis/unroll_custom_definitions.py +1 -1
  190. qiskit/transpiler/passes/calibration/rzx_builder.py +2 -1
  191. qiskit/transpiler/passes/layout/apply_layout.py +8 -3
  192. qiskit/transpiler/passes/layout/sabre_layout.py +15 -3
  193. qiskit/transpiler/passes/layout/set_layout.py +1 -1
  194. qiskit/transpiler/passes/optimization/__init__.py +2 -0
  195. qiskit/transpiler/passes/optimization/commutation_analysis.py +2 -2
  196. qiskit/transpiler/passes/optimization/commutative_cancellation.py +1 -1
  197. qiskit/transpiler/passes/optimization/consolidate_blocks.py +1 -1
  198. qiskit/transpiler/passes/optimization/cx_cancellation.py +10 -0
  199. qiskit/transpiler/passes/optimization/elide_permutations.py +114 -0
  200. qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +9 -3
  201. qiskit/transpiler/passes/optimization/optimize_annotated.py +248 -12
  202. qiskit/transpiler/passes/optimization/remove_final_reset.py +37 -0
  203. qiskit/transpiler/passes/optimization/template_matching/forward_match.py +1 -3
  204. qiskit/transpiler/passes/routing/__init__.py +1 -0
  205. qiskit/transpiler/passes/routing/basic_swap.py +13 -2
  206. qiskit/transpiler/passes/routing/lookahead_swap.py +7 -1
  207. qiskit/transpiler/passes/routing/sabre_swap.py +10 -6
  208. qiskit/transpiler/passes/routing/star_prerouting.py +417 -0
  209. qiskit/transpiler/passes/routing/stochastic_swap.py +24 -8
  210. qiskit/transpiler/passes/scheduling/__init__.py +1 -1
  211. qiskit/transpiler/passes/scheduling/alap.py +1 -2
  212. qiskit/transpiler/passes/scheduling/alignments/align_measures.py +1 -2
  213. qiskit/transpiler/passes/scheduling/alignments/check_durations.py +9 -6
  214. qiskit/transpiler/passes/scheduling/alignments/pulse_gate_validation.py +8 -0
  215. qiskit/transpiler/passes/scheduling/alignments/reschedule.py +13 -4
  216. qiskit/transpiler/passes/scheduling/asap.py +1 -2
  217. qiskit/transpiler/passes/scheduling/base_scheduler.py +21 -2
  218. qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +26 -4
  219. qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +24 -2
  220. qiskit/transpiler/passes/scheduling/time_unit_conversion.py +28 -4
  221. qiskit/transpiler/passes/synthesis/aqc_plugin.py +2 -2
  222. qiskit/transpiler/passes/synthesis/high_level_synthesis.py +120 -13
  223. qiskit/transpiler/passes/synthesis/unitary_synthesis.py +162 -55
  224. qiskit/transpiler/passes/utils/gates_basis.py +3 -3
  225. qiskit/transpiler/passmanager.py +44 -1
  226. qiskit/transpiler/preset_passmanagers/__init__.py +3 -3
  227. qiskit/transpiler/preset_passmanagers/builtin_plugins.py +34 -16
  228. qiskit/transpiler/preset_passmanagers/common.py +4 -6
  229. qiskit/transpiler/preset_passmanagers/plugin.py +9 -1
  230. qiskit/utils/optionals.py +6 -2
  231. qiskit/visualization/array.py +1 -1
  232. qiskit/visualization/bloch.py +2 -3
  233. qiskit/visualization/circuit/matplotlib.py +44 -14
  234. qiskit/visualization/circuit/text.py +38 -18
  235. qiskit/visualization/counts_visualization.py +3 -6
  236. qiskit/visualization/dag_visualization.py +6 -7
  237. qiskit/visualization/pulse_v2/interface.py +8 -3
  238. qiskit/visualization/state_visualization.py +3 -2
  239. qiskit/visualization/timeline/interface.py +18 -8
  240. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/METADATA +12 -8
  241. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/RECORD +245 -235
  242. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/WHEEL +1 -1
  243. qiskit/_qasm2.pyd +0 -0
  244. qiskit/_qasm3.pyd +0 -0
  245. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/LICENSE.txt +0 -0
  246. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/entry_points.txt +0 -0
  247. {qiskit-1.0.2.dist-info → qiskit-1.1.0rc1.dist-info}/top_level.txt +0 -0
@@ -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.quantum_circuit import CircuitData
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, copy.deepcopy(self.__dict__[k], memo))
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=copy.deepcopy(self._data.qubits, memo),
509
- clbits=copy.deepcopy(self._data.clbits, memo),
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: copy.deepcopy(op, memo))
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 = QuantumCircuit(
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(self, power: float, matrix_power: bool = False) -> "QuantumCircuit":
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`` is ``False``, this implementation
746
- defaults to calling ``repeat``. Otherwise, if the circuit is unitary, the matrix is
747
- computed to calculate the matrix power.
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): If True, the circuit is converted to a matrix and then the
752
- matrix power is computed. If False, and ``power`` is a positive integer,
753
- the implementation defaults to ``repeat``.
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 it is not unitary.
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 power >= 0 and isinstance(power, (int, np.integer)) and not matrix_power:
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
- "controlled. Note that no qiskit.circuit.Instruction objects may "
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 not other.data:
990
- # Nothing left to do. Plus, accessing 'data' here is necessary
991
- # to trigger any lazy building since we now access '_data'
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
- variable_mapper = _classical_resource_map.VariableMapper(
996
- dest.cregs, edge_map, dest.add_register
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
- def map_vars(op):
1000
- n_op = op.copy()
1001
- if (condition := getattr(n_op, "condition", None)) is not None:
1002
- n_op.condition = variable_mapper.map_condition(condition)
1003
- if isinstance(n_op, SwitchCaseOp):
1004
- n_op.target = variable_mapper.map_target(n_op.target)
1005
- return n_op
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
- mapped_instrs: CircuitData = other._data.copy()
1008
- mapped_instrs.replace_bits(qubits=mapped_qubits, clbits=mapped_clbits)
1009
- mapped_instrs.map_ops(map_vars)
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
- circuit_scope = dest._current_scope()
1017
- circuit_scope.extend(mapped_instrs)
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
- circuit_scope.extend(append_existing)
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, Parameter)
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 = copy.deepcopy(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) -> "QuantumCircuit":
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(self, name: str | None = None) -> "QuantumCircuit":
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
- * name, calibrations and other metadata
2108
- * global phase
2109
- * all the qubits and clbits, including the registers
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 (str): Name for the copied circuit. If None, then the name stays the same.
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 = copy.copy(self)
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 = copy.deepcopy(self._calibrations)
2138
- cpy._metadata = copy.deepcopy(self._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(CircuitInstruction(Barrier(len(qubits), label=label), qubits, ()))
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), [control_qubit, target_qubit], []
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), [control_qubit, target_qubit], []
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), control_qubits[:] + [target_qubit], []
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(RCCXGate(), [control_qubit1, control_qubit2, target_qubit], [])
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(), [control_qubit1, control_qubit2, control_qubit3, target_qubit], []
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), [control_qubit, target_qubit], []
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), [control_qubit, target_qubit], []
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), [control_qubit, target_qubit], []
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), [control_qubit, target_qubit], []
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(num_ctrl_qubits, dirty_ancillas=True),
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), [control_qubit, target_qubit], []
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), [control_qubit, target_qubit], []
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), qubits
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(ForLoopOp(indexset, loop_parameter, body, label), qubits, clbits)
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 at
4558
- circuit runtime which, if true, will trigger the evaluation of ``true_body``. Can be
4559
- specified as either a tuple of a ``ClassicalRegister`` to be tested for equality
4560
- with a given ``int``, or as a tuple of a ``Clbit`` to be compared to either a
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 runtime which,
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(IfElseOp(condition, true_body, false_body, label), qubits, clbits)
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(BreakLoopOp(self.num_qubits, self.num_clbits), self.qubits, self.clbits)
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