Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add release notes for manual Var and Store #12421

Merged
merged 6 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion qiskit/circuit/classical/expr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
39 changes: 38 additions & 1 deletion qiskit/providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 <circuit-control-flow-repr>`, 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
Expand Down
13 changes: 13 additions & 0 deletions releasenotes/notes/1.1/classical-store-e64ee1286219a862.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
122 changes: 122 additions & 0 deletions releasenotes/notes/storage-var-a00a33fcf9a71f3f.yaml
Original file line number Diff line number Diff line change
@@ -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 <https://matplotlib.org>`__ 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.
Loading