Skip to content

Commit

Permalink
Update docs on developer's guide (#121)
Browse files Browse the repository at this point in the history
Add some explanation about the PySwarms API and on how to use
the backend module.

Signed-off-by: Lester James V. Miranda <[email protected]>
  • Loading branch information
ljvmiranda921 committed Jun 14, 2018
1 parent e1a218d commit 9faa3de
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 21 deletions.
Binary file added docs/assets/optimization_loop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
108 changes: 108 additions & 0 deletions docs/assets/optimization_loop.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
% ==================================================
% Optimization Loop
% Author: Lester James V. Miranda
% ==================================================

\documentclass[preview, convert={outfile=\jobname.png, density=300}]{standalone}

\usepackage[usenames, dvipsnames]{xcolor}
\usepackage{tikz}
\usepackage{tikz-uml}

\renewcommand\familydefault{\sfdefault}

\usetikzlibrary{
shapes,
arrows,
positioning,
fit,
calc,
backgrounds,
shadows.blur,
}

% Define some colors
\definecolor{gold}{RGB}{255,215,0}
\definecolor{pyblue}{RGB}{7,78,104}

% taken from manual
\makeatletter
\pgfdeclareshape{document}{
\inheritsavedanchors[from=rectangle] % this is nearly a rectangle
\inheritanchorborder[from=rectangle]
\inheritanchor[from=rectangle]{center}
\inheritanchor[from=rectangle]{north}
\inheritanchor[from=rectangle]{south}
\inheritanchor[from=rectangle]{west}
\inheritanchor[from=rectangle]{east}
% ... and possibly more
\backgroundpath{% this is new
% store lower right in xa/ya and upper right in xb/yb
\southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
\northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
% compute corner of ‘‘flipped page’’
\pgf@xc=\pgf@xb \advance\pgf@xc by-10pt % this should be a parameter
\pgf@yc=\pgf@yb \advance\pgf@yc by-10pt
% construct main path
\pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
\pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
\pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yb}}
\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yc}}
\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
\pgfpathclose
% add little corner
\pgfpathmoveto{\pgfpoint{\pgf@xc}{\pgf@yb}}
\pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}}
\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yc}}
\pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}}
}
}
\makeatother

\begin{document}
\tikzumlset{fill class=gold}
\begin{tikzpicture}[
textbox/.style={fill=none, align=left, minimum height=0.7cm, minimum width=0.7cm,
text width=5.0cm, text=black},
loop/.style={draw, shape=document, color=black!30!green, fill=green!30,
minimum width=5cm, minimum height=3.5cm, text=black, blur shadow={shadow blur steps=5, text width=6.5cm}},
bigLoop/.style={draw, rounded corners=3pt, dashed, color=pyblue, inner xsep=5mm, inner ysep=5mm}
]

\node[loop, label={[name=l]Custom Swarm Algorithm}] (OptimizationLoop) at (0,0) {
Contains your own PSO implementation. This interacts with the
Swarm, Topology, and (optional) \texttt{pyswarms.backend} modules.
};

\umlclass[left=2cm of OptimizationLoop]{Swarm}{
+ position : numpy.ndarray\\
+ velocity : numpy.ndarray\\
+ options : dict
}{}

\umlclass[below=2cm of OptimizationLoop]{Topology}{
}{
+ compute\_gbest()\\
+ compute\_position()\\
+ compute\_velocity()\\
}

\draw[->, thick, transform canvas={yshift=1em}] (Swarm) -- (OptimizationLoop)
node[pos=0.5,above,yshift=0.45cm, text width=3cm, align=center] {Swarm\\attributes};

\draw[->, thick, dashed, transform canvas={yshift=-1em}] (OptimizationLoop) -- (Swarm)
node[pos=0.5,below,yshift=-0.45cm, text width=3cm, align=center] {Updated\\attributes};

\draw[->, thick] (Topology) -- (OptimizationLoop)
node[pos=0.5,right, text width=3cm, align=left] {Swarm\\ operations};

\begin{scope}[on background layer]
\node [fit=(OptimizationLoop) (Swarm) (l), bigLoop, label={[align=center]Optimization Loop}] (bigLoopy) {};
\end{scope}

\node[textbox] at ([yshift=-0.5cm, xshift=2.8cm]bigLoopy.north west) {
\texttt{for i in range(iterations)}
};
\end{tikzpicture}
\end{document}

32 changes: 32 additions & 0 deletions docs/dev.api.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
===============================
Understanding the PySwarms API
===============================

There are three main layers in PySwarms' main API:

* **Optimizers**: includes all off-the-shelf implementations of most swarm intelligence algorithms
* **Base**: base API where most Optimizer implementations were based upon. Each Base module is designed with respect to the problem domain they're trying to solve: single-continuous, discrete, *(in the future)* multiobjective, constrained, etc.
* **Backend**: backend API that exposes common operations for any swarm algorithm such as swarm initialization, global best computation, nearest neighbor search, etc.

You can find the structure of the main PySwarms API in the figure below:

.. image:: assets/pyswarms_api.png
:align: center
:alt: PySwarms API

When contributing to PySwarms, you can start off with any of the Layers
specified above. Right now, we would really appreciate contributions from the
Base Layer below. Some of which that need some dedicated contributions:

* ConstrainedOptimizer (in Base Layer)
* MultiObjectiveOptimizer (in Base Layer)
* Different Topologies (in Backend Layer)

If we can have a strong set of native APIs for the low-level layers, it will
then be very easy to implement different swarm algorithms. Of course, for
your personal needs, you can simply inherit any of the classes in PySwarms
and modify them according to your own specifications.

Remember, when you want to implement your own Optimizer, there is no need
to go from Backend to Optimizers layer. Instead, you can just import the
:class:`pyswarms.backend.swarms.Swarm` class and the classes in the :mod:`pyswarms.backend.topology` module.
58 changes: 58 additions & 0 deletions docs/dev.loop.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
==================================
Writing your own optimization loop
==================================

The backend module provides a lot of helper methods for you
to customize your swarm implementation. This gives you a black-box
approach by requiring you to write your own optimization-loop.

There are two important components for any swarm implementation:

* The **Swarm** class, containing all important attributes and properties of the swarm; and
* The **Topology** class, governing how the swarm will behave during optimization.

.. image:: assets/optimization_loop.png
:align: center
:alt: Writing your own optimization loop

The main idea is that for every iteration, you interact with the Swarm class
using the methods found in the Topology class (or optionally, in
:mod:`pyswarms.backend.operators`). You continuously take the attributes
present in Swarm, and update them using the operations your algorithm
requires. Together with some methods found in
:mod:`pyswarms.backend.generators` and :mod:`pyswarms.backend.operators`, it
is possible to create different kinds of swarm implementations.

The Swarm Class
----------------

:class:`pyswarms.backend.swarms.Swarm` acts as a data-class that keeps all
necessary attributes in a given swarm implementation. You initialize it by
providing the initial position and velocity matrices. For the current
iteration, you can obtain the following information from the class:

* :code:`position`: the current position-matrix of the swarm. Each row is a particle and each column is its position on a given dimension.
* :code:`velocity`: the current velocity-matrix of the swarm. Each row is a particle and each column is its velocity on a given dimension.
* :code:`pbest_pos`: the personal best position of each particle that corresponds to the personal best cost.
* :code:`pbest_cost`: the personal best fitness attained by the particle since the first iteration.
* :code:`best_pos`: the best position found by the swarm that corresponds to the best cost.
* :code:`best_cost`: the best fitness found by the swarm.
* :code:`options`: additional options that you can use for your particular needs. As an example, the :code:`GlobalBestPSO` implementation uses this to store the cognitive and social parameters of the swarm.

The Topology Class
-------------------

:mod:`pyswarms.backend.base.topology` houses all operations that you can use
on the Swarm attributes. Currently, the Star and Ring topologies are
implemented, but more topologies will still be done in the future. A Topology
implements three methods governing swarm behavior:

* :code:`compute_gbest`: computes the best particle (both cost and position) given a swarm instance.
* :code:`compute_position`: computes the next position of the swarm given its current position.
* :code:`compute_velocity`: computes the velocity of the swarm given its attributes.

Needless to say, these three methods will differ depending on the topology
present. All these methods take in an instance of the :code:`Swarm` class,
and outputs the necessary matrices. The advantage of using this class is that
it abstracts away all the internals of implementing a swarm algorithm. You
just need to provide the topology, and call its methods right away.
45 changes: 25 additions & 20 deletions docs/contributing.optimizer.rst → docs/dev.optimizer.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
===============================
Implementing your own optimizer
Contributing your own optimizer
===============================

PySwarms aims to be the go-to library for various PSO implementations, so if you
Expand Down Expand Up @@ -37,7 +37,7 @@ continuous optimization algorithms such as global-best PSO (:mod:`pyswarms.singl
local-best PSO (:mod:`pyswarms.single.local_best`), we can see that it inherits a set of methods as
seen below:

.. image:: inheritance.png
.. image:: assets/inheritance.png
:align: center
:alt: Inheritance from base class

Expand All @@ -48,28 +48,32 @@ optimizer.
A short note on keyword arguments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The role of keyword arguments, or kwargs in short, is to act as a container for all other parameters
needed for the optimizer. You can define these things in your code, and create assertions to make all
of them required. However, note that in some implementations, required :code:`options` might include
:code:`c1`, :code:`c2`, and :code:`w`. This is the case in :mod:`pyswarms.base.bases` for instance.
The role of keyword arguments, or kwargs in short, is to act as a container
for all other parameters needed for the optimizer. You can define these
things in your code, and create assertions to make all of them required.
However, note that in some implementations, required :code:`options` might
include :code:`c1`, :code:`c2`, and :code:`w`. This is the case in
:mod:`pyswarms.base.bases` for instance.

A short note on :code:`assertions()`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You might notice that in most base classes, an :code:`assertions()` method is being called. This aims
to check if the user-facing input are correct. Although the method is called "assertions", please make
all user-facing catches as raised Exceptions.
You might notice that in most base classes, an :code:`assertions()` method is
being called. This aims to check if the user-facing input are correct.
Although the method is called "assertions", please make all user-facing
catches as raised Exceptions.

A short note on :code:`__init__.py`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

We make sure that everything can be imported when the whole :code:`pyswarms` library is called. Thus,
please make sure to also edit the accompanying :code:`__init__.py` file in the directory you are working
on.
We make sure that everything can be imported when the whole :code:`pyswarms`
library is called. Thus, please make sure to also edit the accompanying
:code:`__init__.py` file in the directory you are working on.

For example, if you write your optimizer class :code:`MyOptimizer` inside a file called :code:`my_optimizer.py`,
and you are working under the :code:`/single` directory, please update the :code:`__init__.py` like
the following:
For example, if you write your optimizer class :code:`MyOptimizer` inside a
file called :code:`my_optimizer.py`, and you are working under the
:code:`/single` directory, please update the :code:`__init__.py` like the
following:

.. code-block:: python
Expand All @@ -90,10 +94,11 @@ This ensures that it will be automatically initialized when the whole library is
Writing unit tests
------------------

Testing is an important element of developing PySwarms, and we wanted everything to be as smooth as
possible, especially when doing the build and integrating. In this case, we provide the :code:`tests`
module in the package. In case you add a test for your optimizer, simply name them with the same
convention as in those tests.
Testing is an important element of developing PySwarms, and we wanted
everything to be as smooth as possible, especially when doing the build and
integrating. In this case, we provide the :code:`tests` module in the
package. In case you add a test for your optimizer, simply name them with the
same convention as in those tests.

You can perform separate checks by

Expand Down
4 changes: 3 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ Launching pad
:caption: Developer's Guide

contributing
contributing.optimizer
dev.api
dev.loop
dev.optimizer

.. toctree::
:caption: API Documentation
Expand Down

0 comments on commit 9faa3de

Please sign in to comment.