Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DEV: Add "Particle Swarm Optimization" algorithm to SciPy.optimization #12821

Closed
wants to merge 2 commits into from
Closed

DEV: Add "Particle Swarm Optimization" algorithm to SciPy.optimization #12821

wants to merge 2 commits into from

Conversation

damarro3
Copy link

@damarro3 damarro3 commented Sep 5, 2020

What does this implement/fix?

Added a new optimization algorithm and some tests to ensure

the correct behaviour of the code.

Additional information

Also the init.py file of
SciPy.optimization has been modified to include this new
feature.

Added a new optimization algorithm and some tests to ensure
the correct behaviour of the code. Also the __init__.py file of
SciPy.optimization has been modified to include this new
feature.
@rgommers rgommers added scipy.optimize enhancement A new feature or improvement labels Sep 5, 2020
@mdhaber
Copy link
Contributor

mdhaber commented Sep 5, 2020

@damarro3 thanks for your interest in contributing. I might not be able to review this, but one thing that would help us decide whether to include it would be to compare this against existing global optimizers. Can you add it to the benchmarks, run them, and share the results?

Please add the function name to the list of global optimizers in __init__.py (near line 98) so that the documentation will render:

Global optimization
-------------------
.. autosummary::
   :toctree: generated/
   basinhopping - Basinhopping stochastic optimizer.
   brute - Brute force searching optimizer.
   differential_evolution - stochastic minimization using differential evolution.
   shgo - simplicial homology global optimisation
   dual_annealing - Dual annealing stochastic optimizer.

You can check to see that it renders properly by clicking "Details" of the ci/circleci: build_docs_artifact link.

image

@rgommers
Copy link
Member

rgommers commented Sep 5, 2020

Hi @damarro3, thanks for opening this PR!

Adding a particle swarm optimization was discussed a few months back on the mailing list, with mildly positive feedback: https://mail.python.org/pipermail/scipy-dev/2020-May/024173.html. Note that there's a detailed reply from @andyfaff to that first message with steps to take for adding a new optimization method. In particular, adding it to the benchmarks and showing that the performance (in terms of number of problems it solves and amount of function evaluations) is competitive.

There was also an unanswered question from me about a comparison to PyGMO.

@damarro3
Copy link
Author

damarro3 commented Sep 5, 2020

Thank you @mdhaber and @rgommers, I didn't know about those specific benchmarks. I will implement them and get the results to check if the algorithm is competitive.

Regarding to the PyGMO comparison, I thought about adding this method because is quite used in literature and not everybody install new packages in order to use a general "black box" optimization method.

@andyfaff
Copy link
Contributor

andyfaff commented Sep 7, 2020

@damarro3, the email topic pointed to by Ralf, is the sequence of steps that we should follow before anything is added. In future, it's best to bring up proposed changes on the scipy-dev mailing list first, before any significant amount of code is written.
For this PR to go any further can you run this code against the global benchmark suite (at least 100 reps) so that we can judge its performance. A solver worth adding will need to have a high percentage of successful minimisations across most of the target problems. Once we know solver performance then code development/review can start

@andyfaff
Copy link
Contributor

andyfaff commented Sep 7, 2020

From my experience adding the differential_evolution function the code review process can seem lengthy and very detailed (even nit-picky). However, the large amount of effort it requires to get a new piece of functionality into the package is rewarded in much lower maintenance costs in the long run, and a greater uptake by users.

Copy link
Contributor

@andyfaff andyfaff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just glanced at a few things, so it's not a comprehensive review. Before you go any further can you set it up to run against the global optimization benchmarks? New global optimizers need to be run against the benchmark suite to show that they offer a performance advantage to the existing minimizer functions in order for them to be merged.
i.e. a greater rate of success, or smaller amount of function evaluations (for a reasonable success), etc.

Initial bounds for variables, inside the global search bounds. If it is
not specified, the initial bounds are settle as the global bounds.
Initial bounds for variables, inside the global search bounds. If it is
not specified, the initial bounds are settle as the global bounds.
There are two ways to specify the initial bounds:
1. Instance of `Bounds` class.
2. ``(min, max)`` pairs for each element in ``x``, defining the finite
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would only accept the Bounds class for this, it's a more modern way of doing things.

self.bestof = bestof
self.func = func

def updatevel(self, w, c1, c2, bestgpos, vmin, vmax):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update_vel

self.velocity = np.maximum(self.velocity, vmin)
self.velocity = np.minimum(self.velocity, vmax)

def updatepos(self, pmin, pmax):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update_pos


pos_value = self.func(self.position)
if pos_value <= self.bestof:
self.bestof = pos_value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

best_of

pos_value = self.func(self.position)
if pos_value <= self.bestof:
self.bestof = pos_value
self.bestpos = self.position
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

best_pos.
Although if best_pos is actually x, then why not use best_x?


# test w
if self.w <= 0:
if (((self.velocity_strategy == 'constant') or (self.velocity_strategy == 'random'))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.velocity_strategy in ['constant', 'random']:

bestof=self.func(init_position),
func=self.func)

def _update(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be preferable if the object was iterable, implementing __iter__ and __next__.

""" Update of the swarm particles """
for i in range(self.n_particles):
self._particle_update(i)
if self.particles[i].bestof <= self.bestgof:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this parallelisable? If so, then we should use a workers keyword to enable parallelisation (see differential_evolution).

self.bestgpos = self.particles[i].bestpos
self.bestgof = self.particles[i].bestof

self.fevals += self.n_particles
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename variable to nfev.

self.bestgof = self.particles[i].bestof

self.fevals += self.n_particles
self.it += 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename attribute to nit

@damarro3
Copy link
Author

I have executed the benchmarks. As soon as they finish, I will post the results.

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement A new feature or improvement scipy.optimize
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants