From 5cd02ead9aa03b4e53e464f2f1bbcf1e851d0442 Mon Sep 17 00:00:00 2001 From: ljvmiranda921 Date: Sun, 30 Jul 2017 14:45:28 +0900 Subject: [PATCH] Improved documentation (#16) This is a massive documentation update in order to make the ReadTheDocs website as appealing it should be. In summary, the following were undertaken: - Small patch fix for importing modules - Small modification in console_utils for console output - Modified ReadTheDocs' sidebar theme with an overriding css file. - Added a use-case example on Basic Optimization - Updated docstrings for most module implementations to make it look nice in the API documentation. Even though most of these updates occured at different files, they were all done for the sole purpose of improving documentation in ReadTheDocs and introducing an API documentation at the end. Author: ljvmiranda921 --- HISTORY.rst | 2 +- README.rst | 4 +- docs/_static/theme_overrides.css | 17 ++ docs/conf.py | 5 + docs/examples/basic_optimization.rst | 186 +++++++++++++ docs/examples/usecases.rst | 8 + docs/features.rst | 31 +++ docs/index.rst | 32 ++- docs/intro.rst | 77 ++++++ docs/readme.rst | 1 - .../basic_optimization-checkpoint.ipynb | 255 ++++++++++++++++++ examples/basic_optimization.ipynb | 253 +++++++++++++++++ pyswarms/single/gb.py | 4 +- pyswarms/utils/console_utils.py | 16 +- pyswarms/utils/functions/__init__.py | 5 +- 15 files changed, 880 insertions(+), 16 deletions(-) create mode 100644 docs/_static/theme_overrides.css create mode 100644 docs/examples/basic_optimization.rst create mode 100644 docs/examples/usecases.rst create mode 100644 docs/features.rst create mode 100644 docs/intro.rst delete mode 100644 docs/readme.rst create mode 100644 examples/.ipynb_checkpoints/basic_optimization-checkpoint.ipynb create mode 100644 examples/basic_optimization.ipynb diff --git a/HISTORY.rst b/HISTORY.rst index db52d73e..8772f5ae 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -8,7 +8,7 @@ History * First release on PyPI. 0.1.1 (2017-7-25) ------------------- +~~~~~~~~~~~~~~~~~ * Bug fixes * Implemented Local Best PSO diff --git a/README.rst b/README.rst index ef638f02..13b7d651 100644 --- a/README.rst +++ b/README.rst @@ -60,7 +60,7 @@ built-in sphere function, :code:`pyswarms.utils.functions.sphere_func()`, and th .. code-block:: python import pyswarms as ps - from pyswarms.utils.functions import sphere_func + from pyswarms.utils.functions import single_obj as fx # Set-up hyperparameters options = {'c1': 0.5, 'c2': 0.3, 'm':0.9} @@ -69,7 +69,7 @@ built-in sphere function, :code:`pyswarms.utils.functions.sphere_func()`, and th optimizer = ps.single.GBestPSO(n_particles=10, dims=2, **options) # Perform optimization - stats = optimizer.optimize(sphere_func, iters=100) + stats = optimizer.optimize(fx.sphere_func, iters=100) Credits diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css new file mode 100644 index 00000000..0e4da362 --- /dev/null +++ b/docs/_static/theme_overrides.css @@ -0,0 +1,17 @@ +.wy-menu-vertical header, .wy-menu-vertical p.caption { + color: gold; +} + +.wy-menu-vertical a { + color: white; +} + +.wy-side-nav-search +{ + color: #cacaca; + background: #074E68 +} + +.wy-side-nav-search input[type=text] { + border-color: rgba(7, 78, 104, 0.83); +} \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 76bac8a0..3496e8c7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -152,6 +152,11 @@ # "default.css". html_static_path = ['_static'] +def setup(app): + # overrides for wide tables in RTD theme + app.add_stylesheet('theme_overrides.css') # path relative to static + + # If not '', a 'Last updated on:' timestamp is inserted at every page # bottom, using the given strftime format. html_last_updated_fmt = '%b %d, %Y' diff --git a/docs/examples/basic_optimization.rst b/docs/examples/basic_optimization.rst new file mode 100644 index 00000000..7a5e7162 --- /dev/null +++ b/docs/examples/basic_optimization.rst @@ -0,0 +1,186 @@ + +Basic Optimization +================== + +In this example, we'll be performing a simple optimization of +single-objective functions using the global-best optimizer in +``pyswarms.single.GBestPSO`` and the local-best optimizer in +``pyswarms.single.LBestPSO``. This aims to demonstrate the basic +capabilities of the library when applied to benchmark problems. + +.. code:: ipython3 + + import sys + sys.path.append('../') + +.. code-block:: python + + # Import modules + import numpy as np + + # Import PySwarms + import pyswarms as ps + from pyswarms.utils.functions import single_obj as fx + + # Some more magic so that the notebook will reload external python modules; + # see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython + %load_ext autoreload + %autoreload 2 + +Optimizing a function +--------------------- + +First, let's start by optimizing the sphere function. Recall that the +minima of this function can be located at ``f(0,0..,0)`` with a value of +``0``. In case you don't remember the characteristics of a given +function, simply call ``help()``. + +For now let's just set some arbitrary parameters in our optimizers. +There are, at minimum, three steps to perform optimization: + +1. Set the hyperparameters to configure the swarm as a ``dict``. +2. Create an instance of the optimizer by passing the dictionary along + with the necessary arguments. +3. Call the ``optimize()`` method and have it store the optimal cost and + position in a variable. + +The ``optimize()`` method returns a ``tuple`` of values, one of which +includes the optimal cost and position after optimization. You can store +it in a single variable and just index the values, or unpack it using +several variables at once. + +.. code-block:: python + + # Set-up hyperparameters + options = {'c1': 0.5, 'c2': 0.3, 'm':0.9} + + # Call instance of PSO + gbest_pso = ps.single.GBestPSO(n_particles=10, dims=2, **options) + + # Perform optimization + cost, pos = gbest_pso.optimize(fx.sphere_func, print_step=100, iters=1000, verbose=3) + + +.. parsed-literal:: + + Iteration 1/1000, cost: 0.0035824017918 + Iteration 101/1000, cost: 1.02538653288e-08 + Iteration 201/1000, cost: 9.95696087972e-13 + Iteration 301/1000, cost: 8.22034343822e-16 + Iteration 401/1000, cost: 3.7188438887e-19 + Iteration 501/1000, cost: 1.23935292549e-25 + Iteration 601/1000, cost: 6.03016193248e-28 + Iteration 701/1000, cost: 3.70755768681e-34 + Iteration 801/1000, cost: 2.64385328058e-37 + Iteration 901/1000, cost: 1.76488833461e-40 + ================================ + Optimization finished! + Final cost: 0.000 + Best value: [-6.5732265560180066e-24, -7.4004230063696789e-22] + + + +We can see that the optimizer was able to find a good minima as shown +above. You can control the verbosity of the output using the ``verbose`` +argument, and the number of steps to be printed out using the +``print_step`` argument. + +Now, let's try this one using local-best PSO: + +.. code-block:: python + + # Set-up hyperparameters + options = {'c1': 0.5, 'c2': 0.3, 'm':0.9} + + # Call instance of PSO + lbest_pso = ps.single.LBestPSO(n_particles=10, dims=2, k=2,p=2, **options) + + # Perform optimization + cost, pos = lbest_pso.optimize(fx.sphere_func, print_step=100, iters=1000, verbose=3) + + +.. parsed-literal:: + + Iteration 1/1000, cost: 0.190175474818 + Iteration 101/1000, cost: 1.14470953523e-06 + Iteration 201/1000, cost: 6.79485221069e-11 + Iteration 301/1000, cost: 1.00691597113e-14 + Iteration 401/1000, cost: 2.98301783945e-18 + Iteration 501/1000, cost: 2.13856158282e-20 + Iteration 601/1000, cost: 5.49351926815e-25 + Iteration 701/1000, cost: 1.7673389214e-29 + Iteration 801/1000, cost: 1.83082804473e-33 + Iteration 901/1000, cost: 1.75920918448e-36 + ================================ + Optimization finished! + Final cost: 3.000 + Best value: [-8.2344756213578705e-21, -2.6563827831876976e-20] + + + +Optimizing a function with bounds +--------------------------------- + +Another thing that we can do is to set some bounds into our solution, so +as to contain our candidate solutions within a specific range. We can do +this simply by passing a ``bounds`` parameter, of type ``tuple``, when +creating an instance of our swarm. Let's try this using the global-best +PSO with the Rastrigin function (``rastrigin_func`` in +``pyswarms.utils.functions.single_obj``). + +Recall that the Rastrigin function is bounded within ``[-5.12, 5.12]``. +If we pass an unbounded swarm into this function, then a ``ValueError`` +might be raised. So what we'll do is to create a bound within the +specified range. There are some things to remember when specifying a +bound: + +- A bound should be of type tuple with length 2. +- It should contain two ``numpy.ndarrays`` so that we have a + ``(min_bound, max_bound)`` +- Obviously, all values in the ``max_bound`` should always be greater + than the ``min_bound``. Their shapes should match the dimensions of + the swarm. + +What we'll do now is to create a 10-particle, 2-dimensional swarm. This +means that we have to set our maximum and minimum boundaries with the +shape of 2. In case we want to initialize an n-dimensional swarm, we +then have to set our bounds with the same shape n. A fast workaround for +this would be to use the ``numpy.ones`` function multiplied by a +constant. + +.. code-block:: python + + # Create bounds + max_bound = 5.12 * np.ones(2) + min_bound = - max_bound + bounds = (min_bound, max_bound) + +.. code-block:: python + + # Initialize swarm + options = {'c1': 0.5, 'c2': 0.3, 'm':0.9} + + # Call instance of PSO with bounds argument + optimizer = ps.single.GBestPSO(n_particles=10, dims=2, bounds=bounds, **options) + + # Perform optimization + cost, pos = optimizer.optimize(fx.rastrigin_func, print_step=100, iters=1000, verbose=3) + + +.. parsed-literal:: + + Iteration 1/1000, cost: 10.3592595923 + Iteration 101/1000, cost: 0.00381030608321 + Iteration 201/1000, cost: 1.31982446305e-07 + Iteration 301/1000, cost: 1.16529008665e-11 + Iteration 401/1000, cost: 0.0 + Iteration 501/1000, cost: 0.0 + Iteration 601/1000, cost: 0.0 + Iteration 701/1000, cost: 0.0 + Iteration 801/1000, cost: 0.0 + Iteration 901/1000, cost: 0.0 + ================================ + Optimization finished! + Final cost: 0.000 + Best value: [8.9869507154871327e-10, -2.7262405947023504e-09] + diff --git a/docs/examples/usecases.rst b/docs/examples/usecases.rst new file mode 100644 index 00000000..02ceb90f --- /dev/null +++ b/docs/examples/usecases.rst @@ -0,0 +1,8 @@ +Use-case examples +================= +Below are some of the applications where PySwarms can be used. +If you wish to check the actual Jupyter Notebooks, please go to this `link `_ + +.. toctree:: + + basic_optimization \ No newline at end of file diff --git a/docs/features.rst b/docs/features.rst new file mode 100644 index 00000000..b80ec53b --- /dev/null +++ b/docs/features.rst @@ -0,0 +1,31 @@ +======== +Features +======== + + + +Single-Objective Optimizers +--------------------------- + +These are standard optimization techniques that aims to find the optima of a single objective function. + +Continuous +~~~~~~~~~~ + +Single-objective optimization where the search space is continuous. + +* :mod:`pyswarms.single.gb` - global-best Particle Swarm Optimization algorithm with a star-topology. Every particle compares itself with the best-performing particle in the swarm. + +* :mod:`pyswarms.single.lb` - local-best Particle Swarm Optimization algorithm with a ring-topology. Every particle compares itself only with its nearest-neighbours as computed by a distance metric. + + +Utilities +--------- + +Test Functions +~~~~~~~~~~~~~~ + +These functions can be used as benchmark tests for assessing the performance of the optimization +algorithm. + +* :mod:`pyswarms.utils.functions.single_obj` - single-objective test functions diff --git a/docs/index.rst b/docs/index.rst index 316affd1..90ca22ac 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,13 +1,41 @@ Welcome to PySwarms's documentation! ====================================== -Contents: +.. image:: https://img.shields.io/pypi/v/pyswarms.svg + :target: https://pypi.python.org/pypi/pyswarms + +.. image:: https://img.shields.io/travis/ljvmiranda921/pyswarms.svg + :target: https://travis-ci.org/ljvmiranda921/pyswarms + +.. image:: https://readthedocs.org/projects/pyswarms/badge/?version=latest + :target: https://pyswarms.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +.. image:: https://pyup.io/repos/github/ljvmiranda921/pyswarms/shield.svg + :target: https://pyup.io/repos/github/ljvmiranda921/pyswarms/ + :alt: Updates + +PySwarms is a simple, Python-based, Particle Swarm Optimization (PSO) library. + +* Free software: MIT license +* Github repository: https://github.com/ljvmiranda921/pyswarms + +Launching pad +------------- + +* If you don't know what Particle Swarm Optimization is, read up this short `Introduction `_! Then, if you plan to use PySwarms in your project, check the `Installation guide `_ and the `use-case examples `_ in this documentation. + +* If you are a researcher in the field of swarm intelligence, and would like to include your technique in our list of optimizers, check our `contributing `_ page to see how to implement your optimizer using the current base classes in the library. + +* If you are an open-source contributor, and would like to help PySwarms grow, be sure to check our `Issues `_ page in Github, and see the open issues with the tag `help-wanted `_. Moreover, we accommodate contributions from first-time contributors! Just check our `first-timers-only `_ tag for open issues (Don't worry! We're happy to help you make your first PR!). + .. toctree:: :maxdepth: 2 :caption: General - readme + intro + features installation authors history diff --git a/docs/intro.rst b/docs/intro.rst new file mode 100644 index 00000000..c4fdd19a --- /dev/null +++ b/docs/intro.rst @@ -0,0 +1,77 @@ +============ +Introduction +============ + +It's all a treasure hunt +------------------------- + +Imagine that you and your friends are looking for a treasure together. +The treasure is magical, and it rewards not only the one who finds it, +but also others based on their proximity. Your group knows, +approximately, where the treasure is, but not exactly sure of its definite +location. + +Your group then decided to split up and all of you received +walkie-talkies and metal detectors. The purpose of the walkie-talkie is +to inform everyone of your current position, while the metal detectors +indicate if you are near the treasure. In return, you gain knowledge of +the location of your friends, and also their proximity to the treasure. + +As a member of the group, you have two options: + +* Ignore your friends, and just search for the treasure the way you want it. Problem is, if you didn't find it, and you're far away from it, you get a very low reward. + +* Using the information you gather from your group, coordinate and find the treasure together. The best way is to know who is the one nearest to the treasure, and move towards that person. + +Here, it is evident that by using the information you can gather from +your friends, you can increase the chances of finding the treasure, and +at the same time maximize the group's reward. This is the basics of +Particle Swarm Optimization (PSO). The group is called the *swarm*, +you are a *particle*, and the treasure is the *global optimum* [CI2007]_. + + +Particle Swarm Optimization (PSO) +--------------------------------- + +As with the treasure example, the idea of PSO is to emulate the social +behaviour of birds and fishes by initializing a set of candidate solutions +to search for an optima. Particles are scattered around the search-space, +and moves around it to find the position of the optimal solution. Each +particle represents a candidate solution, and their movements are +affected in a two-fold manner: (1) their cognitive desire to search +individually, (2) and the collective action of the group or its +neighbors. It is a fairly simple concept with profound applications. + +One interesting characteristic of PSO is that it does not use the gradient +of the function, thus, objective functions need not to be differentiable. +Moreover, the basic PSO is astonishingly simple. And adding variants to +the original implementation can help it adapt to more complicated problems. + +The original PSO algorithm is attributed to Eberhart, +Kennedy, and Shi [IJCNN1995]_ [ICEC2008]_. Nowadays, a lot of variations +in topology, search-space characteristic, constraints, objectives, +are being researched upon to solve a variety of problems. + + +Why make PySwarms? +------------------ + +In one of my graduate courses during Masters, my professor asked us to +implement PSO for training a neural network. It was, in all honesty, my +first experience of implementing an algorithm from concept to code. I +found the concept of PSO very endearing, primarily because it gives +us an insight on the advantage of collaboration given a social situation. + +When I revisited my course project, I realized that PSO, given enough +variations, can be used to solve a lot of problems: from simple optimization, +to robotics, and to job-shop scheduling. I then decided to build a +research toolkit that can be extended by the community (us!) and be used +by anyone. + +.. rubric:: References + +.. [CI2007] A. Engelbrecht, "An Introduction to Computational Intelligence," John Wiley & Sons, 2007. + +.. [IJCNN1995] J. Kennedy and R.C. Eberhart, "Particle Swarm Optimization," Proceedings of the IEEE International Joint Conference on Neural Networks, 1995, pp. 1942-1948. + +.. [ICEC2008] Y. Shi and R.C. Eberhart, "A modified particle swarm optimizer," Proceedings of the IEEE International Conference on Evolutionary Computation, 1998, pp. 69-73. \ No newline at end of file diff --git a/docs/readme.rst b/docs/readme.rst deleted file mode 100644 index 72a33558..00000000 --- a/docs/readme.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../README.rst diff --git a/examples/.ipynb_checkpoints/basic_optimization-checkpoint.ipynb b/examples/.ipynb_checkpoints/basic_optimization-checkpoint.ipynb new file mode 100644 index 00000000..9af97af2 --- /dev/null +++ b/examples/.ipynb_checkpoints/basic_optimization-checkpoint.ipynb @@ -0,0 +1,255 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Basic Optimization\n", + "In this example, we'll be performing a simple optimization of single-objective functions using the global-best optimizer in `pyswarms.single.GBestPSO` and the local-best optimizer in `pyswarms.single.LBestPSO`. This aims to demonstrate the basic capabilities of the library when applied to benchmark problems." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.append('../')" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Import modules\n", + "import numpy as np\n", + "\n", + "# Import PySwarms\n", + "import pyswarms as ps\n", + "from pyswarms.utils.functions import single_obj as fx\n", + "\n", + "# Some more magic so that the notebook will reload external python modules;\n", + "# see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimizing a function\n", + "First, let's start by optimizing the sphere function. Recall that the minima of this function can be located at `f(0,0..,0)` with a value of `0`. In case you don't remember the characteristics of a given function, simply call `help()`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For now let's just set some arbitrary parameters in our optimizers. There are, at minimum, three steps to perform optimization:\n", + "\n", + "1. Set the hyperparameters to configure the swarm as a `dict`.\n", + "2. Create an instance of the optimizer by passing the dictionary along with the necessary arguments.\n", + "3. Call the `optimize()` method and have it store the optimal cost and position in a variable.\n", + "\n", + "The `optimize()` method returns a `tuple` of values, one of which includes the optimal cost and position after optimization. You can store it in a single variable and just index the values, or unpack it using several variables at once." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration 1/1000, cost: 0.241810034912\n", + "Iteration 101/1000, cost: 1.24792343462e-07\n", + "Iteration 201/1000, cost: 3.37290413126e-11\n", + "Iteration 301/1000, cost: 1.69154015e-16\n", + "Iteration 401/1000, cost: 7.45197149386e-20\n", + "Iteration 501/1000, cost: 3.10721498746e-24\n", + "Iteration 601/1000, cost: 1.88640993989e-30\n", + "Iteration 701/1000, cost: 8.54586648864e-34\n", + "Iteration 801/1000, cost: 5.35080705362e-35\n", + "Iteration 901/1000, cost: 2.8556550659e-37\n", + "================================\n", + "Optimization finished!\n", + "Final cost: 0.000\n", + "Best value: [1.1619287820351099e-23, -9.6008484982928834e-23]\n", + "\n" + ] + } + ], + "source": [ + "# Set-up hyperparameters\n", + "options = {'c1': 0.5, 'c2': 0.3, 'm':0.9}\n", + "\n", + "# Call instance of PSO\n", + "gbest_pso = ps.single.GBestPSO(n_particles=10, dims=2, **options)\n", + "\n", + "# Perform optimization\n", + "cost, pos = gbest_pso.optimize(fx.sphere_func, print_step=100, iters=1000, verbose=3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that the optimizer was able to find a good minima as shown above. You can control the verbosity of the output using the `verbose` argument, and the number of steps to be printed out using the `print_step` argument." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's try this one using local-best PSO:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration 1/1000, cost: 0.04003185568\n", + "Iteration 101/1000, cost: 6.3794607757e-06\n", + "Iteration 201/1000, cost: 7.09436163329e-12\n", + "Iteration 301/1000, cost: 1.5461139723e-15\n", + "Iteration 401/1000, cost: 1.19646365726e-16\n", + "Iteration 501/1000, cost: 1.69249151459e-19\n", + "Iteration 601/1000, cost: 4.50338461028e-25\n", + "Iteration 701/1000, cost: 5.19268925253e-28\n", + "Iteration 801/1000, cost: 1.56302357735e-30\n", + "Iteration 901/1000, cost: 9.65270491034e-36\n", + "================================\n", + "Optimization finished!\n", + "Final cost: 0.000\n", + "Best value: [1.083763152840743e-19, 1.1881341950447718e-19]\n", + "\n" + ] + } + ], + "source": [ + "# Set-up hyperparameters\n", + "options = {'c1': 0.5, 'c2': 0.3, 'm':0.9}\n", + "\n", + "# Call instance of PSO\n", + "lbest_pso = ps.single.LBestPSO(n_particles=10, dims=2, k=2,p=2, **options)\n", + "\n", + "# Perform optimization\n", + "cost, pos = lbest_pso.optimize(fx.sphere_func, print_step=100, iters=1000, verbose=3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimizing a function with bounds\n", + "Another thing that we can do is to set some bounds into our solution, so as to contain our candidate solutions within a specific range. We can do this simply by passing a `bounds` parameter, of type `tuple`, when creating an instance of our swarm. Let's try this using the global-best PSO with the Rastrigin function (`rastrigin_func` in `pyswarms.utils.functions.single_obj`)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Recall that the Rastrigin function is bounded within `[-5.12, 5.12]`. If we pass an unbounded swarm into this function, then a `ValueError` might be raised. So what we'll do is to create a bound within the specified range. There are some things to remember when specifying a bound:\n", + "\n", + "* A bound should be of type tuple with length 2. \n", + "* It should contain two `numpy.ndarrays` so that we have a `(min_bound, max_bound)`\n", + "* Obviously, all values in the `max_bound` should always be greater than the `min_bound`. Their shapes should match the dimensions of the swarm." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What we'll do now is to create a 10-particle, 2-dimensional swarm. This means that we have to set our maximum and minimum boundaries with the shape of 2. In case we want to initialize an n-dimensional swarm, we then have to set our bounds with the same shape n. A fast workaround for this would be to use the `numpy.ones` function multiplied by a constant." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on function rastrigin_func in module pyswarms.utils.functions.single_obj:\n", + "\n", + "rastrigin_func(x)\n", + " Rastrigin objective function.\n", + " \n", + " Has a global minimum at :code:`f(0,0,...,0)` with a search\n", + " domain of :code:`[-5.12, 5.12]`\n", + " \n", + " Parameters\n", + " ----------\n", + " x : numpy.ndarray \n", + " set of inputs of shape :code:`(n_particles, dims)`\n", + " \n", + " Returns\n", + " -------\n", + " numpy.ndarray \n", + " computed cost of size :code:`(n_particles, )`\n", + " \n", + " Raises\n", + " ------\n", + " ValueError\n", + " When the input is out of bounds with respect to the function\n", + " domain\n", + "\n" + ] + } + ], + "source": [ + "# Create bounds\n", + "max_bound = 5.12 * np.ones(2)\n", + "min_bound = - max_bound\n", + "bounds = tuple(max_bound, min_bound)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/basic_optimization.ipynb b/examples/basic_optimization.ipynb new file mode 100644 index 00000000..5ae263e9 --- /dev/null +++ b/examples/basic_optimization.ipynb @@ -0,0 +1,253 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Basic Optimization\n", + "In this example, we'll be performing a simple optimization of single-objective functions using the global-best optimizer in `pyswarms.single.GBestPSO` and the local-best optimizer in `pyswarms.single.LBestPSO`. This aims to demonstrate the basic capabilities of the library when applied to benchmark problems." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.append('../')" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Import modules\n", + "import numpy as np\n", + "\n", + "# Import PySwarms\n", + "import pyswarms as ps\n", + "from pyswarms.utils.functions import single_obj as fx\n", + "\n", + "# Some more magic so that the notebook will reload external python modules;\n", + "# see http://stackoverflow.com/questions/1907993/autoreload-of-modules-in-ipython\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimizing a function\n", + "First, let's start by optimizing the sphere function. Recall that the minima of this function can be located at `f(0,0..,0)` with a value of `0`. In case you don't remember the characteristics of a given function, simply call `help()`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For now let's just set some arbitrary parameters in our optimizers. There are, at minimum, three steps to perform optimization:\n", + "\n", + "1. Set the hyperparameters to configure the swarm as a `dict`.\n", + "2. Create an instance of the optimizer by passing the dictionary along with the necessary arguments.\n", + "3. Call the `optimize()` method and have it store the optimal cost and position in a variable.\n", + "\n", + "The `optimize()` method returns a `tuple` of values, one of which includes the optimal cost and position after optimization. You can store it in a single variable and just index the values, or unpack it using several variables at once." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration 1/1000, cost: 0.0035824017918\n", + "Iteration 101/1000, cost: 1.02538653288e-08\n", + "Iteration 201/1000, cost: 9.95696087972e-13\n", + "Iteration 301/1000, cost: 8.22034343822e-16\n", + "Iteration 401/1000, cost: 3.7188438887e-19\n", + "Iteration 501/1000, cost: 1.23935292549e-25\n", + "Iteration 601/1000, cost: 6.03016193248e-28\n", + "Iteration 701/1000, cost: 3.70755768681e-34\n", + "Iteration 801/1000, cost: 2.64385328058e-37\n", + "Iteration 901/1000, cost: 1.76488833461e-40\n", + "================================\n", + "Optimization finished!\n", + "Final cost: 0.000\n", + "Best value: [-6.5732265560180066e-24, -7.4004230063696789e-22]\n", + "\n" + ] + } + ], + "source": [ + "# Set-up hyperparameters\n", + "options = {'c1': 0.5, 'c2': 0.3, 'm':0.9}\n", + "\n", + "# Call instance of PSO\n", + "gbest_pso = ps.single.GBestPSO(n_particles=10, dims=2, **options)\n", + "\n", + "# Perform optimization\n", + "cost, pos = gbest_pso.optimize(fx.sphere_func, print_step=100, iters=1000, verbose=3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that the optimizer was able to find a good minima as shown above. You can control the verbosity of the output using the `verbose` argument, and the number of steps to be printed out using the `print_step` argument." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's try this one using local-best PSO:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration 1/1000, cost: 0.190175474818\n", + "Iteration 101/1000, cost: 1.14470953523e-06\n", + "Iteration 201/1000, cost: 6.79485221069e-11\n", + "Iteration 301/1000, cost: 1.00691597113e-14\n", + "Iteration 401/1000, cost: 2.98301783945e-18\n", + "Iteration 501/1000, cost: 2.13856158282e-20\n", + "Iteration 601/1000, cost: 5.49351926815e-25\n", + "Iteration 701/1000, cost: 1.7673389214e-29\n", + "Iteration 801/1000, cost: 1.83082804473e-33\n", + "Iteration 901/1000, cost: 1.75920918448e-36\n", + "================================\n", + "Optimization finished!\n", + "Final cost: 3.000\n", + "Best value: [-8.2344756213578705e-21, -2.6563827831876976e-20]\n", + "\n" + ] + } + ], + "source": [ + "# Set-up hyperparameters\n", + "options = {'c1': 0.5, 'c2': 0.3, 'm':0.9}\n", + "\n", + "# Call instance of PSO\n", + "lbest_pso = ps.single.LBestPSO(n_particles=10, dims=2, k=2,p=2, **options)\n", + "\n", + "# Perform optimization\n", + "cost, pos = lbest_pso.optimize(fx.sphere_func, print_step=100, iters=1000, verbose=3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Optimizing a function with bounds\n", + "Another thing that we can do is to set some bounds into our solution, so as to contain our candidate solutions within a specific range. We can do this simply by passing a `bounds` parameter, of type `tuple`, when creating an instance of our swarm. Let's try this using the global-best PSO with the Rastrigin function (`rastrigin_func` in `pyswarms.utils.functions.single_obj`)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Recall that the Rastrigin function is bounded within `[-5.12, 5.12]`. If we pass an unbounded swarm into this function, then a `ValueError` might be raised. So what we'll do is to create a bound within the specified range. There are some things to remember when specifying a bound:\n", + "\n", + "* A bound should be of type tuple with length 2. \n", + "* It should contain two `numpy.ndarrays` so that we have a `(min_bound, max_bound)`\n", + "* Obviously, all values in the `max_bound` should always be greater than the `min_bound`. Their shapes should match the dimensions of the swarm." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What we'll do now is to create a 10-particle, 2-dimensional swarm. This means that we have to set our maximum and minimum boundaries with the shape of 2. In case we want to initialize an n-dimensional swarm, we then have to set our bounds with the same shape n. A fast workaround for this would be to use the `numpy.ones` function multiplied by a constant." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# Create bounds\n", + "max_bound = 5.12 * np.ones(2)\n", + "min_bound = - max_bound\n", + "bounds = (min_bound, max_bound)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Iteration 1/1000, cost: 10.3592595923\n", + "Iteration 101/1000, cost: 0.00381030608321\n", + "Iteration 201/1000, cost: 1.31982446305e-07\n", + "Iteration 301/1000, cost: 1.16529008665e-11\n", + "Iteration 401/1000, cost: 0.0\n", + "Iteration 501/1000, cost: 0.0\n", + "Iteration 601/1000, cost: 0.0\n", + "Iteration 701/1000, cost: 0.0\n", + "Iteration 801/1000, cost: 0.0\n", + "Iteration 901/1000, cost: 0.0\n", + "================================\n", + "Optimization finished!\n", + "Final cost: 0.000\n", + "Best value: [8.9869507154871327e-10, -2.7262405947023504e-09]\n", + "\n" + ] + } + ], + "source": [ + "# Initialize swarm\n", + "options = {'c1': 0.5, 'c2': 0.3, 'm':0.9}\n", + "\n", + "# Call instance of PSO with bounds argument\n", + "optimizer = ps.single.GBestPSO(n_particles=10, dims=2, bounds=bounds, **options)\n", + "\n", + "# Perform optimization\n", + "cost, pos = optimizer.optimize(fx.rastrigin_func, print_step=100, iters=1000, verbose=3)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/pyswarms/single/gb.py b/pyswarms/single/gb.py index 887bc50d..e61fc224 100644 --- a/pyswarms/single/gb.py +++ b/pyswarms/single/gb.py @@ -34,7 +34,7 @@ .. code-block:: python import pyswarms as ps - from pyswarms.utils.functions import sphere_func + from pyswarms.utils.functions import single_obj as fx # Set-up hyperparameters options = {'c1': 0.5, 'c2': 0.3, 'm':0.9} @@ -43,7 +43,7 @@ optimizer = ps.single.GBestPSO(n_particles=10, dims=2, **options) # Perform optimization - stats = optimizer.optimize(sphere_func, iters=100) + stats = optimizer.optimize(fx.sphere_func, iters=100) This algorithm was adapted from the earlier works of J. Kennedy and R.C. Eberhart in Particle Swarm Optimization [IJCNN1995]_. diff --git a/pyswarms/utils/console_utils.py b/pyswarms/utils/console_utils.py index 8c251146..1da4f234 100644 --- a/pyswarms/utils/console_utils.py +++ b/pyswarms/utils/console_utils.py @@ -32,11 +32,17 @@ def end_report(cost, pos, verbosity): best position found verbosity : int verbosity setting of the user. - """ - template = ("================================\n" - "Optimization finished!\n" - "Final cost: %.3f\n" - "Best value: %s\n") % (cost, list(pos)) + + # Cuts the length of the best position if it's too long + if len(list(pos)) > 3: + out = (6 * '{:3f} ' + '...').format(*list(pos)) + else: + out = list(pos) + + template = ('================================\n' + 'Optimization finished!\n' + 'Final cost: {:06.4f}\n' + 'Best value: {}\n').format(cost, out) if verbosity >= 1: print(template) \ No newline at end of file diff --git a/pyswarms/utils/functions/__init__.py b/pyswarms/utils/functions/__init__.py index 8bcd8328..b6fc37fb 100644 --- a/pyswarms/utils/functions/__init__.py +++ b/pyswarms/utils/functions/__init__.py @@ -1,5 +1,4 @@ """ -The `pyswarms.utils.functions` module implements various test functions +The mod:`pyswarms.utils.functions` module implements various test functions for optimization. -""" - +""" \ No newline at end of file