Documenting NuPIC with Doxygen

Scott Purdy edited this page Jun 29, 2015 · 18 revisions
Clone this wiki locally

We need help documenting NuPIC! Please see the Documentation Priority Listing if you're interested in helping.

NuPIC API docs are hosted on http://numenta.org/docs/.

NuPIC uses Doxygen for API documentation. Doxygen uses a Doxyfile to define the parameters of the documentation build, which includes what files will be indexed and how the source code will be processed.

Doc Publishing is Automated

Every time new commits are pushed to the master branch of NuPIC, a new doc build runs and publishes results to http://numenta.org/docs/. All you have to do is update the docs as described below and create a pull request as described in our Developer Workflow. Once it gets merged, your doc changes will be live.

Adding new files to the documentation

The NuPIC Doxyfile is currently configured by whitelisting those files which should be indexed and turned into documentation. For example, as of 10-Dec-2013, the following files are being processed into documentation:

INPUT                  = py/nupic/research/__init__.py \
                         py/nupic/research/TP10X2.py \
                         py/nupic/research/TPTrivial.py \
                         py/nupic/research/TP.py

To add a new file to be documented, simply add it to this list of INPUT files.

Documenting code within comments

There are extensive instructions for commenting code on the Doxygen website, but here are some highlights and useful tips. Doxygen provides special commands for denoting things such as method parameters, return values, and referencing other properties of code.

Python

Python code must be documented within a """ triple quoted multiline comment, just like PEP-257.

C++

C++ should be documented inside a Javadoc-style multiline comment:

/**
 * ... text ...
 */

Documenting conventions

Basics

  • JAVADOC_AUTOBRIEF option is enabled, so the first line of each documented comment becomes the brief introduction of method being documented
  • use @ to prefix Doxygen commands, not \
  • documenting comment should be wrapped around column 80
  • brief doc(i.e. the first line of the doc of each entity) should be ended with a period and separated from the rest with an empty line
  • docs for @param and @returns may not end with periods
  • docs for @param and @returns should start at another line, precedent by spaces, to prettify the comment
  • docs for @params and @returns should be separated by an empty line
  • for bool methods that are too simple, may not provide a redundant brief doc, only document the @returns

Useful advanced special commands

  • may grouped methods using the Member Groups feature provided by Doxygen
  • may use these neat Doxygen commands:
    • @name, @{ and @} for grouping
    • @a for referencing arguments
    • @c for referencing types
    • @param[out] for output parameter
    • @code{.cpp} for showing example code snippets in doc
    • @note for noting
    • @todo for marking todos and generate todo list
    • @internal for preventing some outdated comment to show at the doc

Example

Here is an example of the docstring within the python code for the Segment class in TP.py:

def dutyCycle(self, active=False, readOnly=False):
  """Compute/update and return the positive activations duty cycle of
  this segment. This is a measure of how often this segment is
  providing good predictions.

  @param active True if segment just provided a good prediction

  @param readOnly If True, compute the updated duty cycle, but don't change
      the cached value. This is used by debugging print statements.

  @returns The duty cycle, a measure of how often this segment is
      providing good predictions.

  **NOTE:** This method relies on different schemes to compute the duty cycle
  based on how much history we have. In order to support this tiered
  approach **IT MUST BE CALLED ON EVERY SEGMENT AT EACH DUTY CYCLE TIER**
  (@ref dutyCycleTiers).

  When we don't have a lot of history yet (first tier), we simply return
  number of positive activations / total number of iterations

  After a certain number of iterations have accumulated, it converts into
  a moving average calculation, which is updated only when requested
  since it can be a bit expensive to compute on every iteration (it uses
  the pow() function).

  The duty cycle is computed as follows:

      dc[t] = (1-alpha) * dc[t-1] + alpha * value[t]

  If the value[t] has been 0 for a number of steps in a row, you can apply
  all of the updates at once using:

      dc[t] = (1-alpha)^(t-lastT) * dc[lastT]

  We use the alphas and tiers as defined in @ref dutyCycleAlphas and
  @ref dutyCycleTiers.
  """

This produces HTML that displays something like this (styles may change):

HTML example of rendered documentation

Method parameters are specified with the @param annotation. Return values are specified with @returns. Other parts of the code are reference with links when the @ref annotation is used. You can also use Markdown within the docstring for formatting.

Running a local doc build

Before submitting a pull request with documentation changes, please be sure to run a local doc build against the NuPIC codebase to ensure the docs you've created are rendering proplerly in HTML.

Requirements

  • doxypy
    • must exist at /usr/local/bin/doxypy.py, which is where the Doxygen config expects it to exist.
  • Doxygen

Usage

$> cd $NUPIC
$> doxygen docs/Doxyfile

HTML documentation is generated in $NUPIC/html.