Skip to content

Commit

Permalink
Automatically generate documentation ReST files (#339)
Browse files Browse the repository at this point in the history
* Automate generation of documentation ReST files

* Fix error in conf.py

* Adjust .gitignore
  • Loading branch information
Takishima committed Feb 5, 2020
1 parent 7da50cf commit d5bf14e
Show file tree
Hide file tree
Showing 13 changed files with 319 additions and 583 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# python artifacts
*.pyc
docs/projectq.*.rst
*.so
build/
var/
168 changes: 148 additions & 20 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@
import sys
sys.path.insert(0, os.path.abspath('..'))

import projectq
# Also import all the modules that are not automatically imported
import projectq.libs.math
import projectq.libs.revkit
import projectq.setups.default
import projectq.setups.grid
import projectq.setups.ibm
import projectq.setups.ibm16
import projectq.setups.linear
import projectq.setups.restrictedgateset
import projectq.setups.decompositions

# -- General configuration ------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
Expand All @@ -33,8 +45,11 @@
import sphinx_rtd_theme

extensions = [
'sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'sphinx.ext.mathjax',
'sphinx.ext.autosummary', 'sphinx.ext.linkcode',
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.mathjax',
'sphinx.ext.autosummary',
'sphinx.ext.linkcode',
]

autosummary_generate = True
Expand Down Expand Up @@ -125,7 +140,6 @@
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False


# -- Options for HTML output ----------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
Expand Down Expand Up @@ -271,8 +285,7 @@
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'projectq.tex', 'projectq Documentation',
'a', 'manual'),
(master_doc, 'projectq.tex', 'projectq Documentation', 'a', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
Expand Down Expand Up @@ -307,30 +320,24 @@
#
# latex_domain_indices = True


# -- Options for manual page output ---------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'projectq', 'projectq Documentation',
[author], 1)
]
man_pages = [(master_doc, 'projectq', 'projectq Documentation', [author], 1)]

# If true, show URL addresses after external links.
#
# man_show_urls = False


# -- Options for Texinfo output -------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'projectq', 'projectq Documentation',
author, 'projectq', 'One line description of project.',
'Miscellaneous'),
(master_doc, 'projectq', 'projectq Documentation', author, 'projectq',
'One line description of project.', 'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
Expand All @@ -351,7 +358,6 @@

# -- Options for sphinx.ext.linkcode --------------------------------------
import inspect
import projectq


def linkcode_resolve(domain, info):
Expand Down Expand Up @@ -381,7 +387,11 @@ def linkcode_resolve(domain, info):
return None
else:
try:
obj = eval(info['module'] + '.' + info['fullname'])
if ('module' in info and 'fullname' in info
and info['module'] and info['fullname']):
obj = eval(info['module'] + '.' + info['fullname'])
else:
return None
except AttributeError:
# Object might be a non-static attribute of a class, e.g.,
# self.num_qubits, which would only exist after init was called.
Expand All @@ -400,15 +410,133 @@ def linkcode_resolve(domain, info):
if len(new_higher_name) <= 1:
obj = eval(info['module'])
else:
obj = eval(info['module'] + '.' +
'.'.join(new_higher_name[:-1]))
obj = eval(info['module'] + '.'
+ '.'.join(new_higher_name[:-1]))
filepath = inspect.getsourcefile(obj)
line_number = inspect.getsourcelines(obj)[1]
except:
return None
# Only require relative path projectq/relative_path
projectq_path = inspect.getsourcefile(projectq)[:-11]
relative_path = os.path.relpath(filepath, projectq_path)
url = (github_url + github_tag + "/projectq/" + relative_path + "#L" +
str(line_number))
url = (github_url + github_tag + "/projectq/" + relative_path + "#L"
+ str(line_number))
return url


# ------------------------------------------------------------------------------

import importlib
sys.path.append(os.path.abspath('.'))
desc = importlib.import_module('package_description')

PackageDescription = desc.PackageDescription

# ------------------------------------------------------------------------------
# Define the description of ProjectQ packages and their submodules below.
#
# In order for the automatic package recognition to work properly, it is
# important that PackageDescription of sub-packages appear earlier in the list
# than their parent package (see for example libs.math and libs.revkit
# compared to libs).
#
# It is also possible to customize the presentation of submodules (see for
# example the setups and setups.decompositions) or even to have private
# sub-modules listed in the documentation page of a parent packages (see for
# example the cengines package)

descriptions = [
PackageDescription('backends'),
PackageDescription('cengines',
desc='''
The ProjectQ compiler engines package.
'''),
PackageDescription('libs.math',
desc='''
A tiny math library which will be extended thoughout the next weeks. Right now, it only contains the math functions necessary to run Beauregard's implementation of Shor's algorithm.
'''),
PackageDescription('libs.revkit',
desc='''
This library integrates `RevKit <https://msoeken.github.io/revkit.html>`_ into
ProjectQ to allow some automatic synthesis routines for reversible logic. The
library adds the following operations that can be used to construct quantum
circuits:
- :class:`~projectq.libs.revkit.ControlFunctionOracle`: Synthesizes a reversible circuit from Boolean control function
- :class:`~projectq.libs.revkit.PermutationOracle`: Synthesizes a reversible circuit for a permutation
- :class:`~projectq.libs.revkit.PhaseOracle`: Synthesizes phase circuit from an arbitrary Boolean function
RevKit can be installed from PyPi with `pip install revkit`.
.. note::
The RevKit Python module must be installed in order to use this ProjectQ library.
There exist precompiled binaries in PyPi, as well as a source distribution.
Note that a C++ compiler with C++17 support is required to build the RevKit
python module from source. Examples for compatible compilers are Clang
6.0, GCC 7.3, and GCC 8.1.
The integration of RevKit into ProjectQ and other quantum programming languages is described in the paper
* Mathias Soeken, Thomas Haener, and Martin Roetteler "Programming Quantum Computers Using Design Automation," in: Design Automation and Test in Europe (2018) [`arXiv:1803.01022 <https://arxiv.org/abs/1803.01022>`_]
''',
module_special_members='__init__,__or__'),
PackageDescription('libs',
desc='''
The library collection of ProjectQ which, for now, consists of a tiny math library and an interface library to RevKit. Soon, more libraries will be added.
'''),
PackageDescription('meta',
desc='''
Contains meta statements which allow more optimal code while making it easier for users to write their code.
Examples are `with Compute`, followed by an automatic uncompute or `with Control`, which allows the user to condition an entire code block upon the state of a qubit.
'''),
PackageDescription('ops',
desc='''
The operations collection consists of various default gates and is a work-in-progress, as users start to work with ProjectQ.
''',
module_special_members='__init__,__or__'),
PackageDescription('setups.decompositions',
desc='''
The decomposition package is a collection of gate decomposition / replacement rules which can be used by, e.g., the AutoReplacer engine.
'''),
PackageDescription('setups',
desc='''
The setups package contains a collection of setups which can be loaded by the `MainEngine`. Each setup contains a `get_engine_list` function which returns a list of compiler engines:
Example:
.. code-block:: python
import projectq.setups.ibm as ibm_setup
from projectq import MainEngine
eng = MainEngine(engine_list=ibm_setup.get_engine_list())
# eng uses the default Simulator backend
The subpackage decompositions contains all the individual decomposition rules
which can be given to, e.g., an `AutoReplacer`.
''',
submodules_desc='''
Each of the submodules contains a setup which can be used to specify the
`engine_list` used by the `MainEngine` :''',
submodule_special_members='__init__'),
PackageDescription(
'types', '''
The types package contains quantum types such as Qubit, Qureg, and WeakQubitRef. With further development of the math library, also quantum integers, quantum fixed point numbers etc. will be added.
'''),
]
# ------------------------------------------------------------------------------
# Automatically generate ReST files for each package of ProjectQ

for desc in descriptions:
fname = os.path.join(os.path.dirname(os.path.abspath('__file__')),
'projectq.{}.rst'.format(desc.name))
lines = None
if os.path.exists(fname):
with open(fname, 'r') as fd:
lines = [line[:-1] for line in fd.readlines()]

new_lines = desc.get_ReST()

if new_lines != lines:
with open(fname, 'w') as fd:
fd.write('\n'.join(desc.get_ReST()))

0 comments on commit d5bf14e

Please sign in to comment.