Skip to content

Commit

Permalink
Write module-level qiskit.circuit documentation (Qiskit#11904)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

* 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 <[email protected]>
  • Loading branch information
jakelishman and sbrandhsn authored Apr 5, 2024
1 parent 2cbbe2b commit 99c0497
Show file tree
Hide file tree
Showing 26 changed files with 1,337 additions and 392 deletions.
1,288 changes: 1,133 additions & 155 deletions qiskit/circuit/__init__.py

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions qiskit/circuit/_classical_resource_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ def map_condition(self, condition, /, *, allow_reorder=False):
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):
Expand Down
3 changes: 3 additions & 0 deletions qiskit/circuit/annotated_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ def __init__(self, base_op: Operation, modifiers: Union[Modifier, List[Modifier]
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):
Expand Down
23 changes: 10 additions & 13 deletions qiskit/circuit/barrier.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,26 @@
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)
Expand Down
1 change: 0 additions & 1 deletion qiskit/circuit/bit.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
Expand Down
4 changes: 2 additions & 2 deletions qiskit/circuit/classical/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
4 changes: 2 additions & 2 deletions qiskit/circuit/classical/expr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
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
Expand Down
30 changes: 8 additions & 22 deletions qiskit/circuit/controlflow/break_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,17 @@


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)


Expand Down
2 changes: 1 addition & 1 deletion qiskit/circuit/controlflow/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def remove_var(self, var: expr.Var):

@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
Expand Down
30 changes: 8 additions & 22 deletions qiskit/circuit/controlflow/continue_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,17 @@


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)


Expand Down
38 changes: 30 additions & 8 deletions qiskit/circuit/controlflow/control_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@


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)
Expand All @@ -36,17 +41,34 @@ def __init__(self, *args, **kwargs):
@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.
"""
31 changes: 8 additions & 23 deletions qiskit/circuit/controlflow/for_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__(
Expand All @@ -60,9 +38,16 @@ def __init__(
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
)
Expand Down
40 changes: 13 additions & 27 deletions qiskit/circuit/controlflow/if_else.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__(
Expand All @@ -85,6 +58,19 @@ def __init__(
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

Expand Down
Loading

0 comments on commit 99c0497

Please sign in to comment.