Skip to content

Commit

Permalink
Move functions to topologies
Browse files Browse the repository at this point in the history
In this commit, we move the global best computation to the Topology
classes themselves, but keep the compute_pbest(), compute_position() and
compute_velocity() so that people can reuse it.  The position and
velocity computations are standard implementations, so this is just
imported by the Ring and Star topology classes in their own methods

Signed-off-by: Lester James V. Miranda <ljvmiranda@gmail.com>
  • Loading branch information
ljvmiranda921 committed Jun 6, 2018
1 parent 6e1c430 commit 7010380
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 113 deletions.
97 changes: 3 additions & 94 deletions pyswarms/backend/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@

# Import modules
import numpy as np
from scipy.spatial import cKDTree

# Create a logger
logger = logging.getLogger(__name__)

def update_pbest(swarm):
def compute_pbest(swarm):
"""Takes a swarm instance and updates the personal best scores
You can use this method to update your personal best positions.
Expand Down Expand Up @@ -71,97 +70,7 @@ def update_pbest(swarm):
else:
return (new_pbest_pos, new_pbest_cost)

def update_gbest(swarm):
"""Updates the global best given the cost and the position
This method takes the current pbest_pos and pbest_cost, then returns
the minimum cost and position from the matrix. It should be used in
tandem with an if statement
.. code-block:: python
import pyswarms.backend as P
from pyswarms.backend.swarms import Swarm
my_swarm = P.create_swarm(n_particles, dimensions)
# If the minima of the pbest_cost is less than the best_cost
if np.min(pbest_cost) < best_cost:
# Update best_cost and position
swarm.best_pos, swarm.best_cost = P.update_gbest(my_swarm)
Parameters
----------
swarm : pyswarms.backend.swarm.Swarm
a Swarm instance
Returns
-------
numpy.ndarray
Best position of shape :code:`(n_dimensions, )`
float
Best cost
"""
try:
best_pos = swarm.pbest_pos[np.argmin(swarm.pbest_cost)]
best_cost = np.min(swarm.pbest_cost)
except AttributeError:
msg = 'Please pass a Swarm class. You passed {}'.format(type(swarm))
logger.error(msg)
raise
else:
return (best_pos, best_cost)

def update_gbest_neighborhood(swarm, p, k):
"""Updates the global best using a neighborhood approach
This uses the cKDTree method from :code:`scipy` to obtain the nearest
neighbours
Parameters
----------
swarm : pyswarms.backend.swarms.Swarm
a Swarm instance
k : int
number of neighbors to be considered. Must be a
positive integer less than :code:`n_particles`
p: int {1,2}
the Minkowski p-norm to use. 1 is the
sum-of-absolute values (or L1 distance) while 2 is
the Euclidean (or L2) distance.
Returns
-------
numpy.ndarray
Best position of shape :code:`(n_dimensions, )`
float
Best cost
"""
try:
# Obtain the nearest-neighbors for each particle
tree = cKDTree(swarm.position)
_, idx = tree.query(swarm.position, p=p, k=k)

# Map the computed costs to the neighbour indices and take the
# argmin. If k-neighbors is equal to 1, then the swarm acts
# independently of each other.
if k == 1:
# The minimum index is itself, no mapping needed.
best_neighbor = swarm.pbest_cost[idx][:, np.newaxis].argmin(axis=1)
else:
idx_min = swarm.pbest_cost[idx].argmin(axis=1)
best_neighbor = idx[np.arange(len(idx)), idx_min]
# Obtain best cost and position
best_cost = np.min(swarm.pbest_cost[best_neighbor])
best_pos = swarm.pbest_pos[np.argmin(swarm.pbest_cost[best_neighbor])]
except AttributeError:
msg = 'Please pass a Swarm class. You passed {}'.format(type(swarm))
logger.error(msg)
raise
else:
return (best_pos, best_cost)

def update_velocity(swarm, clamp):
def compute_velocity(swarm, clamp):
"""Updates the velocity matrix
This method updates the velocity matrix using the best and current
Expand Down Expand Up @@ -225,7 +134,7 @@ def update_velocity(swarm, clamp):
else:
return updated_velocity

def update_position(swarm, bounds):
def compute_position(swarm, bounds):
"""Updates the position matrix
This method updates the position matrix given the current position and
Expand Down
19 changes: 0 additions & 19 deletions tests/backend/test_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,6 @@ def test_update_pbest_return_values(swarm):
assert (pos == expected_pos).all()
assert (cost == expected_cost).all()

def test_update_gbest_return_values(swarm):
"""Test if update_gbest() gives the expected return values"""
expected_cost = 1
expected_pos = np.array([1,2,3])
pos, cost = P.update_gbest(swarm)
assert cost == expected_cost
assert (pos == expected_pos).all()

@pytest.mark.parametrize('clamp', [None, (0,1), (-1,1)])
def test_update_velocity_return_values(swarm, clamp):
"""Test if update_velocity() gives the expected shape and range"""
Expand All @@ -41,14 +33,3 @@ def test_update_position_return_values(swarm, bounds):
assert p.shape == swarm.velocity.shape
if bounds is not None:
assert (bounds[0] <= p).all() and (bounds[1] >= p).all()

@pytest.mark.parametrize('k', [1,2,3])
@pytest.mark.parametrize('p', [1,2])
def test_update_gbest_neighborhood(swarm, p, k):
"""Test if update_gbest_neighborhood gives the expected return values"""
pos, cost = P.update_gbest_neighborhood(swarm, p=p, k=k)
expected_pos = np.array([1,2,3])
expected_cost = 1
print('k={} p={}, pos={} cost={}'.format(k,p,pos,cost))
assert (pos == expected_pos).all()
assert cost == expected_cost

0 comments on commit 7010380

Please sign in to comment.