diff --git a/qiskit/circuit/classical/expr/__init__.py b/qiskit/circuit/classical/expr/__init__.py index c0057ca96f02..00f1c2e06767 100644 --- a/qiskit/circuit/classical/expr/__init__.py +++ b/qiskit/circuit/classical/expr/__init__.py @@ -43,7 +43,7 @@ real-time variable, or a wrapper around a :class:`.Clbit` or :class:`.ClassicalRegister`. .. autoclass:: Var - :members: var, name + :members: var, name, new Similarly, literals used in expressions (such as integers) should be lifted to :class:`Value` nodes with associated types. diff --git a/qiskit/providers/__init__.py b/qiskit/providers/__init__.py index b0ebc942523c..6736d67a214b 100644 --- a/qiskit/providers/__init__.py +++ b/qiskit/providers/__init__.py @@ -452,8 +452,45 @@ def get_translation_stage_plugin(self): efficient output on ``Mybackend`` the transpiler will be able to perform these custom steps without any manual user input. +.. _providers-guide-real-time-variables: + +Real-time variables +^^^^^^^^^^^^^^^^^^^ + +The transpiler will automatically handle real-time typed classical variables (see +:mod:`qiskit.circuit.classical`) and treat the :class:`.Store` instruction as a built-in +"directive", similar to :class:`.Barrier`. No special handling from backends is necessary to permit +this. + +If your backend is *unable* to handle classical variables and storage, we recommend that you comment +on this in your documentation, and insert a check into your :meth:`~.BackendV2.run` method (see +:ref:`providers-guide-backend-run`) to eagerly reject circuits containing them. You can examine +:attr:`.QuantumCircuit.num_vars` for the presence of variables at the top level. If you accept +:ref:`control-flow operations `, you might need to recursively search the +internal :attr:`~.ControlFlowOp.blocks` of each for scope-local variables with +:attr:`.QuantumCircuit.num_declared_vars`. + +For example, a function to check for the presence of any manual storage locations, or manual stores +to memory:: + + from qiskit.circuit import Store, ControlFlowOp, QuantumCircuit + + def has_realtime_logic(circuit: QuantumCircuit) -> bool: + if circuit.num_vars: + return True + for instruction in circuit.data: + if isinstance(instruction.operation, Store): + return True + elif isinstance(instruction.operation, ControlFlowOp): + for block in instruction.operation.blocks: + if has_realtime_logic(block): + return True + return False + +.. _providers-guide-backend-run: + Backend.run Method --------------------- +------------------ Of key importance is the :meth:`~qiskit.providers.BackendV2.run` method, which is used to actually submit circuits to a device or simulator. The run method diff --git a/releasenotes/notes/1.1/classical-store-e64ee1286219a862.yaml b/releasenotes/notes/1.1/classical-store-e64ee1286219a862.yaml index 9de8affebe49..6718cd66f1f6 100644 --- a/releasenotes/notes/1.1/classical-store-e64ee1286219a862.yaml +++ b/releasenotes/notes/1.1/classical-store-e64ee1286219a862.yaml @@ -54,3 +54,16 @@ features_circuits: Variables can be used wherever classical expressions (see :mod:`qiskit.circuit.classical.expr`) are valid. Currently this is the target expressions of control-flow operations, though we plan to expand this to gate parameters in the future, as the type and expression system are expanded. + + See :ref:`circuit-repr-real-time-classical` for more discussion of these variables, and the + associated data model. + + These are supported throughout the transpiler, through QPY serialization (:mod:`qiskit.qpy`), + OpenQASM 3 export (:mod:`qiskit.qasm3`), and have initial support through the circuit visualizers + (see :meth:`.QuantumCircuit.draw`). + + .. note:: + + The new classical variables and storage will take some time to become supported on hardware + and simulator backends. They are not supported in the primitives interfaces + (:mod:`qiskit.primitives`), but will likely inform those interfaces as they evolve. diff --git a/releasenotes/notes/storage-var-a00a33fcf9a71f3f.yaml b/releasenotes/notes/storage-var-a00a33fcf9a71f3f.yaml new file mode 100644 index 000000000000..b3b18be2fc1a --- /dev/null +++ b/releasenotes/notes/storage-var-a00a33fcf9a71f3f.yaml @@ -0,0 +1,122 @@ +--- +features_circuits: + - | + :class:`.QuantumCircuit` has several new methods to work with and inspect manual :class:`.Var` + variables. + + See :ref:`circuit-real-time-methods` for more in-depth discussion on all of these. + + The new methods are: + + * :meth:`~.QuantumCircuit.add_var` + * :meth:`~.QuantumCircuit.add_input` + * :meth:`~.QuantumCircuit.add_capture` + * :meth:`~.QuantumCircuit.add_uninitialized_var` + * :meth:`~.QuantumCircuit.get_var` + * :meth:`~.QuantumCircuit.has_var` + * :meth:`~.QuantumCircuit.iter_vars` + * :meth:`~.QuantumCircuit.iter_declared_vars` + * :meth:`~.QuantumCircuit.iter_captured_vars` + * :meth:`~.QuantumCircuit.iter_input_vars` + * :meth:`~.QuantumCircuit.store` + + In addition, there are several new dynamic attributes on :class:`.QuantumCircuit` surrounding + these variables: + + * :attr:`~.QuantumCircuit.num_vars` + * :attr:`~.QuantumCircuit.num_input_vars` + * :attr:`~.QuantumCircuit.num_captured_vars` + * :attr:`~.QuantumCircuit.num_declared_vars` + - | + :class:`.ControlFlowOp` and its subclasses now have a :meth:`~.ControlFlowOp.iter_captured_vars` + method, which will return an iterator over the unique variables captured in any of its immediate + blocks. + - | + :class:`.DAGCircuit` has several new methods to work with and inspect manual :class:`.Var` + variables. These are largely equivalent to their :class:`.QuantumCircuit` counterparts, except + that the :class:`.DAGCircuit` ones are optimized for programmatic access with already defined + objects, while the :class:`.QuantumCircuit` methods are more focussed on interactive human use. + + The new methods are: + + * :meth:`~.DAGCircuit.add_input_var` + * :meth:`~.DAGCircuit.add_captured_var` + * :meth:`~.DAGCircuit.add_declared_var` + * :meth:`~.DAGCircuit.has_var` + * :meth:`~.DAGCircuit.iter_vars` + * :meth:`~.DAGCircuit.iter_declared_vars` + * :meth:`~.DAGCircuit.iter_captured_vars` + * :meth:`~.DAGCircuit.iter_input_vars` + + There are also new public attributes: + + * :attr:`~.DAGCircuit.num_vars` + * :attr:`~.DAGCircuit.num_input_vars` + * :attr:`~.DAGCircuit.num_captured_vars` + * :attr:`~.DAGCircuit.num_declared_vars` + - | + :attr:`.DAGCircuit.wires` will now also contain any :class:`.Var` manual variables in the + circuit as well, as these are also classical data flow. + - | + A new method, :meth:`.Var.new`, is added to manually construct a real-time classical variable + that owns its memory. + - | + :meth:`.QuantumCircuit.compose` has two need keyword arguments, ``var_remap`` and ``inline_captures`` + to better support real-time classical variables. + + ``var_remap`` can be used to rewrite :class:`.Var` nodes in the circuit argument as its + instructions are inlined onto the base circuit. This can be used to avoid naming conflicts. + + ``inline_captures`` can be set to ``True`` (defaults to ``False``) to link all :class:`.Var` + nodes tracked as "captures" in the argument circuit with the same :class:`.Var` nodes in the + base circuit, without attempting to redeclare the variables. This can be used, in combination + with :meth:`.QuantumCircuit.copy_empty_like`'s ``vars_mode="captures"`` handling, to build up + a circuit layer by layer, containing variables. + - | + :meth:`.DAGCircuit.compose` has a new keyword argument, ``inline_captures``, which can be set to + ``True`` to inline "captured" :class:`.Var` nodes on the argument circuit onto the base circuit + without redeclaring them. In conjunction with the ``vars_mode="captures"`` option to several + :class:`.DAGCircuit` methods, this can be used to combine DAGs that operate on the same variables. + - | + :meth:`.QuantumCircuit.copy_empty_like` and :meth:`.DAGCircuit.copy_empty_like` have a new + keyword argument, ``vars_mode`` which controls how any memory-owning :class:`.Var` nodes are + tracked in the output. By default (``"alike"``), the variables are declared in the same + input/captured/local mode as the source. This can be set to ``"captures"`` to convert all + variables to captures (useful with :meth:`~.QuantumCircuit.compose`) or ``"drop"`` to remove + them. + - | + A new ``vars_mode`` keyword argument has been added to the :class:`.DAGCircuit` methods: + + * :meth:`~.DAGCircuit.separable_circuits` + * :meth:`~.DAGCircuit.layers` + * :meth:`~.DAGCircuit.serial_layers` + + which has the same meaning as it does for :meth:`~.DAGCircuit.copy_empty_like`. +features_qasm: + - | + The OpenQASM 3 exporter supports manual-storage :class:`.Var` nodes on circuits. +features_qpy: + - | + QPY (:mod:`qiskit.qpy`) format version 12 has been added, which includes support for memory-owning + :class:`.Var` variables. See :ref:`qpy_version_12` for more detail on the format changes. +features_visualization: + - | + The text and `Matplotlib `__ circuit drawers (:meth:`.QuantumCircuit.draw`) + have minimal support for displaying expressions involving manual real-time variables. The + :class:`.Store` operation and the variable initializations are not yet supported; for large-scale + dynamic circuits, we recommend using the OpenQASM 3 export capabilities (:func:`.qasm3.dumps`) to + get a textual representation of a circuit. +upgrade_qpy: + - | + The value of :attr:`qiskit.qpy.QPY_VERSION` is now 12. :attr:`.QPY_COMPATIBILITY_VERSION` is + unchanged at 10. +upgrade_providers: + - | + Implementations of :class:`.BackendV2` (and :class:`.BackendV1`) may desire to update their + :meth:`~.BackendV2.run` methods to eagerly reject inputs containing typed + classical variables (see :mod:`qiskit.circuit.classical`) and the :class:`.Store` instruction, + if they do not have support for them. The new :class:`.Store` instruction is treated by the + transpiler as an always-available "directive" (like :class:`.Barrier`); if your backends do not + support this won't be caught by the :mod:`~qiskit.transpiler`. + + See :ref:`providers-guide-real-time-variables` for more information.