Skip to content

Commit

Permalink
Merge pull request #246 from ljvmiranda921/refactor/general
Browse files Browse the repository at this point in the history
  • Loading branch information
ljvmiranda921 committed Oct 20, 2018
2 parents bf0d11c + f7e376a commit 7e4d04c
Show file tree
Hide file tree
Showing 56 changed files with 1,060 additions and 1,663 deletions.
5 changes: 5 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[report]
exclude_lines =
pragma: no cover
@abc.abstractmethod
pos = init_pos
5 changes: 5 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[settings]
skip=test_plotters.py
import_heading_stdlib=Import standard library
import_heading_firstparty=Import from pyswarms
import_heading_thirdparty=Import modules
7 changes: 5 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
# Import standard library
import os
import sys

# Import from pyswarms
import pyswarms

# If extensions (or modules to document with autodoc) are in another
# directory, add these directories to sys.path here. If the directory is
Expand All @@ -32,7 +36,6 @@
# sys.path.insert(0, project_root)
sys.path.insert(0, os.path.abspath("../"))

import pyswarms

# -- General configuration ---------------------------------------------

Expand Down
50 changes: 38 additions & 12 deletions pyswarms/backend/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
"""

# Import standard library
import logging

# Import modules
import numpy as np

from ..utils.reporter import Reporter
Expand Down Expand Up @@ -44,6 +46,14 @@ def generate_swarm(
-------
numpy.ndarray
swarm matrix of shape (n_particles, n_dimensions)
Raises
------
ValueError
When the shapes and values of bounds, dimensions, and init_pos
are inconsistent.
TypeError
When the argument passed to bounds is not an iterable.
"""
try:
if (init_pos is not None) and (bounds is None):
Expand All @@ -70,12 +80,13 @@ def generate_swarm(
low=min_bounds, high=max_bounds, size=(n_particles, dimensions)
)
except ValueError:
rep.logger.exception(
"Please check the size and value of bounds and dimensions"
)
msg = "Bounds and/or init_pos should be of size ({},)"
rep.logger.exception(msg.format(dimensions))
raise
except TypeError:
rep.logger.exception("Invalid input type!")
msg = "generate_swarm() takes an int for n_particles and dimensions and an array for bounds"
rep.logger.exception(msg)
raise
else:
return pos

Expand All @@ -96,6 +107,18 @@ def generate_discrete_swarm(
init_pos : :code:`numpy.ndarray` (default is :code:`None`)
option to explicitly set the particles' initial positions. Set to
:code:`None` if you wish to generate the particles randomly.
Returns
-------
numpy.ndarray
swarm matrix of shape (n_particles, n_dimensions)
Raises
------
ValueError
When init_pos during binary=True does not contain two unique values.
TypeError
When the argument passed to n_particles or dimensions is incorrect.
"""
try:
if (init_pos is not None) and binary:
Expand All @@ -112,11 +135,12 @@ def generate_discrete_swarm(
size=(n_particles, dimensions)
).argsort(axis=1)
except ValueError:
rep.logger.exception(
"Please check the size and value of bounds and dimensions"
)
rep.logger.exception("Please check the size and value of dimensions")
raise
except TypeError:
rep.logger.exception("Invalid input type!")
msg = "generate_discrete_swarm() takes an int for n_particles and dimensions"
rep.logger.exception(msg)
raise
else:
return pos

Expand Down Expand Up @@ -146,11 +170,13 @@ def generate_velocity(n_particles, dimensions, clamp=None):
size=(n_particles, dimensions)
) + min_velocity
except ValueError:
rep.logger.exception(
"Please check the size and value of clamp and dimensions"
)
msg = "Please check clamp shape: {} != {}"
rep.logger.exception(msg.format(len(clamp), dimensions))
raise
except TypeError:
rep.logger.exception("Invalid input type!")
msg = "generate_velocity() takes an int for n_particles and dimensions and an array for clamp"
rep.logger.exception(msg)
raise
else:
return velocity

Expand Down
6 changes: 6 additions & 0 deletions pyswarms/backend/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
to specify how the swarm will behave.
"""

# Import standard library
import logging

# Import modules
import numpy as np

from ..utils.reporter import Reporter
Expand Down Expand Up @@ -69,6 +71,7 @@ def compute_pbest(swarm):
rep.logger.exception(
"Please pass a Swarm class. You passed {}".format(type(swarm))
)
raise
else:
return (new_pbest_pos, new_pbest_cost)

Expand Down Expand Up @@ -139,8 +142,10 @@ def compute_velocity(swarm, clamp):
rep.logger.exception(
"Please pass a Swarm class. You passed {}".format(type(swarm))
)
raise
except KeyError:
rep.logger.exception("Missing keyword in swarm.options")
raise
else:
return updated_velocity

Expand Down Expand Up @@ -187,5 +192,6 @@ def compute_position(swarm, bounds):
rep.logger.exception(
"Please pass a Swarm class. You passed {}".format(type(swarm))
)
raise
else:
return position
1 change: 1 addition & 0 deletions pyswarms/backend/swarms.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
as input to most backend cases.
"""

# Import modules
import numpy as np
from attr import attrib, attrs
from attr.validators import instance_of
Expand Down
3 changes: 2 additions & 1 deletion pyswarms/backend/topology/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
:mod:`pyswarms.backend.swarms.Swarm` module.
"""

# Import standard library
import abc
import logging

Expand All @@ -33,7 +34,7 @@ def __init__(self, static, **kwargs):
self.rep.log(
"Running on `dynamic` topology,"
"set `static=True` for fixed neighbors.",
lvl=10,
lvl=logging.DEBUG,
)

@abc.abstractmethod
Expand Down
4 changes: 3 additions & 1 deletion pyswarms/backend/topology/pyramid.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
This class implements a pyramid topology. In this topology, the particles are connected by N-dimensional simplices.
"""

# Import standard library
import logging

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

Expand All @@ -29,7 +31,7 @@ def __init__(self, static=False):
super(Pyramid, self).__init__(static)
self.rep = Reporter(logger=logging.getLogger(__name__))

def compute_gbest(self, swarm):
def compute_gbest(self, swarm, **kwargs):
"""Update the global best using a pyramid neighborhood approach
This topology uses the :code:`Delaunay` class from :code:`scipy`. To prevent precision errors in the Delaunay
Expand Down
19 changes: 13 additions & 6 deletions pyswarms/backend/topology/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
This class implements a random topology. All particles are connected in a random fashion.
"""

# Import standard library
import itertools
import logging

# Import modules
import numpy as np
from scipy.sparse.csgraph import connected_components, dijkstra

Expand All @@ -25,11 +27,12 @@ def __init__(self, static=False):
----------
static : bool (Default is :code:`False`)
a boolean that decides whether the topology
is static or dynamic"""
is static or dynamic
"""
super(Random, self).__init__(static)
self.rep = Reporter(logger=logging.getLogger(__name__))

def compute_gbest(self, swarm, k):
def compute_gbest(self, swarm, k, **kwargs):
"""Update the global best using a random neighborhood approach
This uses random class from :code:`numpy` to give every particle k
Expand Down Expand Up @@ -81,10 +84,14 @@ def compute_gbest(self, swarm, k):
).astype(int)

# Obtain best cost and position
best_cost = np.min(swarm.pbest_cost[best_neighbor])
best_pos = swarm.pbest_pos[
best_neighbor[np.argmin(swarm.pbest_cost[best_neighbor])]
]
if np.min(swarm.pbest_cost) < swarm.best_cost:
best_cost = np.min(swarm.pbest_cost[best_neighbor])
best_pos = swarm.pbest_pos[
best_neighbor[np.argmin(swarm.pbest_cost[best_neighbor])]
]
else:
# Just get the previous best_pos and best_cost
best_pos, best_cost = swarm.best_pos, swarm.best_cost

except AttributeError:
self.rep.logger.exception(
Expand Down
13 changes: 8 additions & 5 deletions pyswarms/backend/topology/ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
optimizers.
"""

# Import standard library
import logging

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

Expand All @@ -27,11 +29,12 @@ def __init__(self, static=False):
----------
static : bool (Default is :code:`False`)
a boolean that decides whether the topology
is static or dynamic"""
is static or dynamic
"""
super(Ring, self).__init__(static)
self.rep = Reporter(logger=logging.getLogger(__name__))

def compute_gbest(self, swarm, p, k):
def compute_gbest(self, swarm, p, k, **kwargs):
"""Update the global best using a ring-like neighborhood approach
This uses the cKDTree method from :code:`scipy` to obtain the nearest
Expand All @@ -41,13 +44,13 @@ def compute_gbest(self, swarm, p, k):
----------
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.
k : int
number of neighbors to be considered. Must be a
positive integer less than :code:`n_particles`
Returns
-------
Expand Down
27 changes: 17 additions & 10 deletions pyswarms/backend/topology/star.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
optimizers.
"""

# Import standard library
import logging

# Import modules
import numpy as np

from .. import operators as ops
Expand All @@ -19,16 +21,17 @@


class Star(Topology):
def __init__(self):
def __init__(self, static=None, **kwargs):
# static = None is just an artifact to make the API consistent
# Setting it will not change swarm behavior
super(Star, self).__init__(static=True)
self.rep = Reporter(logger=logging.getLogger(__name__))

def compute_gbest(self, swarm):
def compute_gbest(self, swarm, **kwargs):
"""Update the global best using a star topology
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
the minimum cost and position from the matrix.
.. code-block:: python
Expand All @@ -39,10 +42,8 @@ def compute_gbest(self, swarm):
my_swarm = P.create_swarm(n_particles, dimensions)
my_topology = Star()
# 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 = my_topology.compute_best_particle(my_swarm)
# Update best_cost and position
swarm.best_pos, swarm.best_cost = my_topology.compute_gbest(my_swarm)
Parameters
----------
Expand All @@ -61,8 +62,14 @@ def compute_gbest(self, swarm):
self.neighbor_idx = np.tile(
np.arange(swarm.n_particles), (swarm.n_particles, 1)
)
best_pos = swarm.pbest_pos[np.argmin(swarm.pbest_cost)]
best_cost = np.min(swarm.pbest_cost)
if np.min(swarm.pbest_cost) < swarm.best_cost:
# Get the particle position with the lowest pbest_cost
# and assign it to be the best_pos
best_pos = swarm.pbest_pos[np.argmin(swarm.pbest_cost)]
best_cost = np.min(swarm.pbest_cost)
else:
# Just get the previous best_pos and best_cost
best_pos, best_cost = swarm.best_pos, swarm.best_cost
except AttributeError:
self.rep.logger.exception(
"Please pass a Swarm class. You passed {}".format(type(swarm))
Expand Down

0 comments on commit 7e4d04c

Please sign in to comment.