Write module-level `qiskit.circuit` documentation (#11904)

* Write module-level `qiskit.circuit` documentation

I was pretty surprised to see that we had very little written for our
principal module, and the first entry in our API docs.

This is a totally new set of documentation for the `qiskit.circuit`
module, including discussion of what circuits are, what they represent
in Qiskit, how all the different data elements fit together, and where
to go for more information on things.

This commit is intended to be followed by a later one that does a
similar rewrite for the whole `QuantumCircuit` class, including
structuring its references to all its attributes and methods, and adding
a holistic view of how the methods fit together.  This is why there are
some (hidden to Sphinx) `TODO` comments scattered throughout this
documentation.

* Apply suggestions from Sebastian's review

Co-authored-by: Sebastian Brandhofer <148463728+sbrandhsn@users.noreply.github.com>

* Move larger classes to separate pages

This moves the larger class definitions (basically those that actually
have any public methods) to separate pages, at the request of the docs
team.  Much of this is intended to be temporary, and for most of these
classes to be moved back inline once the IBM docs platform can better
support that.

* Fix docs build with autosummary

* Switch "near time"/"runtime" terminology to "real time"

This avoids overloading "runtime" with too many meanings, and appears to
be more consistent with other messaging coming out of IBM Quantum.

* Remove misleading 'bitwise' terminology

---------

Co-authored-by: Sebastian Brandhofer <148463728+sbrandhsn@users.noreply.github.com>
This commit is contained in:
Jake Lishman 2024-04-05 13:27:47 +01:00 committed by GitHub
parent 2cbbe2bee2
commit 99c0497052
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 1344 additions and 399 deletions

File diff suppressed because it is too large Load Diff

View File

@ -110,8 +110,8 @@ class VariableMapper(expr.ExprVisitor[expr.Expr]):
return (mapped_theirs, mapped_value)
def map_target(self, target, /):
"""Map the runtime variables in a ``target`` of a :class:`.SwitchCaseOp` to the new circuit,
as defined in the ``circuit`` argument of the initialiser of this class."""
"""Map the real-time variables in a ``target`` of a :class:`.SwitchCaseOp` to the new
circuit, as defined in the ``circuit`` argument of the initialiser of this class."""
if isinstance(target, Clbit):
return self.bit_map[target]
if isinstance(target, ClassicalRegister):

View File

@ -97,7 +97,10 @@ class AnnotatedOperation(Operation):
inverted and then controlled by 2 qubits.
"""
self.base_op = base_op
"""The base operation that the modifiers in this annotated operation applies to."""
self.modifiers = modifiers if isinstance(modifiers, List) else [modifiers]
"""Ordered sequence of the modifiers to apply to :attr:`base_op`. The modifiers are applied
in order from lowest index to highest index."""
@property
def name(self):

View File

@ -16,29 +16,26 @@ Can be applied to a :class:`~qiskit.circuit.QuantumCircuit`
with the :meth:`~qiskit.circuit.QuantumCircuit.barrier` method.
"""
from __future__ import annotations
from qiskit.exceptions import QiskitError
from .instruction import Instruction
class Barrier(Instruction):
"""Barrier instruction.
"""A directive for circuit compilation to separate pieces of a circuit so that any optimizations
or re-writes are constrained to only act between barriers.
A barrier is a visual indicator of the grouping of a circuit section.
It also acts as a directive for circuit compilation to separate pieces
of a circuit so that any optimizations or re-writes are constrained
to only act between barriers."""
This will also appear in visualizations as a visual marker.
"""
_directive = True
def __init__(self, num_qubits, label=None):
"""Create new barrier instruction.
def __init__(self, num_qubits: int, label: str | None = None):
"""
Args:
num_qubits (int): the number of qubits for the barrier type [Default: 0].
label (str): the barrier label
Raises:
TypeError: if barrier label is invalid.
num_qubits: the number of qubits for the barrier.
label: the optional label of this barrier.
"""
self._label = label
super().__init__("barrier", num_qubits, 0, [], label=label)

View File

@ -24,7 +24,6 @@ class Bit:
.. note::
This class should not be instantiated directly. This is just a superclass
for :class:`~.Clbit` and :class:`~.circuit.Qubit`.
"""
__slots__ = {"_register", "_index", "_hash", "_repr"}

View File

@ -15,8 +15,8 @@
Classical expressions (:mod:`qiskit.circuit.classical`)
=======================================================
This module contains an exploratory representation of runtime operations on classical values during
circuit execution.
This module contains an exploratory representation of real-time operations on classical values
during circuit execution.
Currently, only simple expressions on bits and registers that result in a Boolean value are
supported, and these are only valid for use in the conditions of :meth:`.QuantumCircuit.if_test`

View File

@ -39,8 +39,8 @@ The expression system is based on tree representation. All nodes in the tree ar
These objects are mutable and should not be reused in a different location without a copy.
The base for dynamic variables is the :class:`Var`, which can be either an arbitrarily typed runtime
variable, or a wrapper around a :class:`.Clbit` or :class:`.ClassicalRegister`.
The base for dynamic variables is the :class:`Var`, which can be either an arbitrarily typed
real-time variable, or a wrapper around a :class:`.Clbit` or :class:`.ClassicalRegister`.
.. autoclass:: Var
:members: var, name

View File

@ -19,31 +19,17 @@ from .builder import InstructionPlaceholder, InstructionResources
class BreakLoopOp(Instruction):
"""A circuit operation which, when encountered, jumps to the end of
the nearest enclosing loop.
.. note:
Can be inserted only within the body of a loop op, and must span
the full width of that block.
**Circuit symbol:**
.. parsed-literal::
q_0: 0
q_1: 1
break_loop
q_2: 2
c_0: 0
"""A circuit operation which, when encountered, jumps to the end of the nearest enclosing loop.
Can only be used inside loops.
"""
def __init__(self, num_qubits: int, num_clbits: int, label: Optional[str] = None):
"""
Args:
num_qubits: the number of qubits this affects.
num_clbits: the number of qubits this affects.
label: an optional string label for the instruction.
"""
super().__init__("break_loop", num_qubits, num_clbits, [], label=label)

View File

@ -133,7 +133,7 @@ class CircuitScopeInterface(abc.ABC):
@abc.abstractmethod
def use_var(self, var: expr.Var):
"""Called for every standalone classical runtime variable being used by some circuit
"""Called for every standalone classical real-time variable being used by some circuit
instruction.
The given variable is guaranteed to be a stand-alone variable; bit-like resource-wrapping

View File

@ -19,31 +19,17 @@ from .builder import InstructionPlaceholder, InstructionResources
class ContinueLoopOp(Instruction):
"""A circuit operation which, when encountered, moves to the next iteration of
the nearest enclosing loop.
.. note::
Can be inserted only within the body of a loop op, and must span the full
width of that block.
**Circuit symbol:**
.. parsed-literal::
q_0: 0
q_1: 1
continue_loop
q_2: 2
c_0: 0
"""A circuit operation which, when encountered, moves to the next iteration of the nearest
enclosing loop. Can only be used inside loops.
"""
def __init__(self, num_qubits: int, num_clbits: int, label: Optional[str] = None):
"""
Args:
num_qubits: the number of qubits this affects.
num_clbits: the number of qubits this affects.
label: an optional string label for the instruction.
"""
super().__init__("continue_loop", num_qubits, num_clbits, [], label=label)

View File

@ -25,7 +25,12 @@ if typing.TYPE_CHECKING:
class ControlFlowOp(Instruction, ABC):
"""Abstract class to encapsulate all control flow operations."""
"""Abstract class to encapsulate all control flow operations.
All subclasses of :class:`ControlFlowOp` have an internal attribute,
:attr:`~ControlFlowOp.blocks`, which exposes the inner subcircuits used in the different blocks
of the control flow.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@ -36,17 +41,34 @@ class ControlFlowOp(Instruction, ABC):
@property
@abstractmethod
def blocks(self) -> tuple[QuantumCircuit, ...]:
"""Tuple of QuantumCircuits which may be executed as part of the
execution of this ControlFlowOp. May be parameterized by a loop
parameter to be resolved at run time.
"""
"""Tuple of :class:`.QuantumCircuit`\\ s which may be executed as part of the
execution of this :class:`ControlFlowOp`."""
@abstractmethod
def replace_blocks(self, blocks: typing.Iterable[QuantumCircuit]) -> ControlFlowOp:
"""Replace blocks and return new instruction.
"""Return a new version of this control-flow operations with the :attr:`blocks` mapped to
the given new ones.
Typically this is used in a workflow such as::
existing_op = ...
def map_block(block: QuantumCircuit) -> QuantumCircuit:
new_block = block.copy_empty_like()
# ... do something to `new_block` ...
return new_block
new_op = existing_op.replace_blocks(
map_block(block) for block in existing_op.blocks
)
It is the caller's responsibility to ensure that the mapped blocks are defined over a
unified set of circuit resources, much like constructing a :class:`ControlFlowOp` using its
default constructor.
Args:
blocks: Tuple of QuantumCircuits to replace in instruction.
blocks: the new subcircuit blocks to use.
Returns:
New ControlFlowOp with replaced blocks.
New :class:`ControlFlowOp` with replaced blocks.
"""

View File

@ -29,28 +29,6 @@ class ForLoopOp(ControlFlowOp):
"""A circuit operation which repeatedly executes a subcircuit
(``body``) parameterized by a parameter ``loop_parameter`` through
the set of integer values provided in ``indexset``.
Parameters:
indexset: A collection of integers to loop over.
loop_parameter: The placeholder parameterizing ``body`` to which
the values from ``indexset`` will be assigned.
body: The loop body to be repeatedly executed.
label: An optional label for identifying the instruction.
**Circuit symbol:**
.. parsed-literal::
q_0: 0
q_1: 1
for_loop
q_2: 2
c_0: 0
"""
def __init__(
@ -60,9 +38,16 @@ class ForLoopOp(ControlFlowOp):
body: QuantumCircuit,
label: Optional[str] = None,
):
"""
Args:
indexset: A collection of integers to loop over.
loop_parameter: The placeholder parameterizing ``body`` to which
the values from ``indexset`` will be assigned.
body: The loop body to be repeatedly executed.
label: An optional label for identifying the instruction.
"""
num_qubits = body.num_qubits
num_clbits = body.num_clbits
super().__init__(
"for_loop", num_qubits, num_clbits, [indexset, loop_parameter, body], label=label
)

View File

@ -44,38 +44,11 @@ class IfElseOp(ControlFlowOp):
provided condition (``condition``) evaluates to true, and
optionally evaluates another program (``false_body``) otherwise.
Parameters:
condition: A condition to be evaluated at circuit runtime which,
if true, will trigger the evaluation of ``true_body``. Can be
specified as either a tuple of a ``ClassicalRegister`` to be
tested for equality with a given ``int``, or as a tuple of a
``Clbit`` to be compared to either a ``bool`` or an ``int``.
true_body: A program to be executed if ``condition`` evaluates
to true.
false_body: A optional program to be executed if ``condition``
evaluates to false.
label: An optional label for identifying the instruction.
If provided, ``false_body`` must be of the same ``num_qubits`` and
``num_clbits`` as ``true_body``.
The classical bits used in ``condition`` must be a subset of those attached
to the circuit on which this ``IfElseOp`` will be appended.
**Circuit symbol:**
.. parsed-literal::
q_0: 0
q_1: 1
if_else
q_2: 2
c_0: 0
"""
def __init__(
@ -85,6 +58,19 @@ class IfElseOp(ControlFlowOp):
false_body: QuantumCircuit | None = None,
label: str | None = None,
):
"""
Args:
condition: A condition to be evaluated in real time during circuit execution which,
if true, will trigger the evaluation of ``true_body``. Can be
specified as either a tuple of a ``ClassicalRegister`` to be
tested for equality with a given ``int``, or as a tuple of a
``Clbit`` to be compared to either a ``bool`` or an ``int``.
true_body: A program to be executed if ``condition`` evaluates
to true.
false_body: A optional program to be executed if ``condition``
evaluates to false.
label: An optional label for identifying the instruction.
"""
# pylint: disable=cyclic-import
from qiskit.circuit import QuantumCircuit

View File

@ -32,39 +32,25 @@ if TYPE_CHECKING:
class _DefaultCaseType:
"""The type of the default-case singleton. This is used instead of just having
``CASE_DEFAULT = object()`` so we can set the pretty-printing properties, which are class-level
only."""
# Note: Sphinx uses the docstring of this singleton class object as the documentation of the
# `CASE_DEFAULT` object.
"""A special object that represents the "default" case of a switch statement. If you use this
as a case target, it must be the last case, and will match anything that wasn't already matched.
When using the builder interface of :meth:`.QuantumCircuit.switch`, this can also be accessed as
the ``DEFAULT`` attribute of the bound case-builder object."""
def __repr__(self):
return "<default case>"
CASE_DEFAULT = _DefaultCaseType()
"""A special object that represents the "default" case of a switch statement. If you use this
as a case target, it must be the last case, and will match anything that wasn't already matched.
When using the builder interface of :meth:`.QuantumCircuit.switch`, this can also be accessed as the
``DEFAULT`` attribute of the bound case-builder object."""
class SwitchCaseOp(ControlFlowOp):
"""A circuit operation that executes one particular circuit block based on matching a given
``target`` against an ordered list of ``values``. The special value :data:`.CASE_DEFAULT` can
be used to represent a default condition.
This is the low-level interface for creating a switch-case statement; in general, the circuit
method :meth:`.QuantumCircuit.switch` should be used as a context manager to access the
builder interface. At the low level, you must ensure that all the circuit blocks contain equal
numbers of qubits and clbits, and that the order the virtual bits of the containing circuit
should be bound is the same for all blocks. This will likely mean that each circuit block is
wider than its natural width, as each block must span the union of all the spaces covered by
*any* of the blocks.
Args:
target: the runtime value to switch on.
cases: an ordered iterable of the corresponding value of the ``target`` and the circuit
block that should be executed if this is matched. There is no fall-through between
blocks, and the order matters.
"""
def __init__(
@ -74,6 +60,13 @@ class SwitchCaseOp(ControlFlowOp):
*,
label: Optional[str] = None,
):
"""
Args:
target: the real-time value to switch on.
cases: an ordered iterable of the corresponding value of the ``target`` and the circuit
block that should be executed if this is matched. There is no fall-through between
blocks, and the order matters.
"""
# pylint: disable=cyclic-import
from qiskit.circuit import QuantumCircuit

View File

@ -30,31 +30,8 @@ class WhileLoopOp(ControlFlowOp):
"""A circuit operation which repeatedly executes a subcircuit (``body``) until
a condition (``condition``) evaluates as False.
Parameters:
condition: A condition to be checked prior to executing ``body``. Can be
specified as either a tuple of a ``ClassicalRegister`` to be tested
for equality with a given ``int``, or as a tuple of a ``Clbit`` to
be compared to either a ``bool`` or an ``int``.
body: The loop body to be repeatedly executed.
label: An optional label for identifying the instruction.
The classical bits used in ``condition`` must be a subset of those attached
to ``body``.
**Circuit symbol:**
.. parsed-literal::
q_0: 0
q_1: 1
while_loop
q_2: 2
c_0: 0
"""
def __init__(
@ -63,6 +40,15 @@ class WhileLoopOp(ControlFlowOp):
body: QuantumCircuit,
label: str | None = None,
):
"""
Args:
condition: A condition to be checked prior to executing ``body``. Can be
specified as either a tuple of a ``ClassicalRegister`` to be tested
for equality with a given ``int``, or as a tuple of a ``Clbit`` to
be compared to either a ``bool`` or an ``int``.
body: The loop body to be repeatedly executed.
label: An optional label for identifying the instruction.
"""
num_qubits = body.num_qubits
num_clbits = body.num_clbits

View File

@ -111,9 +111,9 @@ class ControlledGate(Gate):
@property
def definition(self) -> QuantumCircuit:
"""Return definition in terms of other basic gates. If the gate has
open controls, as determined from `self.ctrl_state`, the returned
open controls, as determined from :attr:`ctrl_state`, the returned
definition is conjugated with X without changing the internal
`_definition`.
``_definition``.
"""
if self._open_ctrl:
closed_gate = self.to_mutable()

View File

@ -24,7 +24,11 @@ class Delay(Instruction):
"""Do nothing and just delay/wait/idle for a specified duration."""
def __init__(self, duration, unit="dt"):
"""Create new delay instruction."""
"""
Args:
duration: the length of time of the duration. Given in units of ``unit``.
unit: the unit of the duration. Must be ``"dt"`` or an SI-prefixed seconds unit.
"""
if unit not in {"s", "ms", "us", "ns", "ps", "dt"}:
raise CircuitError("Unknown unit %s is specified." % unit)

View File

@ -268,12 +268,17 @@ class Instruction(Operation):
return True
def _define(self):
"""Populates self.definition with a decomposition of this gate."""
"""Populate the cached :attr:`_definition` field of this :class:`Instruction`.
Subclasses should implement this method to provide lazy construction of their public
:attr:`definition` attribute. A subclass can use its :attr:`params` at the time of the
call. The method should populate :attr:`_definition` with a :class:`.QuantumCircuit` and
not return a value."""
pass
@property
def params(self):
"""return instruction params."""
"""The parameters of this :class:`Instruction`. Ideally these will be gate angles."""
return self._params
@params.setter
@ -290,7 +295,8 @@ class Instruction(Operation):
return parameter
def is_parameterized(self):
"""Return True .IFF. instruction is parameterized else False"""
"""Return whether the :class:`Instruction` contains :ref:`compile-time parameters
<circuit-compile-time-parameters>`."""
return any(
isinstance(param, ParameterExpression) and param.parameters for param in self.params
)

View File

@ -87,7 +87,11 @@ class InstructionSet:
self._instructions.append((data, pos))
def inverse(self, annotated: bool = False):
"""Invert all instructions."""
"""Invert all instructions.
.. note::
It is preferable to take the inverse *before* appending the gate(s) to the circuit.
"""
for i, instruction in enumerate(self._instructions):
if isinstance(instruction, CircuitInstruction):
self._instructions[i] = instruction.replace(
@ -105,6 +109,10 @@ class InstructionSet:
"""Set a classical equality condition on all the instructions in this set between the
:obj:`.ClassicalRegister` or :obj:`.Clbit` ``classical`` and value ``val``.
.. note::
You should prefer to use the :meth:`.QuantumCircuit.if_test` builder interface, rather
than using this method.
.. note::
This is a setter method, not an additive one. Calling this multiple times will silently
@ -124,27 +132,6 @@ class InstructionSet:
Raises:
CircuitError: if the passed classical resource is invalid, or otherwise not resolvable
to a concrete resource that these instructions are permitted to access.
Example:
.. plot::
:include-source:
from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit
qr = QuantumRegister(2)
cr = ClassicalRegister(2)
qc = QuantumCircuit(qr, cr)
qc.h(range(2))
qc.measure(range(2), range(2))
# apply x gate if the classical register has the value 2 (10 in binary)
qc.x(0).c_if(cr, 2)
# apply y gate if bit 0 is set to 1
qc.y(1).c_if(0, 1)
qc.draw('mpl')
"""
if self._requester is None and not isinstance(classical, (Clbit, ClassicalRegister)):
raise CircuitError(

View File

@ -137,8 +137,11 @@ Directives are operations to the quantum stack that are meant to be interpreted
the transpiler. In general, the transpiler or backend might optionally ignore them if there is no
implementation for them.
..
This summary table deliberately does not generate toctree entries; these directives are "owned"
by ``qiskit.circuit``.
.. autosummary::
:toctree: ../stubs/
Barrier
@ -147,8 +150,11 @@ Standard Operations
Operations are non-reversible changes in the quantum state of the circuit.
..
This summary table deliberately does not generate toctree entries; these directives are "owned"
by ``qiskit.circuit``.
.. autosummary::
:toctree: ../stubs/
Measure
Reset

View File

@ -22,7 +22,10 @@ class Measure(SingletonInstruction):
"""Quantum measurement in the computational basis."""
def __init__(self, label=None, *, duration=None, unit="dt"):
"""Create new measurement instruction."""
"""
Args:
label: optional string label for this instruction.
"""
super().__init__("measure", 1, 1, [], label=label, duration=duration, unit=unit)
_singleton_lookup_key = stdlib_singleton_key()

View File

@ -16,17 +16,22 @@ from abc import ABC, abstractmethod
class Operation(ABC):
"""Quantum Operation Interface Class.
For objects that can be added to a :class:`~qiskit.circuit.QuantumCircuit`.
These objects include :class:`~qiskit.circuit.Gate`, :class:`~qiskit.circuit.Reset`,
:class:`~qiskit.circuit.Barrier`, :class:`~qiskit.circuit.Measure`,
and operators such as :class:`~qiskit.quantum_info.Clifford`.
The main purpose is to add an :class:`~qiskit.circuit.Operation` to a
:class:`~qiskit.circuit.QuantumCircuit` without synthesizing it before the transpilation.
"""Quantum operation interface.
The minimal interface that any object must fulfil in order to be added to a
:class:`.QuantumCircuit`.
Concrete instances of this interface include :class:`~qiskit.circuit.Gate`,
:class:`~qiskit.circuit.Reset`, :class:`~qiskit.circuit.Barrier`,
:class:`~qiskit.circuit.Measure`, and operators such as :class:`~qiskit.quantum_info.Clifford`.
The main purpose is to add allow abstract mathematical objects to be added directly onto
abstract circuits, and for the exact syntheses of these to be determined later, during
compilation.
Example:
Add a Clifford and a Toffoli gate to a QuantumCircuit.
Add a Clifford and a Toffoli gate to a :class:`QuantumCircuit`.
.. plot::
:include-source:

View File

@ -25,10 +25,16 @@ from .parameterexpression import ParameterExpression
class Parameter(ParameterExpression):
"""Parameter Class for variable parameters.
"""A compile-time symbolic parameter.
A parameter is a variable value that is not required to be fixed
at circuit definition.
The value of a :class:`Parameter` must be entirely determined before a circuit begins execution.
Typically this will mean that you should supply values for all :class:`Parameter`\\ s in a
circuit using :meth:`.QuantumCircuit.assign_parameters`, though certain hardware vendors may
allow you to give them a circuit in terms of these parameters, provided you also pass the values
separately.
This is the atom of :class:`.ParameterExpression`, and is itself an expression. The numeric
value of a parameter need not be fixed while the circuit is being defined.
Examples:
@ -62,11 +68,10 @@ class Parameter(ParameterExpression):
def __init__(
self, name: str, *, uuid: UUID | None = None
): # pylint: disable=super-init-not-called
"""Create a new named :class:`Parameter`.
"""
Args:
name: name of the ``Parameter``, used for visual representation. This can
be any unicode string, e.g. "ϕ".
be any Unicode string, e.g. "ϕ".
uuid: For advanced usage only. Override the UUID of this parameter, in order to make it
compare equal to some other parameter object. By default, two parameters with the
same name do not compare equal to help catch shadowing bugs when two circuits

View File

@ -144,7 +144,7 @@ class QuantumCircuit:
circuit. This gets stored as free-form data in a dict in the
:attr:`~qiskit.circuit.QuantumCircuit.metadata` attribute. It will
not be directly used in the circuit.
inputs: any variables to declare as ``input`` runtime variables for this circuit. These
inputs: any variables to declare as ``input`` real-time variables for this circuit. These
should already be existing :class:`.expr.Var` nodes that you build from somewhere else;
if you need to create the inputs as well, use :meth:`QuantumCircuit.add_input`. The
variables given in this argument will be passed directly to :meth:`add_input`. A
@ -1171,14 +1171,14 @@ class QuantumCircuit:
@property
def num_vars(self) -> int:
"""The number of runtime classical variables in the circuit.
"""The number of real-time classical variables in the circuit.
This is the length of the :meth:`iter_vars` iterable."""
return self.num_input_vars + self.num_captured_vars + self.num_declared_vars
@property
def num_input_vars(self) -> int:
"""The number of runtime classical variables in the circuit marked as circuit inputs.
"""The number of real-time classical variables in the circuit marked as circuit inputs.
This is the length of the :meth:`iter_input_vars` iterable. If this is non-zero,
:attr:`num_captured_vars` must be zero."""
@ -1186,7 +1186,7 @@ class QuantumCircuit:
@property
def num_captured_vars(self) -> int:
"""The number of runtime classical variables in the circuit marked as captured from an
"""The number of real-time classical variables in the circuit marked as captured from an
enclosing scope.
This is the length of the :meth:`iter_captured_vars` iterable. If this is non-zero,
@ -1195,14 +1195,14 @@ class QuantumCircuit:
@property
def num_declared_vars(self) -> int:
"""The number of runtime classical variables in the circuit that are declared by this
"""The number of real-time classical variables in the circuit that are declared by this
circuit scope, excluding inputs or captures.
This is the length of the :meth:`iter_declared_vars` iterable."""
return len(self._vars_local)
def iter_vars(self) -> typing.Iterable[expr.Var]:
"""Get an iterable over all runtime classical variables in scope within this circuit.
"""Get an iterable over all real-time classical variables in scope within this circuit.
This method will iterate over all variables in scope. For more fine-grained iterators, see
:meth:`iter_declared_vars`, :meth:`iter_input_vars` and :meth:`iter_captured_vars`."""
@ -1214,7 +1214,7 @@ class QuantumCircuit:
)
def iter_declared_vars(self) -> typing.Iterable[expr.Var]:
"""Get an iterable over all runtime classical variables that are declared with automatic
"""Get an iterable over all real-time classical variables that are declared with automatic
storage duration in this scope. This excludes input variables (see :meth:`iter_input_vars`)
and captured variables (see :meth:`iter_captured_vars`)."""
if self._control_flow_scopes:
@ -1222,15 +1222,15 @@ class QuantumCircuit:
return self._vars_local.values()
def iter_input_vars(self) -> typing.Iterable[expr.Var]:
"""Get an iterable over all runtime classical variables that are declared as inputs to this
circuit scope. This excludes locally declared variables (see :meth:`iter_declared_vars`)
and captured variables (see :meth:`iter_captured_vars`)."""
"""Get an iterable over all real-time classical variables that are declared as inputs to
this circuit scope. This excludes locally declared variables (see
:meth:`iter_declared_vars`) and captured variables (see :meth:`iter_captured_vars`)."""
if self._control_flow_scopes:
return ()
return self._vars_input.values()
def iter_captured_vars(self) -> typing.Iterable[expr.Var]:
"""Get an iterable over all runtime classical variables that are captured by this circuit
"""Get an iterable over all real-time classical variables that are captured by this circuit
scope from a containing scope. This excludes input variables (see :meth:`iter_input_vars`)
and locally declared variables (see :meth:`iter_declared_vars`)."""
if self._control_flow_scopes:
@ -1730,8 +1730,8 @@ class QuantumCircuit:
qc.cx(0, i)
qc.measure(range(8), cr2)
# Now when we add the variable, it is initialized using the runtime state of the two
# classical registers we measured into above.
# Now when we add the variable, it is initialized using the real-time state of the
# two classical registers we measured into above.
qc.add_var(my_var, expr.bit_and(cr1, cr2))
"""
# Validate the initialiser first to catch cases where the variable to be declared is being
@ -2619,7 +2619,7 @@ class QuantumCircuit:
return self.append(Reset(), [qubit], [])
def store(self, lvalue: typing.Any, rvalue: typing.Any, /) -> InstructionSet:
"""Store the result of the given runtime classical expression ``rvalue`` in the memory
"""Store the result of the given real-time classical expression ``rvalue`` in the memory
location defined by ``lvalue``.
Typically ``lvalue`` will be a :class:`~.expr.Var` node and ``rvalue`` will be some
@ -2631,7 +2631,7 @@ class QuantumCircuit:
a :class:`~.expr.Var` node, but you can also write to :class:`.Clbit` or
:class:`.ClassicalRegister` memory locations if your hardware supports it. The
memory location must already be present in the circuit.
rvalue: a runtime classical expression whose result should be written into the given
rvalue: a real-time classical expression whose result should be written into the given
memory location.
.. seealso::
@ -5023,11 +5023,11 @@ class QuantumCircuit:
qc.z(2)
Args:
condition (Tuple[Union[ClassicalRegister, Clbit], int]): A condition to be evaluated at
circuit runtime which, if true, will trigger the evaluation of ``true_body``. Can be
specified as either a tuple of a ``ClassicalRegister`` to be tested for equality
with a given ``int``, or as a tuple of a ``Clbit`` to be compared to either a
``bool`` or an ``int``.
condition (Tuple[Union[ClassicalRegister, Clbit], int]): A condition to be evaluated in
real time during circuit execution, which, if true, will trigger the evaluation of
``true_body``. Can be specified as either a tuple of a ``ClassicalRegister`` to be
tested for equality with a given ``int``, or as a tuple of a ``Clbit`` to be
compared to either a ``bool`` or an ``int``.
true_body (Optional[QuantumCircuit]): The circuit body to be run if ``condition`` is
true.
qubits (Optional[Sequence[QubitSpecifier]]): The circuit qubits over which the if/else
@ -5099,7 +5099,7 @@ class QuantumCircuit:
qc.x(0)
Args:
condition: A condition to be evaluated at circuit runtime which,
condition: A condition to be evaluated in real time at circuit execution, which,
if true, will trigger the evaluation of ``true_body``. Can be
specified as either a tuple of a ``ClassicalRegister`` to be
tested for equality with a given ``int``, or as a tuple of a

View File

@ -18,10 +18,13 @@ from qiskit.circuit.singleton import SingletonInstruction, stdlib_singleton_key
class Reset(SingletonInstruction):
"""Qubit reset."""
r"""Incoherently reset a qubit to the :math:`\lvert0\rangle` state."""
def __init__(self, label=None, *, duration=None, unit="dt"):
"""Create new reset instruction."""
"""
Args:
label: optional string label of this instruction.
"""
super().__init__("reset", 1, 0, [], label=label, duration=duration, unit=unit)
_singleton_lookup_key = stdlib_singleton_key()

View File

@ -57,10 +57,14 @@ class Store(Instruction):
This is a low-level primitive of the classical-expression handling (similar to how
:class:`~.circuit.Measure` is a primitive for quantum measurement), and is not safe for
subclassing. It is likely to become a special-case instruction in later versions of Qiskit
circuit and compiler internal representations."""
subclassing."""
def __init__(self, lvalue: expr.Expr, rvalue: expr.Expr):
"""
Args:
lvalue: the memory location being stored into.
rvalue: the expression result being stored.
"""
if not expr.is_lvalue(lvalue):
raise CircuitError(f"'{lvalue}' is not an l-value")
@ -82,6 +86,7 @@ class Store(Instruction):
return self.params[1]
def c_if(self, classical, val):
""":meta hidden:"""
raise NotImplementedError(
"stores cannot be conditioned with `c_if`; use a full `if_test` context instead"
)