Skip to content

Commit

Permalink
Write complete manual QuantumCircuit documentation (#12403) (#12420)
Browse files Browse the repository at this point in the history
* Write complete manual `QuantumCircuit` documentation

This writes huge tracts of new `QuantumCircuit` API documentation,
linking together alike methods and writing explanatory text for how all
the components fit together.  There's likely an awful lot more that
could go into this too, but this hopefully should impose a lot more
order on the huge `QuantumCircuit` documentation page, and provide a lot
more explanation for how the class works holistically.

In particular, the section on the control-flow builder interface could
do with a lot more exposition and examples right now.

* Reword from review

Co-authored-by: Matthew Treinish <[email protected]>

* Add missing text around `Var` methods

* Add example to `find_bit`

* Comment on metadata through serialization

* Add see-also sections to undesirable methods

* Re-add internal utilities to documentation

* Add examples to `depth`

---------

Co-authored-by: Matthew Treinish <[email protected]>
(cherry picked from commit 72ad545)

Co-authored-by: Jake Lishman <[email protected]>
  • Loading branch information
mergify[bot] and jakelishman authored May 16, 2024
1 parent 0a05ea2 commit 3f0b5e3
Show file tree
Hide file tree
Showing 4 changed files with 1,098 additions and 299 deletions.
1 change: 1 addition & 0 deletions docs/apidoc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Circuit construction:
:maxdepth: 1

circuit
qiskit.circuit.QuantumCircuit
circuit_classical
classicalfunction
circuit_library
Expand Down
17 changes: 17 additions & 0 deletions docs/apidoc/qiskit.circuit.QuantumCircuit.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.. _qiskit-circuit-quantumcircuit:

==============================
:class:`.QuantumCircuit` class
==============================

..
This is so big it gets its own page in the toctree, and because we
don't want it to use autosummary.
.. currentmodule:: qiskit.circuit

.. autoclass:: qiskit.circuit.QuantumCircuit
:no-members:
:no-inherited-members:
:no-special-members:
:class-doc-from: class
163 changes: 15 additions & 148 deletions qiskit/circuit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,16 +321,6 @@
:class:`QuantumCircuit` class itself and the multitude of available methods on it in its class
documentation.
..
TODO: the intention is to replace this `autosummary` directive with a proper entry in the API
toctree once the `QuantumCircuit` class-level documentation has been completely rewritten into
more of this style. For now, this just ensures it gets *any* page generated.
.. autosummary::
:toctree: ../stubs/
QuantumCircuit
Internally, a :class:`QuantumCircuit` contains the qubits, classical bits, compile-time parameters,
real-time variables, and other tracking information about the data it acts on and how it is
parametrized. It then contains a sequence of :class:`CircuitInstruction`\ s, which contain
Expand Down Expand Up @@ -390,7 +380,7 @@
Circuits track registers, but registers themselves impart almost no behavioral differences on
circuits. The only exception is that :class:`ClassicalRegister`\ s can be implicitly cast to
unsigned integers for use in conditional comparisons of :ref:`control flow operations
<circuit-control-flow>`.
<circuit-control-flow-repr>`.
Classical registers and bits were the original way of representing classical data in Qiskit, and
remain the most supported currently. Longer term, the data model is moving towards a more complete
Expand Down Expand Up @@ -433,6 +423,8 @@
circuit), but these are now discouraged and you should use the alternatives noted in those methods.
.. _circuit-operations-instructions:
Operations, instructions and gates
----------------------------------
Expand Down Expand Up @@ -598,17 +590,14 @@
Real-time classical computation
-------------------------------
.. note::
.. seealso::
:mod:`qiskit.circuit.classical`
Module-level documentation for how the variable-, expression- and type-systems work, the
objects used to represent them, and the classical operations available.
The primary documentation for real-time classical computation is in the module-level
documentation of :mod:`qiskit.circuit.classical`.
You might also want to read about the circuit methods for working with real-time variables on
the :class:`QuantumCircuit` class page.
..
TODO: write a section in the QuantumCircuit-level guide about real-time-variable methods and
cross-ref to it.
:ref:`circuit-real-time-methods`
The :class:`QuantumCircuit` methods for working with these variables in the context of a
single circuit.
Qiskit has rudimentary low-level support for representing real-time classical computations, which
happen during the QPU execution and affect the results. We are still relatively early into hardware
Expand Down Expand Up @@ -674,7 +663,7 @@
ParameterVector
.. _circuit-control-flow:
.. _circuit-control-flow-repr:
Control flow in circuits
------------------------
Expand Down Expand Up @@ -718,11 +707,8 @@
The classes representations are documented here, but please note that manually constructing
these classes is a low-level operation that we do not expect users to need to do frequently.
..
TODO: make this below statement valid, and reinsert.
Users should read :ref:`circuit-creating-control-flow` for the recommended workflows for
building control-flow-enabled circuits.
Users should read :ref:`circuit-control-flow-methods` for the recommended workflows for building
control-flow-enabled circuits.
Since :class:`ControlFlowOp` subclasses are also :class:`Instruction` subclasses, this means that
the way they are stored in :class:`CircuitInstruction` instances has them "applied" to a sequence of
Expand Down Expand Up @@ -772,11 +758,8 @@
argument), but user code will typically use the control-flow builder interface, which handles this
automatically.
..
TODO: make the below sentence valid, then re-insert.
Consult :ref:`the control-flow construction documentation <circuit-creating-control-flow>` for
more information on how to build circuits with control flow.
Consult :ref:`the control-flow construction documentation <circuit-control-flow-methods>` for more
information on how to build circuits with control flow.
.. _circuit-custom-gates:
Expand Down Expand Up @@ -920,122 +903,6 @@ def __array__(self, dtype=None, copy=None):
Working with circuit-level objects
==================================
Circuit properties
------------------
..
TODO: rewrite this section and move it into the `QuantumCircuit` class-level overview of its
functions.
When constructing quantum circuits, there are several properties that help quantify
the "size" of the circuits, and their ability to be run on a noisy quantum device.
Some of these, like number of qubits, are straightforward to understand, while others
like depth and number of tensor components require a bit more explanation. Here we will
explain all of these properties, and, in preparation for understanding how circuits change
when run on actual devices, highlight the conditions under which they change.
Consider the following circuit:
.. plot::
:include-source:
from qiskit import QuantumCircuit
qc = QuantumCircuit(12)
for idx in range(5):
qc.h(idx)
qc.cx(idx, idx+5)
qc.cx(1, 7)
qc.x(8)
qc.cx(1, 9)
qc.x(7)
qc.cx(1, 11)
qc.swap(6, 11)
qc.swap(6, 9)
qc.swap(6, 10)
qc.x(6)
qc.draw('mpl')
From the plot, it is easy to see that this circuit has 12 qubits, and a collection of
Hadamard, CNOT, X, and SWAP gates. But how to quantify this programmatically? Because we
can do single-qubit gates on all the qubits simultaneously, the number of qubits in this
circuit is equal to the **width** of the circuit:
.. code-block::
qc.width()
.. parsed-literal::
12
We can also just get the number of qubits directly:
.. code-block::
qc.num_qubits
.. parsed-literal::
12
.. important::
For a quantum circuit composed from just qubits, the circuit width is equal
to the number of qubits. This is the definition used in quantum computing. However,
for more complicated circuits with classical registers, and classically controlled gates,
this equivalence breaks down. As such, from now on we will not refer to the number of
qubits in a quantum circuit as the width.
It is also straightforward to get the number and type of the gates in a circuit using
:meth:`QuantumCircuit.count_ops`:
.. code-block::
qc.count_ops()
.. parsed-literal::
OrderedDict([('cx', 8), ('h', 5), ('x', 3), ('swap', 3)])
We can also get just the raw count of operations by computing the circuits
:meth:`QuantumCircuit.size`:
.. code-block::
qc.size()
.. parsed-literal::
19
A particularly important circuit property is known as the circuit **depth**. The depth
of a quantum circuit is a measure of how many "layers" of quantum gates, executed in
parallel, it takes to complete the computation defined by the circuit. Because quantum
gates take time to implement, the depth of a circuit roughly corresponds to the amount of
time it takes the quantum computer to execute the circuit. Thus, the depth of a circuit
is one important quantity used to measure if a quantum circuit can be run on a device.
The depth of a quantum circuit has a mathematical definition as the longest path in a
directed acyclic graph (DAG). However, such a definition is a bit hard to grasp, even for
experts. Fortunately, the depth of a circuit can be easily understood by anyone familiar
with playing `Tetris <https://en.wikipedia.org/wiki/Tetris>`_. Lets see how to compute this
graphically:
.. image:: /source_images/depth.gif
We can verify our graphical result using :meth:`QuantumCircuit.depth`:
.. code-block::
qc.depth()
.. parsed-literal::
9
.. _circuit-abstract-to-physical:
Converting abstract circuits to physical circuits
Expand Down
Loading

0 comments on commit 3f0b5e3

Please sign in to comment.