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

Write complete manual QuantumCircuit documentation #12403

Merged
merged 8 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
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some notes if we stick with this rather than the simpler QuantumCircuit (no link):

  1. We're not consistent with all the other class pages, e.g. https://docs.quantum.ibm.com/api/qiskit/qiskit.circuit.AncillaRegister
  2. I don't think the link is very useful. On https://qiskit-docs-preview-pr-1380.1799mxdls7qz.us-south.codeengine.appdomain.cloud/api/qiskit/dev/qiskit.circuit.QuantumCircuit, it simply takes you to the class definition which is the first part of the page anyways
  3. The styling is messed up for code in headers, tracked by https://github.ibm.com/IBM-Q-Software/iqp-channel-docs/issues/1037. If we stick with this approach, we'll try to fix the issue in the next week

Despite those concerns, I think I agree with your approach here, particularly because it makes the index page more readable with QuantumCircuit being escaped as code and having the word class. I tried to get a custom title to work in index.rst like '``QuantumCircuit`` class <qiskit.circuit.QuantumCircuit>', but RST doesn't like the inline formatting with `.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mostly did this out of habit because I almost always put in cross-references when possible. If there's a way that works a little better, I can do that.

From my side, I don't mind the styling not being perfect immediately, if that's the remaining blocker (I'd seen it locally, too). It's a styling bug that we probably need to get fixed anyway, because I'd be surprised if it's not in use in at least some other places - I'm quite likely to have done it somewhere else in the API docs too - but it's still totally legible in the meantime, it just looks slightly odd.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we could get the index.rst to properly render 'QuantumCircuit class <qiskit.circuit.QuantumCircuit>', then I would ask us to change to simply QuantumCircuit. But I couldn't get that working. So I think what you have is the best choice because it makes the index page more readable.

From my side, I don't mind the styling not being perfect immediately, if that's the remaining blocker

Indeed, it's my biggest concern. It's always been a problem though, and we'll bump https://github.ibm.com/IBM-Q-Software/iqp-channel-docs/issues/1037 up in priority. It's a short-term bug, so I agree it's not a blocker.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean a link where the inline code block and the word "class" are both the link text? If so: nested syntax (inline code inside a link) is (in)famously hard to do in rST. It's just about possible to hack together in some cases, but the syntax is at best arcane.

Sphinx-specific stuff is easier because that produces the nested elements by manipulating the docutils tree directly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean a link where the inline code block and the word "class" are both the link text? If so: nested syntax (inline code inside a link) is (in)famously hard to do in rST. It's just about possible to hack together in some cases, but the syntax is at best arcane.

Yep, exactly. So, I think we should stick with how you have things.

==============================

..
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
Loading