Writing Documentation

The documentation for QInfer is written using the Sphinx documentation engine, and is hosted by ReadTheDocs. This allows us to produce high-quality HTML- and LaTeX-formatted reference and tutorial material for QInfer. In particular, the documentation hosted by ReadTheDocs is integrated with the GitHub project for QInfer, simplifying the process of building and deploying documentation.

In this section, we will discuss how to use Sphinx and ReadTheDocs together to contribute to and improve QInfer documentation.

Building Documentation With Sphinx

In developing and writing documentation, it is helpful to be able to compile the current version of the documentation offline. To do so, first install Sphinx itself. If you are using Anaconda:

$ conda install sphinx

Otherwise, we suggest installing Sphinx using pip:

$ pip install sphinx

In either case, after installing Sphinx, you may need to install additional libraries that used by particular examples in the QInfer documentation. On Anaconda:

$ conda install scikit-learn ipython future matplotlib
$ conda install -c conda-forge qutip
$ pip install mpltools

Otherwise:

$ pip install -r doc/rtd-requirements.txt

With the dependencies installed, you can now build the documentation using the Makefile provided by Sphinx, or using the make.bat script for Windows. Note that because the documentation includes several computationally-intensive examples, the build process may take a significant amount of time (a few minutes). On Linux and OS X:

$ cd doc/
$ make clean # Deletes all previously compiled outputs.
$ make html # Builds HTML-formatted docs.
$ make latexpdf # Builds PDF-formatted docs using LaTeX.

All of the compiled outputs will be saved to the doc/_build folder. In particular, the HTML version can be found at doc/_build/html/index.html.

On Windows, we recommend using PowerShell to run make.bat:

PS > cd doc/
PS > .\make.bat clean
PS > .\make.bat html

Note that on Windows, building PDF-formatted docs requires an additional step. First, make the LaTeX-formatted source:

PS > .\make latex

This will produce a folder called doc/_build/latex containing QInfer.tex. Build this with your favorite LaTeX front-end to produce the final PDF.

Formatting Documentation With reStructuredText

The documentation itself is written in the reStructuredText language, an extensible and (largely) human-readable text format. We recommend reading the primer provided with Sphinx to get a start. Largely, however, documentation can be written as plain text, with emphasis indicated by *asterisks*, strong text indicated by **double asterisks**, and verbatim snippets indicated by ``double backticks``. Sections are denoted by different kinds of underlining, using =, -, ~ and ^ to indicate sections, subsections, paragraphs and subparagraphs, respectively.

Links are a bit more complicated, and take on a couple several different forms:

  • Inline links consist of backticks, with addresses denoted in angle-brackets, `link text <link target>`_. Note the final _, which denotes that the backticks describe a link.

  • Alternatively, the link target may be placed later on the page, as in the following snippet:

    Lorem `ipsum`_ dolor sit amet...
    
    .. _ipsum: http://www.lipsum.com/
    
  • Links within the documentation are made using :ref:. For example, :ref:`apiref`: formats as API Reference. The target of such a reference must be declared before a section header, as in the following example, which declares the target foobar:

    .. _foobar:
    
    A Foo About Bar
    ---------------
    
  • Links to Python classes, modules and functions are formatted using :class:, :mod: and :func:, repsectively. For example, :class:`qinfer.SMCUpdater formats as qinfer.SMCUpdater. To suppress the path to a Python name, preface the name with a tilde (~), as in :class:`~qinfer.SMCUpdater:`. For a Python name to be a valid link target, it must be listed in the API Reference (see below), or must be documented in one of the external projects listed in doc/conf.py. For instance, to link to NumPy documentation, use a link of the form :class:`~numpy.ndarray`.

  • Finally, QInfer provides special notation for linking to DOIs, Handles and arXiv postings:

    :doi:`10.1088/1367-2630/18/3/033024`, :hdl:`10012/9217`,
    :arxiv:`1304.5828`
    

Typesetting Math

Math is formatted using the Sphinx markup :math:`...` in place of $, and using the .. math:: directive in place of $$. When building HTML- or PDF-formatted documentation, this is automatically converted to MathJax- or LaTeX-formatted math. The QInfer documentation is configured with several macros available to each of MathJax and LaTeX, specified in doc/_templates/page.html and doc/conf.py, respectively. For example, :math:`\expect` is configured to produce the blackboard-bold expectation operator \(\expect\).

Docstrings and API References

One of the most useful features of Sphinx is that it can import documentation from Python code itself. In particular, the .. autofunction:: and .. autoclass:: directives import documentation from functions and classes, respectively. These directives typeset the docstrings for their targets as reStructuredText, with the following notation used to indicate arguments, return types, etc.:

  • :param name: is used to declare that a class’ initializer or a function takes an argument named name, and is followed by a description of that parameter.
  • :param type name: can be used to indicate that name has the type type type. If type is a recognized Python type, then Sphinx will automatically convert it into a link.
  • :type name: can be used to provide more detailed information about the type of the parameter name, and is followed by a longer description of that parameter’s type. :type: on its own can be used to denote the type of a property accessor.
  • :return: is used to describe what a function returns.
  • :rtype: is used to describe the type of a return value.
  • :raises exc_type: denotes that the described function raises an exception of type exc_type, and describes the conditions under which that exception is raised.

In addition to the standard Sphinx fields described above, QInfer adds the following fields:

  • :modelparam name: describes a model parameter named name, where the name is formatted as math (or should be, pending bugs in the documentation configuration).
  • :expparam field_type field_name: describes an experiment parameter field named field_name with dtype field_type.
  • :scalar-expparam scalar_type describes that a class has exactly one experiment parameter of type scalar_type.
  • :column dtype name: describes a column for data taken by Simple Estimation Functions functions.

Importantly, if math is included in a docstring, it is highly recommended to format the docstring as a raw string; that is, as a string starting with r' or r" for inline strings or r''' or r""" for multi-line strings. This avoids having to escape TeX markup that appears within a docstring. For instance, consider the following hypothetical function:

def state(theta, phi):
    r"""
    Returns an array representing :math:`\cos(\theta)\ket{0} +
    \sin(\theta) e^{i \phi} \ket{1}`.
    """
    ...

If the docstring were instead declared using """, then \t everywhere inside the docstring would be interpreted by Python as a tab character, and not as the start of a LaTeX command.

Showing Code Snippets

The documentation would be useless without code snippets, so Sphinx provides several ways to show snippets. Perhaps the most common is doctest-style:

Lorem ipsum dolor sit amet...

>>> print("Hello, world!")
Hello, world!

As described in _doctest_devguide, these snippets are run automatically as tests to ensure that the documentation and code are both correct. To mark a particular line in a snippet as not testable, add # doctest: +SKIP as a comment after.

For longer snippets, or for snippets that should not be run as tests, use the .. code:: python directive:

.. code:: python

    print("Hello, world!")

This formats as:

print("Hello, world!")

Finally, a block can be formatted as code without any syntax highlighting by using the :: notation on the previous line, and then indenting the block itself:

This is in fact how this section denotes reStructuredText code samples::

    :foobar: is not a valid reStructuredText role.

Plotting Support

Sphinx can also run Python code and plot the resulting figures. To do so, use the .. plot:: directive. Note that any such plots should be relatively quick to generate, especially so as to not overburden the build servers provided by ReadTheDocs. The .. plot:: directive has been configured to automatically import QInfer itself and to import matplotlib as plt. Thus, for example, the following demonstrates plotting functionality provided by the qinfer.tomography module:

.. plot::

    basis = tomography.bases.pauli_basis(1)
    prior = tomography.distributions.GinibreDistribution(basis)
    tomography.plot_rebit_prior(prior, rebit_axes=[1, 3])
    plt.show()

Note the plt.show() call at the end; this is required to produce the final figure!