=============================
Contributing to Psignifit 3.0
=============================

Psignifit 3.0 is free software. You are free to modify the software under the terms of the license
that is distributed with Psignifit 3.0. We welcome developers that want to contribute to Psignifit 3.0.

Software Architecture
---------------------

The Psignifit 3.x code base is logically split into several components:

:psi++:
    The C++ *engine* of Psignifit.
:pypsignifit:
    High level Python interface, including visualisation methods.
:swignifit:
    Python interface to ``psi++`` autogenerated using the ``swig`` tool.
:cli:
    Pure C++ command-line interface to ``psi++``
:rpsignift:
    R interface to ``psi++``.
:mpsignifit:
    MATLAB interface to ``cli``.

We refer to previous versions of psignifit (2.5.6 and before) as
**psignifit-classic**.

The following UML inspired diagram shows the individual components of Psignifit 3.x, and how they relate:

.. image:: architecture.png
    :alt: Software Architecture
    :scale: 75 %

The diagram shows all components and how they are connected. The high-level
interfaces ``pypsignifit``, ``mpsignifit`` all eventually access
the ``psi++`` engine via an layer. Depending on the interface language, the
layer may be either ``swignifit`` or ``cli``.

In Linux, building the software begins with compiling the ``psi++`` headers and
sources into a shared library ``libpsipp.so``. Then ``swignifit`` is compiled
in two steps. First the swig tool translates the swig definition file
``swignifit_raw.i`` into the ``swignifit_raw.py`` and ``swignifit_raw.cxx``.
Then, the shared library ``_swignifit_raw.so`` is compiled and linked with
``libpsipp.so``. When accessing the engine from Python, the high-level
``pypsignifit`` calls one of the Python files in swignifit
``interface_methods.py`` or ``swignifit_raw.py``, which in turn call
``_swignifit_raw.so``, which in turn calls ``libpsipp.so``. For Matlab The
situation is similar, but instead of ``swignifit`` the ``cli`` handles calling
the engine.

Dependencies
------------

This section lists all dependencies. The version numbers are the Debian versions
we used when we began development, and hence they will probably be outdated by
the time you read this.

Compile-Time
............
* `Make <http://www.gnu.org/software/make/>`_ (3.81-8)
    for building the software
* `Gcc <http://gcc.gnu.org/>`_ (4:4.4.3-1)/
* `Python <python http://www.python.org/>`_ (2.5.5-6)/
* `Python/C API <http://docs.python.org/c-api/>`_ (2.5.5-2)
    for compiling the ``swignifit`` interface for Python
* `Simplified Wrapper and Interface Generator (SWIG) <http://www.swig.org/>`_ (1.3.40-2)
    for generating the ``swignifit`` interface for Python

Run-Time
........
* `Python <python http://www.python.org/>`_ (2.5.5-6)/
* `Numpy <http://numpy.scipy.org/>`_  (1:1.3.0-3)/
* `Scipy <http://www.scipy.org/>`_ (0.7.1-1)/
* `Matplotlib <http://matplotlib.sourceforge.net/>`_ (0.99.1.2-3)
    for the Python version

Documentation
.............

* `sphinx <http://sphinx.pocoo.org/>`_ (0.6.5-1)
    to generate the html documentation
* `doxygen <http://www.stack.nl/~dimitri/doxygen/>`_ (1.6.3-1)
   to generate the C++ documentation
* `epydoc <http://epydoc.sourceforge.net/>`_ (3.0.1-5)
   to generate the Python API documentation

Testing
.......

* `nosetest <http://somethingaboutorange.com/mrl/projects/nose/0.11.2/>`_ (0.11.1-1)
  for running some of the unit tests


Build System
------------

We use a combination of `distutils <http://docs.python.org/library/distutils.html>`_ and `make <http://www.gnu.org/software/make/>`_
to build the software.

There are several ``Makefiles``:

:Makefile:
    main makefile.
:src/Makefile:
    ``psi++`` makefile.
:cli/Makefile:
    ``cli`` makefile.
:cli/MakefileMinGW:
    ``cli`` makefile to compile ``mingw`` for windows.

Note that main makefile contains targets to invoke the ``psi++`` and ``cli``
makefiles. The main targets are ``build``, ``install``, ``clean`` and ``test``.
The main targets will invoke separate targets to build the individual components
of the software. If during development you wish to build components separately,
have a look at the main makefile, it should contain everything you need.

There is a single ``setup.py`` file that can be used to compile and install
``pypsignifit`` including the ``swignifit`` interface. Since the source download
we provide includes the already generated interface, this is the
recommended method of installation for users.

For more information about how to use the ``setup.py`` file, you may look at:
`Installing Pyhon Modules <http://docs.python.org/install/>`_.

Git-Repositories
----------------

We use `Git <http://git-scm.com/>`_ for version control. Our main repository is
hosted at `Sourceforge <http://sourceforge.net/>`_ as `Psignifit
<http://sourceforge.net/projects/psignifit/>`_. Clone the repository
with the following command :

.. code-block:: console

    $ git clone git://psignifit.git.sourceforge.net/gitroot/psignifit/psignifit

You can also `browse the Sourceforge repository online
<http://psignifit.git.sourceforge.net/git/gitweb.cgi?p=psignifit/psignifit;a=summary>`_.

We also provide a alternative repository on `Github <https://github.com/>`_:
`https://github.com/esc/Psignifit-3.x <https://github.com/esc/Psignifit-3.x>`_.
This is a mirror of the sourceforge which is updated daily. If you prefer to
use the Github workflow (fork -> clone -> pull-request) please fork from this
repository.

Layout
......

Every developer has his/her own branch, and we use the master branch to do
integration. Hence we have the following layout in the sourceforge repository:

:master:
    the integration branch
:ingo/master:
    Ingo's main branch
:val/master:
    Valentin's main branch

In addition we also make heavy use of short-lived topic branches, which are
deleted after being merged.

All branches except ``master`` are subject to rewind/rebase. So please base you
development either on ``master`` or better yet, on the latest development snapshot(see
below).

Commits
.......

To make it easier to keep track of the development of Psignifit, we use the
following marks forto identify what parts of the code
base we worked on:

:C++:
    C++ code base
:swig:
    swig interface
:py:
    Python code
:R:
    R code
:matlab:
    matlab code
:build:
    Build system
:docs:
    Documentation

And the following marks  to identify the type of change that was made

:NF:
    new feature
:BF:
    bug fix
:RF:
    refactor
:FO:
    formatting
:UT:
    unit test

Example::

    [build/RF] do proper signed tags with new tag naming structure

Also, If you wish to automate the process of creating such markers, to increase
consistency, we suggest using the following git-hook:
https://github.com/esc/commit-marker

Merging
.......

For easy tracking of what changes were absorbed during merge, we advise you to
enable merge summary within git:

.. code-block:: console

    $ git-config merge.summary true

Execute without installation
----------------------------

Since it is tedious to install ``pypsignifit`` during development. We provide a
so called in-place compilation. To compile the ``swignifit`` interface without
installation simply type:

.. code-block:: console

    $ make

You can then run:

.. code-block:: pycon

    >>> import pypsignifit as psi

from the source directory. Furthermore you can use the environment variable
``PYTHONPATH`` in case you need to bring source directory into scope elsewhere
in the filesystem.

Maintainers Notes
-----------------

This section contains notes about the release process. We also support this
process with various ``Makefile`` targets. All targets for release are prefixed
with ``dist-``

Since Psignift 3.x is still beta
software we provide so called development snapshots as and when new features and
bugfixes are available.

Development Snapshots
.....................

Development snapshots are made on a regular basis. They are invoked with:

.. code-block:: console

    $ make dist-upload-archives

This will create all the required zip files and windows installers, tag the git
repository, and upload the files and tags to sourceforge.

Tags
....

Tags should mark critical points in the development history in the following way:

* ``release/3.0_beta.YYYYMMDD.1`` marks the release of a development snapshot
* ``doc-YYYYMMDD`` marks a modification of the documentation that has been uploaded to sourceforge.

Older tags may have different versioning schemes. This scheme was established
beginning of 2012.

Extending
---------

This section contains hints about writing code.

Coding Style
............

We try to adhere to the:
`Numpy Docstring Conventions <http://projects.scipy.org/numpy/wiki/CodingStyleGuidelines#docstring-standard>`_
as far as possible.


Adding a new sigmoid
....................

In principle every part of the library can be replaced. This is generally done by deriving from the fundamental base classes.
An exception is adding a new sigmoid:

Adding a new sigmoid requires two steps:

1. Write a new class that inherits from PsiSigmoid
2. If you want your new sigmoid to work with mwCore objects, you have to add a label for that, too.
    The mwCore class scales the second parameter such that w can be directly interpreted as the
    width of the region in which the sigmoid still rises significantly. What to "rise significantly"
    means is parameterized by the parameter alpha of the mwCore. The default alpha==0.1 indicates
    that w is the width of the range over which the sigmoid rises from 0.1 to 0.9. Thus, the scaling
    of the second parameter obviously depends on the sigmoid.
    The constructor for the mwCore class looks roughly like this::

        mwCore::mwCore ( int sigmoid, double al )
                : sigmtype(sigmoid), alpha(al), zshift(0) {
            switch (sigmoid) {
            case 1:
                ...
                break;
            /////////////// here ////////////////
            default:
                throw NotImplementedError();
            }
        }

    At the position marked by::

        /////////////// here ////////////////

    in the above code example, you should add a new case that defines all the scaling parameters
    depending on your sigmoid. zalpha scales w to the correct range, zshift is an additional
    shift to ensure the the sigmoid has an output value of 0.5 at an input value of 0.

Adding a new source file
........................

When adding a new C++ source or header file you will have to:

* add the file to the git repository
* add the filename to the Makefile
* add the filename to the Python setup file