diff --git a/docs/conf.py b/docs/conf.py index 56e0eceb..a9ad411d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,50 +20,50 @@ # directory, add these directories to sys.path here. If the directory is # relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +# sys.path.insert(0, os.path.abspath('.')) # Get the project root dir, which is the parent dir of this -#cwd = os.getcwd() -#project_root = os.path.dirname(cwd) +# cwd = os.getcwd() +# project_root = os.path.dirname(cwd) # Insert the project root dir as the first element in the PYTHONPATH. # This lets us ensure that the source package is imported, and that its # version is used. -#sys.path.insert(0, project_root) -sys.path.insert(0, os.path.abspath('../')) +# sys.path.insert(0, project_root) +sys.path.insert(0, os.path.abspath("../")) import pyswarms # -- General configuration --------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.viewcode', - 'sphinx.ext.napoleon', - 'sphinx.ext.mathjax' - ] + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinx.ext.napoleon", + "sphinx.ext.mathjax", +] -exclude_patterns = ['_build', '**.ipynb_checkpoints'] +exclude_patterns = ["_build", "**.ipynb_checkpoints"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'PySwarms' +project = u"PySwarms" copyright = u"2017, Lester James V. Miranda" # The version info for the project you're documenting, acts as replacement @@ -77,174 +77,177 @@ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -#language = None +# language = None # There are two options for replacing |today|: either, you set today to # some non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built # documents. -#keep_warnings = False +# keep_warnings = False # -- Options for HTML output ------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a # theme further. For a list of options available for each theme, see the # documentation. -#html_theme_options = {} +# html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] +# html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as # html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (relative to this directory) to place at the # top of the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon # of the docs. This file should be a Windows icon file (.ico) being # 16x16 or 32x32 pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) # here, relative to this directory. They are copied after the builtin # static files, so a file named "default.css" will overwrite the builtin # "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] + def setup(app): # overrides for wide tables in RTD theme - app.add_stylesheet('theme_overrides.css') # path relative to static + 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' +html_last_updated_fmt = "%b %d, %Y" # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names # to template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. # Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. # Default is True. -#html_show_copyright = True +# html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages # will contain a tag referring to it. The value of this option # must be the base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'pyswarmsdoc' +htmlhelp_basename = "pyswarmsdoc" # -- Options for LaTeX output ------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). - 'papersize': 'a4paper', - + "papersize": "a4paper", # The font size ('10pt', '11pt' or '12pt'). - #'pointsize': '10pt', - + # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. - #'preamble': '', + # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass # [howto/manual]). latex_documents = [ - ('index', 'pyswarms.tex', - u'PySwarms Documentation', - u'Lester James V. Miranda', 'manual'), + ( + "index", + "pyswarms.tex", + u"PySwarms Documentation", + u"Lester James V. Miranda", + "manual", + ) ] # The name of an image file (relative to this directory) to place at # the top of the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings # are parts, not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output ------------------------------------ @@ -252,13 +255,17 @@ def setup(app): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'pyswarms', - u'PySwarms Documentation', - [u'Lester James V. Miranda'], 1) + ( + "index", + "pyswarms", + u"PySwarms Documentation", + [u"Lester James V. Miranda"], + 1, + ) ] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ---------------------------------------- @@ -267,22 +274,25 @@ def setup(app): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'pyswarms', - u'PySwarms Documentation', - u'Lester James V. Miranda', - 'pyswarms', - 'PySwarms is a simple, Python-based, Particle Swarm Optimization (PSO) library.', - 'Research'), + ( + "index", + "pyswarms", + u"PySwarms Documentation", + u"Lester James V. Miranda", + "pyswarms", + "PySwarms is a simple, Python-based, Particle Swarm Optimization (PSO) library.", + "Research", + ) ] # Documents to append as an appendix to all manuals. -#texinfo_appendices = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False +# texinfo_no_detailmenu = False diff --git a/pyswarms/backend/topology/pyramid.py b/pyswarms/backend/topology/pyramid.py index 1f209502..f1af7713 100644 --- a/pyswarms/backend/topology/pyramid.py +++ b/pyswarms/backend/topology/pyramid.py @@ -61,24 +61,39 @@ def compute_gbest(self, swarm): try: # If there are less than (swarm.dimensions + 1) particles they are all connected if swarm.n_particles < swarm.dimensions + 1: - self.neighbor_idx = np.tile(np.arange(swarm.n_particles), (swarm.n_particles, 1)) + 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) else: # Check if the topology is static or dynamic and assign neighbors - if (self.static and self.neighbor_idx is None) or not self.static: - pyramid = Delaunay(swarm.position, qhull_options="QJ0.001 Qbb Qc Qx") + if ( + self.static and self.neighbor_idx is None + ) or not self.static: + pyramid = Delaunay( + swarm.position, qhull_options="QJ0.001 Qbb Qc Qx" + ) indices, index_pointer = pyramid.vertex_neighbor_vertices # Insert all the neighbors for each particle in the idx array self.neighbor_idx = np.array( - [index_pointer[indices[i]:indices[i + 1]] for i in range(swarm.n_particles)] + [ + index_pointer[indices[i] : indices[i + 1]] + for i in range(swarm.n_particles) + ] ) idx_min = np.array( - [swarm.pbest_cost[self.neighbor_idx[i]].argmin() for i in range(len(self.neighbor_idx))] + [ + swarm.pbest_cost[self.neighbor_idx[i]].argmin() + for i in range(len(self.neighbor_idx)) + ] ) best_neighbor = np.array( - [self.neighbor_idx[i][idx_min[i]] for i in range(len(self.neighbor_idx))] + [ + self.neighbor_idx[i][idx_min[i]] + for i in range(len(self.neighbor_idx)) + ] ).astype(int) # Obtain best cost and position diff --git a/pyswarms/backend/topology/random.py b/pyswarms/backend/topology/random.py index 17439621..91464ee6 100644 --- a/pyswarms/backend/topology/random.py +++ b/pyswarms/backend/topology/random.py @@ -15,7 +15,7 @@ from scipy.sparse.csgraph import connected_components, dijkstra # Import from package -from ..import operators as ops +from .. import operators as ops from .base import Topology # Create a logger @@ -65,10 +65,23 @@ def compute_gbest(self, swarm, k): # Check if the topology is static or dynamic and assign neighbors if (self.static and self.neighbor_idx is None) or not self.static: adj_matrix = self.__compute_neighbors(swarm, k) - self.neighbor_idx = np.array([adj_matrix[i].nonzero()[0] for i in range(swarm.n_particles)]) - idx_min = np.array([swarm.pbest_cost[self.neighbor_idx[i]].argmin() for i in range(len(self.neighbor_idx))]) + self.neighbor_idx = np.array( + [ + adj_matrix[i].nonzero()[0] + for i in range(swarm.n_particles) + ] + ) + idx_min = np.array( + [ + swarm.pbest_cost[self.neighbor_idx[i]].argmin() + for i in range(len(self.neighbor_idx)) + ] + ) best_neighbor = np.array( - [self.neighbor_idx[i][idx_min[i]] for i in range(len(self.neighbor_idx))] + [ + self.neighbor_idx[i][idx_min[i]] + for i in range(len(self.neighbor_idx)) + ] ).astype(int) # Obtain best cost and position @@ -186,23 +199,43 @@ def __compute_neighbors(self, swarm, k): adj_matrix = np.identity(swarm.n_particles, dtype=int) neighbor_matrix = np.array( - [np.random.choice( - # Exclude i from the array - np.setdiff1d( - np.arange(swarm.n_particles), np.array([i]) - ), k, replace=False - ) for i in range(swarm.n_particles)]) + [ + np.random.choice( + # Exclude i from the array + np.setdiff1d(np.arange(swarm.n_particles), np.array([i])), + k, + replace=False, + ) + for i in range(swarm.n_particles) + ] + ) # Set random elements to one using the neighbor matrix - adj_matrix[np.arange(swarm.n_particles).reshape(swarm.n_particles, 1), neighbor_matrix] = 1 - adj_matrix[neighbor_matrix, np.arange(swarm.n_particles).reshape(swarm.n_particles, 1)] = 1 - - dist_matrix = dijkstra(adj_matrix, directed=False, return_predecessors=False, unweighted=True) + adj_matrix[ + np.arange(swarm.n_particles).reshape(swarm.n_particles, 1), + neighbor_matrix, + ] = 1 + adj_matrix[ + neighbor_matrix, + np.arange(swarm.n_particles).reshape(swarm.n_particles, 1), + ] = 1 + + dist_matrix = dijkstra( + adj_matrix, + directed=False, + return_predecessors=False, + unweighted=True, + ) # Generate connected graph. - while connected_components(adj_matrix, directed=False, return_labels=False) != 1: + while ( + connected_components( + adj_matrix, directed=False, return_labels=False + ) + != 1 + ): for i, j in itertools.product(range(swarm.n_particles), repeat=2): - if dist_matrix[i][j] == np.inf: - adj_matrix[i][j] = 1 + if dist_matrix[i][j] == np.inf: + adj_matrix[i][j] = 1 return adj_matrix diff --git a/pyswarms/backend/topology/ring.py b/pyswarms/backend/topology/ring.py index bef98219..660899c4 100644 --- a/pyswarms/backend/topology/ring.py +++ b/pyswarms/backend/topology/ring.py @@ -72,12 +72,14 @@ def compute_gbest(self, swarm, p, k): # independently of each other. if k == 1: # The minimum index is itself, no mapping needed. - best_neighbor = swarm.pbest_cost[self.neighbor_idx][:, np.newaxis].argmin( - axis=0 - ) + best_neighbor = swarm.pbest_cost[self.neighbor_idx][ + :, np.newaxis + ].argmin(axis=0) else: idx_min = swarm.pbest_cost[self.neighbor_idx].argmin(axis=1) - best_neighbor = self.neighbor_idx[np.arange(len(self.neighbor_idx)), idx_min] + best_neighbor = self.neighbor_idx[ + np.arange(len(self.neighbor_idx)), idx_min + ] # Obtain best cost and position best_cost = np.min(swarm.pbest_cost[best_neighbor]) best_pos = swarm.pbest_pos[ diff --git a/pyswarms/backend/topology/star.py b/pyswarms/backend/topology/star.py index 8c666b2d..8a8f3750 100644 --- a/pyswarms/backend/topology/star.py +++ b/pyswarms/backend/topology/star.py @@ -62,7 +62,9 @@ def compute_gbest(self, swarm): """ try: if self.neighbor_idx is None: - self.neighbor_idx = np.tile(np.arange(swarm.n_particles), (swarm.n_particles, 1)) + 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) except AttributeError: diff --git a/pyswarms/backend/topology/von_neumann.py b/pyswarms/backend/topology/von_neumann.py index ad44cb85..168ec8ec 100644 --- a/pyswarms/backend/topology/von_neumann.py +++ b/pyswarms/backend/topology/von_neumann.py @@ -71,8 +71,9 @@ def delannoy(d, r): if d == 0 or r == 0: return 1 else: - del_number = (VonNeumann.delannoy(d - 1, r) - + VonNeumann.delannoy(d - 1, r - 1) - + VonNeumann.delannoy(d, r - 1) - ) + del_number = ( + VonNeumann.delannoy(d - 1, r) + + VonNeumann.delannoy(d - 1, r - 1) + + VonNeumann.delannoy(d, r - 1) + ) return del_number diff --git a/pyswarms/discrete/binary.py b/pyswarms/discrete/binary.py index 72d8d536..93c481e6 100644 --- a/pyswarms/discrete/binary.py +++ b/pyswarms/discrete/binary.py @@ -149,7 +149,9 @@ def __init__( # Initialize the topology self.top = Ring(static=False) - def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): + def optimize( + self, objective_func, iters, print_step=1, verbose=1, **kwargs + ): """Optimize the swarm for a number of iterations Performs the optimization to evaluate the objective @@ -174,13 +176,21 @@ def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): the local best cost and the local best position among the swarm. """ - cli_print("Arguments Passed to Objective Function: {}".format(kwargs), - verbose, 2, logger=self.logger) + cli_print( + "Arguments Passed to Objective Function: {}".format(kwargs), + verbose, + 2, + logger=self.logger, + ) for i in range(iters): # Compute cost for current position and personal best - self.swarm.current_cost = objective_func(self.swarm.position, **kwargs) - self.swarm.pbest_cost = objective_func(self.swarm.pbest_pos, **kwargs) + self.swarm.current_cost = objective_func( + self.swarm.position, **kwargs + ) + self.swarm.pbest_cost = objective_func( + self.swarm.pbest_pos, **kwargs + ) self.swarm.pbest_pos, self.swarm.pbest_cost = compute_pbest( self.swarm ) @@ -192,7 +202,9 @@ def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): # Print to console if i % print_step == 0: cli_print( - "Iteration {}/{}, cost: {}".format(i + 1, iters, np.min(self.swarm.best_cost)), + "Iteration {}/{}, cost: {}".format( + i + 1, iters, np.min(self.swarm.best_cost) + ), verbose, 2, logger=self.logger, diff --git a/pyswarms/single/general_optimizer.py b/pyswarms/single/general_optimizer.py index d127e582..27edc268 100644 --- a/pyswarms/single/general_optimizer.py +++ b/pyswarms/single/general_optimizer.py @@ -206,8 +206,8 @@ def __init__( if ( self.r <= 0 or not 0 - <= VonNeumann.delannoy(self.swarm.dimensions, self.r) - <= self.n_particles - 1 + <= VonNeumann.delannoy(self.swarm.dimensions, self.r) + <= self.n_particles - 1 ): raise ValueError( "The range must be set such that the computed" @@ -215,7 +215,9 @@ def __init__( "between 0 and the no. of particles." ) - def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): + def optimize( + self, objective_func, iters, print_step=1, verbose=1, **kwargs + ): """Optimize the swarm for a number of iterations Performs the optimization to evaluate the objective @@ -240,19 +242,29 @@ def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): the global best cost and the global best position. """ - cli_print("Arguments Passed to Objective Function: {}".format(kwargs), - verbose, 2, logger=self.logger) + cli_print( + "Arguments Passed to Objective Function: {}".format(kwargs), + verbose, + 2, + logger=self.logger, + ) for i in range(iters): # Compute cost for current position and personal best - self.swarm.current_cost = objective_func(self.swarm.position, **kwargs) - self.swarm.pbest_cost = objective_func(self.swarm.pbest_pos, **kwargs) + self.swarm.current_cost = objective_func( + self.swarm.position, **kwargs + ) + self.swarm.pbest_cost = objective_func( + self.swarm.pbest_pos, **kwargs + ) self.swarm.pbest_pos, self.swarm.pbest_cost = compute_pbest( self.swarm ) best_cost_yet_found = self.swarm.best_cost # If the topology is a ring topology just use the local minimum - if isinstance(self.top, Ring) and not isinstance(self.top, VonNeumann): + if isinstance(self.top, Ring) and not isinstance( + self.top, VonNeumann + ): # Update gbest from neighborhood self.swarm.best_pos, self.swarm.best_cost = self.top.compute_gbest( self.swarm, self.p, self.k @@ -279,10 +291,12 @@ def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): # Print to console if i % print_step == 0: cli_print( - "Iteration {}/{}, cost: {}".format(i + 1, iters, self.swarm.best_cost), + "Iteration {}/{}, cost: {}".format( + i + 1, iters, self.swarm.best_cost + ), verbose, 2, - logger=self.logger + logger=self.logger, ) # Save to history hist = self.ToHistory( @@ -290,7 +304,7 @@ def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): mean_pbest_cost=np.mean(self.swarm.pbest_cost), mean_neighbor_cost=self.swarm.best_cost, position=self.swarm.position, - velocity=self.swarm.velocity + velocity=self.swarm.velocity, ) self._populate_history(hist) # Verify stop criteria based on the relative acceptable cost ftol @@ -314,4 +328,4 @@ def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): end_report( final_best_cost, final_best_pos, verbose, logger=self.logger ) - return(final_best_cost, final_best_pos) + return (final_best_cost, final_best_pos) diff --git a/pyswarms/single/global_best.py b/pyswarms/single/global_best.py index 36bc812e..dbbc35ba 100644 --- a/pyswarms/single/global_best.py +++ b/pyswarms/single/global_best.py @@ -131,7 +131,9 @@ def __init__( # Initialize the topology self.top = Star() - def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): + def optimize( + self, objective_func, iters, print_step=1, verbose=1, **kwargs + ): """Optimize the swarm for a number of iterations Performs the optimization to evaluate the objective @@ -156,13 +158,21 @@ def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): the global best cost and the global best position. """ - cli_print("Arguments Passed to Objective Function: {}".format(kwargs), - verbose, 2, logger=self.logger) + cli_print( + "Arguments Passed to Objective Function: {}".format(kwargs), + verbose, + 2, + logger=self.logger, + ) for i in range(iters): # Compute cost for current position and personal best - self.swarm.current_cost = objective_func(self.swarm.position, **kwargs) - self.swarm.pbest_cost = objective_func(self.swarm.pbest_pos, **kwargs) + self.swarm.current_cost = objective_func( + self.swarm.position, **kwargs + ) + self.swarm.pbest_cost = objective_func( + self.swarm.pbest_pos, **kwargs + ) self.swarm.pbest_pos, self.swarm.pbest_cost = compute_pbest( self.swarm ) @@ -175,7 +185,9 @@ def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): # Print to console if i % print_step == 0: cli_print( - "Iteration {}/{}, cost: {}".format(i + 1, iters, self.swarm.best_cost), + "Iteration {}/{}, cost: {}".format( + i + 1, iters, self.swarm.best_cost + ), verbose, 2, logger=self.logger, diff --git a/pyswarms/single/local_best.py b/pyswarms/single/local_best.py index 8e64b041..06cb8ad2 100644 --- a/pyswarms/single/local_best.py +++ b/pyswarms/single/local_best.py @@ -113,7 +113,7 @@ def __init__( center=1.00, ftol=-np.inf, init_pos=None, - static=False + static=False, ): """Initialize the swarm @@ -178,7 +178,9 @@ def __init__( # Initialize the topology self.top = Ring(static=static) - def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): + def optimize( + self, objective_func, iters, print_step=1, verbose=1, **kwargs + ): """Optimize the swarm for a number of iterations Performs the optimization to evaluate the objective @@ -203,13 +205,21 @@ def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): the local best cost and the local best position among the swarm. """ - cli_print("Arguments Passed to Objective Function: {}".format(kwargs), - verbose, 2, logger=self.logger) + cli_print( + "Arguments Passed to Objective Function: {}".format(kwargs), + verbose, + 2, + logger=self.logger, + ) for i in range(iters): # Compute cost for current position and personal best - self.swarm.current_cost = objective_func(self.swarm.position, **kwargs) - self.swarm.pbest_cost = objective_func(self.swarm.pbest_pos, **kwargs) + self.swarm.current_cost = objective_func( + self.swarm.position, **kwargs + ) + self.swarm.pbest_cost = objective_func( + self.swarm.pbest_pos, **kwargs + ) self.swarm.pbest_pos, self.swarm.pbest_cost = compute_pbest( self.swarm ) @@ -221,7 +231,9 @@ def optimize(self, objective_func, iters, print_step=1, verbose=1, **kwargs): # Print to console if i % print_step == 0: cli_print( - "Iteration {}/{}, cost: {}".format(i + 1, iters, np.min(self.swarm.best_cost)), + "Iteration {}/{}, cost: {}".format( + i + 1, iters, np.min(self.swarm.best_cost) + ), verbose, 2, logger=self.logger, diff --git a/pyswarms/utils/__init__.py b/pyswarms/utils/__init__.py index feb2c0bd..ea80fdaf 100644 --- a/pyswarms/utils/__init__.py +++ b/pyswarms/utils/__init__.py @@ -1 +1,5 @@ """ Pacakge for various utilities """ + +from .reporter.reporter import Reporter + +__all__ = ["Reporter"] diff --git a/pyswarms/utils/plotters/formatters.py b/pyswarms/utils/plotters/formatters.py index 78e1173b..027c14a5 100644 --- a/pyswarms/utils/plotters/formatters.py +++ b/pyswarms/utils/plotters/formatters.py @@ -62,11 +62,11 @@ class Designer(object): default=["x-axis", "y-axis", "z-axis"], ) limits = attrib( - validator=instance_of((list, tuple)), default=[(-1, 1), (-1, 1), (-1, 1)] + validator=instance_of((list, tuple)), + default=[(-1, 1), (-1, 1), (-1, 1)], ) colormap = attrib( - validator=instance_of(colors.Colormap), - default=cm.viridis, + validator=instance_of(colors.Colormap), default=cm.viridis ) diff --git a/pyswarms/utils/reporter/__init__.py b/pyswarms/utils/reporter/__init__.py new file mode 100644 index 00000000..15390076 --- /dev/null +++ b/pyswarms/utils/reporter/__init__.py @@ -0,0 +1,5 @@ +"""Reporter module""" + +from .reporter import Reporter + +__all__ = ["Reporter"] diff --git a/pyswarms/utils/reporter/reporter.py b/pyswarms/utils/reporter/reporter.py new file mode 100644 index 00000000..61bffe6e --- /dev/null +++ b/pyswarms/utils/reporter/reporter.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +import os +import yaml +import pprint +import logging + + +class Reporter(object): + """A Reporter object that abstracts various logging capabilities + + To set-up a Reporter, simply perform the following tasks: + + .. code-block:: python + + from pyswarms.utils import Reporter + + rep = Reporter() + rep.log("Here's my message", lvl=20) + + This will set-up a reporter with a default configuration that + logs to a file, `report.log`, on the current working directory. + You can change the log path by passing a string to the `log_path` + parameter: + + .. code-block:: python + + from pyswarms.utils import Reporter + + rep = Reporter(log_path="/path/to/log/file.log") + rep.log("Here's my message", lvl=20) + + If you are working on a module and you have an existing logger, + you can pass that logger instance during initialization: + + .. code-block:: python + + # mymodule.py + from pyswarms.utils import Reporter + + # An existing logger in a module + logger = logging.getLogger(__name__) + rep = Reporter(logger=logger) + + Lastly, if you have your own logger configuration (YAML file), + then simply pass that to the `config_path` parameter. This + overrides the default configuration (including `log_path`): + + .. code-block:: python + + from pyswarms.utils import Reporter + + rep = Reporter(config_path="/path/to/config/file.yml") + rep.log("Here's my message", lvl=20) + + """ + + def __init__( + self, log_path=None, config_path=None, logger=None, printer=None + ): + """Initialize the reporter + + Attributes + ---------- + log_path : str (default is :code:`None`) + Sets the default log path (overriden when :code:`path` is given to + :code:`_setup_logger()`) + config_path : str (default is :code:`None`) + Sets the configuration path for custom loggers + logger : logging.Logger (default is :code:`None`) + The logger object. By default, it creates a new :code:`Logger` + instance + printer : pprint.PrettyPrinter (default is :code:`None`) + A printer object. By default, it creates a :code:`PrettyPrinter` + instance with default values + """ + self.logger = logger or logging.getLogger(__name__) + self.printer = printer or pprint.PrettyPrinter() + self.log_path = log_path or (os.getcwd() + "/report.log") + self._env_key = "LOG_CFG" + self._default_config = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "standard": { + "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + } + }, + "handlers": { + "default": { + "level": "INFO", + "class": "logging.StreamHandler", + "formatter": "standard", + }, + "file_default": { + "level": "INFO", + "formatter": "standard", + "class": "logging.handlers.RotatingFileHandler", + "filename": self.log_path, + "encoding": "utf8", + "maxBytes": 10485760, + "backupCount": 20, + }, + }, + "loggers": { + "": { + "handlers": ["default", "file_default"], + "level": "INFO", + "propagate": True, + } + }, + } + self._setup_logger(config_path) + + def log(self, msg, lvl=20, *args, **kwargs): + """Log a message within a set level + + This method abstracts the logging.Logger.log() method. We use this + method during major state changes, errors, or critical events during + the optimization run. + + You can check logging levels on this `link`_. In essence, DEBUG is 10, + INFO is 20, WARNING is 30, ERROR is 40, and CRITICAL is 50. + + .. link: https://docs.python.org/3/library/logging.html#logging-levels + + Parameters + ---------- + msg : str + Message to be logged + lvl : int (default is 20) + Logging level + """ + self.logger.log(lvl, msg, *args, **kwargs) + + def print(self, msg, verbosity, threshold=0): + """Print a message into console + + This method can be called during non-system calls or minor state + changes. In practice, we call this method when reporting the cost + on a given timestep. + + Parameters + ---------- + msg : str + Message to be printed + verbosity : int + Verbosity parameter, prints message when it's greater than the + threshold + threshold : int (default is 0) + Threshold parameer, prints message when it's lesser than the + verbosity + """ + if verbosity > threshold: + self.printer.pprint(msg) + else: + pass + + def _setup_logger(self, path=None): + """Set-up the logger with default values + + This method is called right after initializing the Reporter module. + If no path is supplied, then it loads a default configuration. + You can view the defaults via the Reporter._default_config attribute. + + + Parameters + ---------- + path : str + Path to a YAML configuration. If not supplied, uses + a default config. + """ + value = path or os.getenv(self._env_key, None) + try: + with open(path, "rt") as f: + config = yaml.safe_load(f.read()) + logging.config.dictConfig(config) + except (TypeError, FileNotFoundError): + self._load_defaults() + + def _load_defaults(self): + """Load default logging configuration""" + logging.config.dictConfig(self._default_config) diff --git a/tests/backend/topology/conftest.py b/tests/backend/topology/conftest.py index 4aade1b1..be5a5014 100644 --- a/tests/backend/topology/conftest.py +++ b/tests/backend/topology/conftest.py @@ -14,6 +14,7 @@ @pytest.fixture(scope="module") def swarm(): """A contrived instance of the Swarm class at a certain timestep""" + # fmt: off attrs_at_t = { "position": np.array([[9.95838686e-01, 5.87433429e-04, 6.49113772e-03], [1.00559609e+00, 3.96477697e-02, 7.67205397e-01], @@ -53,4 +54,5 @@ def swarm(): "best_pos": np.array([9.90438476e-01, 2.50379538e-03, 1.87405987e-05]), "options": {'c1': 0.5, 'c2': 0.3, 'w': 0.9}, } + # fmt: on return Swarm(**attrs_at_t) diff --git a/tests/backend/topology/test_pyramid.py b/tests/backend/topology/test_pyramid.py index 31583428..cce94e19 100644 --- a/tests/backend/topology/test_pyramid.py +++ b/tests/backend/topology/test_pyramid.py @@ -17,7 +17,7 @@ def test_compute_gbest_return_values(swarm, static): expected_pos = np.array([9.90438476e-01, 2.50379538e-03, 1.87405987e-05]) pos, cost = topology.compute_gbest(swarm) assert cost == pytest.approx(expected_cost) - assert (pos == pytest.approx(expected_pos)) + assert pos == pytest.approx(expected_pos) @pytest.mark.parametrize("static", [True, False]) diff --git a/tests/backend/topology/test_random.py b/tests/backend/topology/test_random.py index 1b12a5dc..9cc406f8 100644 --- a/tests/backend/topology/test_random.py +++ b/tests/backend/topology/test_random.py @@ -18,7 +18,7 @@ def test_update_gbest_neighborhood(swarm, k, static): expected_pos = np.array([9.90438476e-01, 2.50379538e-03, 1.87405987e-05]) expected_cost = 1.0002528364353296 assert cost == pytest.approx(expected_cost) - assert (pos == pytest.approx(expected_pos)) + assert pos == pytest.approx(expected_pos) @pytest.mark.parametrize("static", [True, False]) @@ -63,6 +63,7 @@ def test_compute_neighbors_adjacency_matrix(swarm, k, static): np.random.seed(1) topology = Random(static=static) adj_matrix = topology._Random__compute_neighbors(swarm, k) + # fmt: off comparison_matrix = np.array([[1, 1, 1, 0, 1, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], @@ -74,6 +75,7 @@ def test_compute_neighbors_adjacency_matrix(swarm, k, static): [0, 1, 1, 1, 1, 0, 1, 1, 1, 0], [1, 1, 1, 0, 1, 1, 1, 0, 0, 1]]) assert np.allclose(adj_matrix, comparison_matrix, atol=1e-8) + # fmt: on @pytest.mark.parametrize("static", [True, False]) diff --git a/tests/backend/topology/test_ring.py b/tests/backend/topology/test_ring.py index c7723724..9dc6e7a5 100644 --- a/tests/backend/topology/test_ring.py +++ b/tests/backend/topology/test_ring.py @@ -19,7 +19,7 @@ def test_update_gbest_neighborhood(swarm, p, k, static): expected_pos = np.array([9.90438476e-01, 2.50379538e-03, 1.87405987e-05]) expected_cost = 1.0002528364353296 assert cost == pytest.approx(expected_cost) - assert (pos == pytest.approx(expected_pos)) + assert pos == pytest.approx(expected_pos) @pytest.mark.parametrize("static", [True, False]) diff --git a/tests/backend/topology/test_star.py b/tests/backend/topology/test_star.py index 1dc72415..957ecdad 100644 --- a/tests/backend/topology/test_star.py +++ b/tests/backend/topology/test_star.py @@ -16,7 +16,7 @@ def test_compute_gbest_return_values(swarm): expected_pos = np.array([9.90438476e-01, 2.50379538e-03, 1.87405987e-05]) pos, cost = topology.compute_gbest(swarm) assert cost == pytest.approx(expected_cost) - assert (pos == pytest.approx(expected_pos)) + assert pos == pytest.approx(expected_pos) @pytest.mark.parametrize("clamp", [None, (0, 1), (-1, 1)]) diff --git a/tests/backend/topology/test_von_neumann.py b/tests/backend/topology/test_von_neumann.py index e34a9000..1e27cd9a 100644 --- a/tests/backend/topology/test_von_neumann.py +++ b/tests/backend/topology/test_von_neumann.py @@ -18,7 +18,7 @@ def test_update_gbest_neighborhood(swarm, p, r): expected_pos = np.array([9.90438476e-01, 2.50379538e-03, 1.87405987e-05]) expected_cost = 1.0002528364353296 assert cost == pytest.approx(expected_cost) - assert (pos == pytest.approx(expected_pos)) + assert pos == pytest.approx(expected_pos) @pytest.mark.parametrize("clamp", [None, (0, 1), (-1, 1)]) @@ -56,11 +56,12 @@ def test_neighbor_idx(swarm, p, r): @pytest.mark.parametrize("m", [i for i in range(9)]) @pytest.mark.parametrize("n", [i for i in range(10)]) def test_delannoy_numbers(m, n): + # fmt: off expected_values = np.array([1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 25, 41, 61, 63, 85, 113, 129, 145, 181, 231, 321, 377, 575, 681, 833, 1159, 1289, 1683, 2241, 3649, 3653, 5641, 7183, 8989, 13073, 19825, 40081, 48639, 75517, 108545, 22363, 224143, 265729, 598417]) - print(VonNeumann.delannoy(m, n)) + # fmt: on assert VonNeumann.delannoy(m, n) in expected_values diff --git a/tests/optimizers/conftest.py b/tests/optimizers/conftest.py index 0d278d4f..cb78cf1f 100644 --- a/tests/optimizers/conftest.py +++ b/tests/optimizers/conftest.py @@ -18,7 +18,9 @@ def general_opt_history(topology): """Returns a GeneralOptimizerPSO instance run for 1000 iterations for checking history""" - pso = GeneralOptimizerPSO(10, 2, {"c1": 0.5, "c2": 0.7, "w": 0.5}, topology=topology) + pso = GeneralOptimizerPSO( + 10, 2, {"c1": 0.5, "c2": 0.7, "w": 0.5}, topology=topology + ) pso.optimize(sphere, 1000, verbose=0) return pso @@ -27,7 +29,9 @@ def general_opt_history(topology): def general_opt_reset(topology): """Returns a GeneralOptimizerPSO instance that has been run and reset to check default value""" - pso = GeneralOptimizerPSO(10, 2, {"c1": 0.5, "c2": 0.7, "w": 0.5}, topology=topology) + pso = GeneralOptimizerPSO( + 10, 2, {"c1": 0.5, "c2": 0.7, "w": 0.5}, topology=topology + ) pso.optimize(sphere, 10, verbose=0) pso.reset() return pso @@ -97,6 +101,7 @@ def options(): return options_ +# fmt: off @pytest.fixture(params=[ Star(), Ring(static=False), Ring(static=True), @@ -104,6 +109,7 @@ def options(): Random(static=False), Random(static=True), VonNeumann() ]) +# fmt: on def topology(request): """Parametrized topology parameter""" topology_ = request.param diff --git a/tests/optimizers/test_general_optimizer.py b/tests/optimizers/test_general_optimizer.py index 779dad88..eac1d5b2 100644 --- a/tests/optimizers/test_general_optimizer.py +++ b/tests/optimizers/test_general_optimizer.py @@ -108,7 +108,7 @@ def test_invalid_r_or_p_values(options): [ {"c1": 0.5, "c2": 0.7, "w": 0.5, "k": -1}, {"c1": 0.5, "c2": 0.7, "w": 0.5, "k": 6}, - {"c1": 0.5, "c2": 0.7, "w": 0.5, "k": 0.5} + {"c1": 0.5, "c2": 0.7, "w": 0.5, "k": 0.5}, ], ) def test_invalid_k_value(options, static): @@ -118,10 +118,7 @@ def test_invalid_k_value(options, static): GeneralOptimizerPSO(5, 2, options, Random(static=static)) -@pytest.mark.parametrize( - "topology", - [object(), int(), dict()] -) +@pytest.mark.parametrize("topology", [object(), int(), dict()]) def test_topology_type_exception(options, topology): """Tests if exceptions are thrown when the topology has the wrong type""" with pytest.raises(TypeError): @@ -139,7 +136,9 @@ def test_topology_type_exception(options, topology): def test_bounds_size_exception(bounds, options, topology): """Tests if exceptions are raised when bound sizes are wrong""" with pytest.raises(IndexError): - GeneralOptimizerPSO(5, 2, options=options, topology=topology, bounds=bounds) + GeneralOptimizerPSO( + 5, 2, options=options, topology=topology, bounds=bounds + ) @pytest.mark.parametrize( @@ -152,7 +151,9 @@ def test_bounds_size_exception(bounds, options, topology): def test_bounds_maxmin_exception(bounds, options, topology): """Tests if the max bounds is less than min bounds and vice-versa""" with pytest.raises(ValueError): - GeneralOptimizerPSO(5, 2, options=options, topology=topology, bounds=bounds) + GeneralOptimizerPSO( + 5, 2, options=options, topology=topology, bounds=bounds + ) @pytest.mark.parametrize( @@ -165,7 +166,9 @@ def test_bounds_maxmin_exception(bounds, options, topology): def test_bound_type_exception(bounds, options, topology): """Tests if exception is raised when bound type is not a tuple""" with pytest.raises(TypeError): - GeneralOptimizerPSO(5, 2, options=options, topology=topology, bounds=bounds) + GeneralOptimizerPSO( + 5, 2, options=options, topology=topology, bounds=bounds + ) @pytest.mark.parametrize("velocity_clamp", [(1, 1, 1), (2, 3, 1)]) @@ -173,7 +176,13 @@ def test_vclamp_shape_exception(velocity_clamp, options, topology): """Tests if exception is raised when velocity_clamp's size is not equal to 2""" with pytest.raises(IndexError): - GeneralOptimizerPSO(5, 2, velocity_clamp=velocity_clamp, options=options, topology=topology) + GeneralOptimizerPSO( + 5, + 2, + velocity_clamp=velocity_clamp, + options=options, + topology=topology, + ) @pytest.mark.parametrize("velocity_clamp", [(3, 2), (10, 8)]) @@ -181,14 +190,22 @@ def test_vclamp_maxmin_exception(velocity_clamp, options, topology): """Tests if the max velocity_clamp is less than min velocity_clamp and vice-versa""" with pytest.raises(ValueError): - GeneralOptimizerPSO(5, 2, velocity_clamp=velocity_clamp, options=options, topology=topology) + GeneralOptimizerPSO( + 5, + 2, + velocity_clamp=velocity_clamp, + options=options, + topology=topology, + ) @pytest.mark.parametrize("err, center", [(IndexError, [1.5, 3.2, 2.5])]) def test_center_exception(err, center, options, topology): """Tests if exception is thrown when center is not a list or of different shape""" with pytest.raises(err): - GeneralOptimizerPSO(5, 2, center=center, options=options, topology=topology) + GeneralOptimizerPSO( + 5, 2, center=center, options=options, topology=topology + ) def test_reset_default_values(gbest_reset): @@ -216,6 +233,8 @@ def test_training_history_shape(gbest_history, history, expected_shape): def test_ftol_effect(options, topology): """Test if setting the ftol breaks the optimization process accordingly""" - pso = GeneralOptimizerPSO(10, 2, options=options, topology=topology, ftol=1e-1) + pso = GeneralOptimizerPSO( + 10, 2, options=options, topology=topology, ftol=1e-1 + ) pso.optimize(sphere, 2000, verbose=0) assert np.array(pso.cost_history).shape != (2000,) diff --git a/tests/optimizers/test_objective_func_with_kwargs.py b/tests/optimizers/test_objective_func_with_kwargs.py index c73442dc..169fd198 100644 --- a/tests/optimizers/test_objective_func_with_kwargs.py +++ b/tests/optimizers/test_objective_func_with_kwargs.py @@ -16,64 +16,66 @@ def rosenbrock_with_args(x, a, b): return f -@pytest.mark.parametrize('func', [ - rosenbrock_with_args -]) +@pytest.mark.parametrize("func", [rosenbrock_with_args]) def test_global_kwargs(func): """Tests if kwargs are passed properly to the objective function for when kwargs are present""" # setup optimizer - options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2} + options = {"c1": 0.5, "c2": 0.3, "w": 0.9, "k": 2, "p": 2} x_max = 10 * np.ones(2) x_min = -1 * x_max bounds = (x_min, x_max) - opt_ps = GlobalBestPSO(n_particles=100, dimensions=2, options=options, bounds=bounds) + opt_ps = GlobalBestPSO( + n_particles=100, dimensions=2, options=options, bounds=bounds + ) # run it - cost, pos = opt_ps.optimize(func, 1000, print_step=10, verbose=3, a=1 , b=100) + cost, pos = opt_ps.optimize( + func, 1000, print_step=10, verbose=3, a=1, b=100 + ) assert np.isclose(cost, 0, rtol=1e-03) assert np.isclose(pos[0], 1.0, rtol=1e-03) assert np.isclose(pos[1], 1.0, rtol=1e-03) -@pytest.mark.parametrize('func', [ - rosenbrock_with_args -]) +@pytest.mark.parametrize("func", [rosenbrock_with_args]) def test_global_kwargs_without_named_arguments(func): """Tests if kwargs are passed properly to the objective function for when kwargs are present and other named arguments are not passed, such as print_step""" # setup optimizer - options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2} + options = {"c1": 0.5, "c2": 0.3, "w": 0.9, "k": 2, "p": 2} x_max = 10 * np.ones(2) x_min = -1 * x_max bounds = (x_min, x_max) - opt_ps = GlobalBestPSO(n_particles=100, dimensions=2, options=options, bounds=bounds) + opt_ps = GlobalBestPSO( + n_particles=100, dimensions=2, options=options, bounds=bounds + ) # run it - cost, pos = opt_ps.optimize(func, 1000, verbose=3, a=1 , b=100) + cost, pos = opt_ps.optimize(func, 1000, verbose=3, a=1, b=100) assert np.isclose(cost, 0, rtol=1e-03) assert np.isclose(pos[0], 1.0, rtol=1e-03) assert np.isclose(pos[1], 1.0, rtol=1e-03) -@pytest.mark.parametrize('func', [ - rosenbrock -]) +@pytest.mark.parametrize("func", [rosenbrock]) def test_global_no_kwargs(func): """Tests if args are passed properly to the objective function for when no args are present""" # setup optimizer - options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2} + options = {"c1": 0.5, "c2": 0.3, "w": 0.9, "k": 2, "p": 2} x_max = 10 * np.ones(2) x_min = -1 * x_max bounds = (x_min, x_max) - opt_ps = GlobalBestPSO(n_particles=100, dimensions=2, options=options, bounds=bounds) + opt_ps = GlobalBestPSO( + n_particles=100, dimensions=2, options=options, bounds=bounds + ) # run it cost, pos = opt_ps.optimize(func, 1000, print_step=10, verbose=3) @@ -83,41 +85,43 @@ def test_global_no_kwargs(func): assert np.isclose(pos[1], 1.0, rtol=1e-03) -@pytest.mark.parametrize('func', [ - rosenbrock_with_args -]) +@pytest.mark.parametrize("func", [rosenbrock_with_args]) def test_local_kwargs(func): """Tests if kwargs are passed properly to the objective function for when kwargs are present""" # setup optimizer - options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2} + options = {"c1": 0.5, "c2": 0.3, "w": 0.9, "k": 2, "p": 2} x_max = 10 * np.ones(2) x_min = -1 * x_max bounds = (x_min, x_max) - opt_ps = LocalBestPSO(n_particles=100, dimensions=2, options=options, bounds=bounds) + opt_ps = LocalBestPSO( + n_particles=100, dimensions=2, options=options, bounds=bounds + ) # run it - cost, pos = opt_ps.optimize(func, 1000, print_step=10, verbose=3, a=1, b=100) + cost, pos = opt_ps.optimize( + func, 1000, print_step=10, verbose=3, a=1, b=100 + ) assert np.isclose(cost, 0, rtol=1e-03) assert np.isclose(pos[0], 1.0, rtol=1e-03) assert np.isclose(pos[1], 1.0, rtol=1e-03) -@pytest.mark.parametrize('func', [ - rosenbrock -]) +@pytest.mark.parametrize("func", [rosenbrock]) def test_local_no_kwargs(func): """Tests if no kwargs/args are passed properly to the objective function for when kwargs are present""" # setup optimizer - options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2} + options = {"c1": 0.5, "c2": 0.3, "w": 0.9, "k": 2, "p": 2} x_max = 10 * np.ones(2) x_min = -1 * x_max bounds = (x_min, x_max) - opt_ps = LocalBestPSO(n_particles=100, dimensions=2, options=options, bounds=bounds) + opt_ps = LocalBestPSO( + n_particles=100, dimensions=2, options=options, bounds=bounds + ) # run it cost, pos = opt_ps.optimize(func, iters=1000, print_step=10, verbose=3) @@ -127,121 +131,125 @@ def test_local_no_kwargs(func): assert np.isclose(pos[1], 1.0, rtol=1e-03) -@pytest.mark.parametrize('func', [ - rosenbrock -]) +@pytest.mark.parametrize("func", [rosenbrock]) def test_global_uneeded_kwargs(func): """Tests kwargs are passed the objective function for when kwargs do not exist""" # setup optimizer - options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2} + options = {"c1": 0.5, "c2": 0.3, "w": 0.9, "k": 2, "p": 2} x_max = 10 * np.ones(2) x_min = -1 * x_max bounds = (x_min, x_max) - opt_ps = GlobalBestPSO(n_particles=100, dimensions=2, options=options, bounds=bounds) + opt_ps = GlobalBestPSO( + n_particles=100, dimensions=2, options=options, bounds=bounds + ) # run it with pytest.raises(TypeError) as excinfo: cost, pos = opt_ps.optimize(func, 1000, print_step=10, verbose=3, a=1) - assert 'unexpected keyword' in str(excinfo.value) + assert "unexpected keyword" in str(excinfo.value) -@pytest.mark.parametrize('func', [ - rosenbrock_with_args -]) +@pytest.mark.parametrize("func", [rosenbrock_with_args]) def test_global_missed_kwargs(func): """Tests kwargs are passed the objective function for when kwargs do not exist""" # setup optimizer - options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2} + options = {"c1": 0.5, "c2": 0.3, "w": 0.9, "k": 2, "p": 2} x_max = 10 * np.ones(2) x_min = -1 * x_max bounds = (x_min, x_max) - opt_ps = GlobalBestPSO(n_particles=100, dimensions=2, options=options, bounds=bounds) + opt_ps = GlobalBestPSO( + n_particles=100, dimensions=2, options=options, bounds=bounds + ) # run it with pytest.raises(TypeError) as excinfo: cost, pos = opt_ps.optimize(func, 1000, print_step=10, verbose=3, a=1) - assert 'missing 1 required positional argument' in str(excinfo.value) + assert "missing 1 required positional argument" in str(excinfo.value) -@pytest.mark.parametrize('func', [ - rosenbrock -]) +@pytest.mark.parametrize("func", [rosenbrock]) def test_local_uneeded_kwargs(func): """Tests kwargs are passed the objective function for when kwargs do not exist""" # setup optimizer - options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2} + options = {"c1": 0.5, "c2": 0.3, "w": 0.9, "k": 2, "p": 2} x_max = 10 * np.ones(2) x_min = -1 * x_max bounds = (x_min, x_max) - opt_ps = LocalBestPSO(n_particles=100, dimensions=2, options=options, bounds=bounds) + opt_ps = LocalBestPSO( + n_particles=100, dimensions=2, options=options, bounds=bounds + ) # run it with pytest.raises(TypeError) as excinfo: cost, pos = opt_ps.optimize(func, 1000, print_step=10, verbose=3, a=1) - assert 'unexpected keyword' in str(excinfo.value) + assert "unexpected keyword" in str(excinfo.value) -@pytest.mark.parametrize('func', [ - rosenbrock_with_args -]) +@pytest.mark.parametrize("func", [rosenbrock_with_args]) def test_local_missed_kwargs(func): """Tests kwargs are passed the objective function for when kwargs do not exist""" # setup optimizer - options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2} + options = {"c1": 0.5, "c2": 0.3, "w": 0.9, "k": 2, "p": 2} x_max = 10 * np.ones(2) x_min = -1 * x_max bounds = (x_min, x_max) - opt_ps = LocalBestPSO(n_particles=100, dimensions=2, options=options, bounds=bounds) + opt_ps = LocalBestPSO( + n_particles=100, dimensions=2, options=options, bounds=bounds + ) # run it with pytest.raises(TypeError) as excinfo: cost, pos = opt_ps.optimize(func, 1000, print_step=10, verbose=3, a=1) - assert 'missing 1 required positional argument' in str(excinfo.value) + assert "missing 1 required positional argument" in str(excinfo.value) -@pytest.mark.parametrize('func', [ - rosenbrock_with_args -]) +@pytest.mark.parametrize("func", [rosenbrock_with_args]) def test_local_wrong_kwargs(func): """Tests kwargs are passed the objective function for when kwargs do not exist""" # setup optimizer - options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2} + options = {"c1": 0.5, "c2": 0.3, "w": 0.9, "k": 2, "p": 2} x_max = 10 * np.ones(2) x_min = -1 * x_max bounds = (x_min, x_max) - opt_ps = LocalBestPSO(n_particles=100, dimensions=2, options=options, bounds=bounds) + opt_ps = LocalBestPSO( + n_particles=100, dimensions=2, options=options, bounds=bounds + ) # run it with pytest.raises(TypeError) as excinfo: - cost, pos = opt_ps.optimize(func, 1000, print_step=10, verbose=3, c=1, d=100) - assert 'unexpected keyword' in str(excinfo.value) + cost, pos = opt_ps.optimize( + func, 1000, print_step=10, verbose=3, c=1, d=100 + ) + assert "unexpected keyword" in str(excinfo.value) -@pytest.mark.parametrize('func', [ - rosenbrock_with_args -]) +@pytest.mark.parametrize("func", [rosenbrock_with_args]) def test_global_wrong_kwargs(func): """Tests kwargs are passed the objective function for when kwargs do not exist""" # setup optimizer - options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2} + options = {"c1": 0.5, "c2": 0.3, "w": 0.9, "k": 2, "p": 2} x_max = 10 * np.ones(2) x_min = -1 * x_max bounds = (x_min, x_max) - opt_ps = GlobalBestPSO(n_particles=100, dimensions=2, options=options, bounds=bounds) + opt_ps = GlobalBestPSO( + n_particles=100, dimensions=2, options=options, bounds=bounds + ) # run it with pytest.raises(TypeError) as excinfo: - cost, pos = opt_ps.optimize(func, 1000, print_step=10, verbose=3, c=1, d=100) - assert 'unexpected keyword' in str(excinfo.value) + cost, pos = opt_ps.optimize( + func, 1000, print_step=10, verbose=3, c=1, d=100 + ) + assert "unexpected keyword" in str(excinfo.value) diff --git a/tests/utils/functions/test_singleobj_bounds.py b/tests/utils/functions/test_singleobj_bounds.py index 5390f7f9..17fa9379 100644 --- a/tests/utils/functions/test_singleobj_bounds.py +++ b/tests/utils/functions/test_singleobj_bounds.py @@ -33,7 +33,6 @@ } - def test_ackley_bound_fail(outbound): """Test ackley bound exception""" with pytest.raises(ValueError): diff --git a/tests/utils/functions/test_singleobj_dims.py b/tests/utils/functions/test_singleobj_dims.py index 9ab0e38d..a7f7c328 100644 --- a/tests/utils/functions/test_singleobj_dims.py +++ b/tests/utils/functions/test_singleobj_dims.py @@ -41,6 +41,7 @@ def test_easom_dim_fail(outdim): with pytest.raises(IndexError): fx.easom(outdim) + def test_goldstein_dim_fail(outdim): """Test goldstein dim exception""" with pytest.raises(IndexError): diff --git a/tests/utils/functions/test_singleobj_return.py b/tests/utils/functions/test_singleobj_return.py index 3aced1b5..e3cf8c74 100644 --- a/tests/utils/functions/test_singleobj_return.py +++ b/tests/utils/functions/test_singleobj_return.py @@ -10,9 +10,6 @@ from pyswarms.utils.functions import single_obj as fx - - - def test_ackley_output(common_minima): """Tests ackley function output.""" assert np.isclose(fx.ackley(common_minima), np.zeros(3)).all() @@ -20,45 +17,38 @@ def test_ackley_output(common_minima): def test_beale_output(common_minima2): """Tests beale function output.""" - assert np.isclose( - fx.beale([3, 0.5] * common_minima2), np.zeros(3) - ).all() + assert np.isclose(fx.beale([3, 0.5] * common_minima2), np.zeros(3)).all() def test_booth_output(common_minima2): """Test booth function output.""" - assert np.isclose( - fx.booth([1, 3] * common_minima2), np.zeros(3) - ).all() + assert np.isclose(fx.booth([1, 3] * common_minima2), np.zeros(3)).all() def test_bukin6_output(common_minima2): """Test bukin function output.""" - assert np.isclose( - fx.bukin6([-10, 1] * common_minima2), np.zeros(3) - ).all() + assert np.isclose(fx.bukin6([-10, 1] * common_minima2), np.zeros(3)).all() @pytest.mark.parametrize( "x", [ - np.array([[1.34941, -1.34941], - [1.34941, 1.34941], - [-1.34941, 1.34941], - [-1.34941, -1.34941]]) + np.array( + [ + [1.34941, -1.34941], + [1.34941, 1.34941], + [-1.34941, 1.34941], + [-1.34941, -1.34941], + ] + ) ], ) @pytest.mark.parametrize( - "minima", - [ - np.array([-2.06261, -2.06261, -2.06261, -2.06261]) - ], + "minima", [np.array([-2.06261, -2.06261, -2.06261, -2.06261])] ) def test_crossintray_output(x, minima): """Tests crossintray function output.""" - assert np.isclose( - fx.crossintray(x), minima - ).all() + assert np.isclose(fx.crossintray(x), minima).all() def test_easom_output(common_minima2): @@ -71,7 +61,8 @@ def test_easom_output(common_minima2): def test_eggholder_output(common_minima2): """Tests eggholder function output.""" assert np.isclose( - fx.eggholder([512, 404.3219] * common_minima2), (-959.6407 * np.ones(3)) + fx.eggholder([512, 404.3219] * common_minima2), + (-959.6407 * np.ones(3)), ).all() @@ -85,39 +76,40 @@ def test_goldstein_output(common_minima2): @pytest.mark.parametrize( "x", [ - np.array([[3.0, 2.0], - [-2.805118, 3.131312], - [-3.779310, -3.283186], - [3.584428, -1.848126]]) + np.array( + [ + [3.0, 2.0], + [-2.805118, 3.131312], + [-3.779310, -3.283186], + [3.584428, -1.848126], + ] + ) ], ) def test_himmelblau_output(x): """Tests himmelblau function output.""" - assert np.isclose( - fx.himmelblau(x), np.zeros(4) - ).all() + assert np.isclose(fx.himmelblau(x), np.zeros(4)).all() @pytest.mark.parametrize( "x", [ - np.array([[8.05502, 9.66459], - [-8.05502, 9.66459], - [8.05502, -9.66459], - [-8.05502, -9.66459]]) + np.array( + [ + [8.05502, 9.66459], + [-8.05502, 9.66459], + [8.05502, -9.66459], + [-8.05502, -9.66459], + ] + ) ], ) @pytest.mark.parametrize( - "minima", - [ - np.array([-19.2085, -19.2085, -19.2085, -19.2085]) - ], + "minima", [np.array([-19.2085, -19.2085, -19.2085, -19.2085])] ) def test_holdertable_output(x, minima): """Tests holdertable function output.""" - assert np.isclose( - fx.holdertable(x), minima - ).all() + assert np.isclose(fx.holdertable(x), minima).all() def test_levi_output(common_minima2): diff --git a/travis_pypi_setup.py b/travis_pypi_setup.py index 844491f9..a0354fde 100644 --- a/travis_pypi_setup.py +++ b/travis_pypi_setup.py @@ -20,9 +20,10 @@ from urllib.request import urlopen -GITHUB_REPO = 'ljvmiranda921/pyswarms' +GITHUB_REPO = "ljvmiranda921/pyswarms" TRAVIS_CONFIG_FILE = os.path.join( - os.path.dirname(os.path.abspath(__file__)), '.travis.yml') + os.path.dirname(os.path.abspath(__file__)), ".travis.yml" +) def load_key(pubkey): @@ -37,7 +38,7 @@ def load_key(pubkey): return load_pem_public_key(pubkey.encode(), default_backend()) except ValueError: # workaround for https://github.com/travis-ci/travis-api/issues/196 - pubkey = pubkey.replace('BEGIN RSA', 'BEGIN').replace('END RSA', 'END') + pubkey = pubkey.replace("BEGIN RSA", "BEGIN").replace("END RSA", "END") return load_pem_public_key(pubkey.encode(), default_backend()) @@ -57,13 +58,13 @@ def fetch_public_key(repo): Travis API docs: http://docs.travis-ci.com/api/#repository-keys """ - keyurl = 'https://api.travis-ci.org/repos/{0}/key'.format(repo) + keyurl = "https://api.travis-ci.org/repos/{0}/key".format(repo) data = json.loads(urlopen(keyurl).read().decode()) - if 'key' not in data: + if "key" not in data: errmsg = "Could not find public key for repo: {}.\n".format(repo) errmsg += "Have you already added your GitHub repo to Travis?" raise ValueError(errmsg) - return data['key'] + return data["key"] def prepend_line(filepath, line): @@ -73,7 +74,7 @@ def prepend_line(filepath, line): lines.insert(0, line) - with open(filepath, 'w') as f: + with open(filepath, "w") as f: f.writelines(lines) @@ -85,7 +86,7 @@ def load_yaml_config(filepath): def save_yaml_config(filepath, config): """Save yaml config file at the given path.""" - with open(filepath, 'w') as f: + with open(filepath, "w") as f: yaml.dump(config, f, default_flow_style=False) @@ -93,12 +94,14 @@ def update_travis_deploy_password(encrypted_password): """Put `encrypted_password` into the deploy section of .travis.yml.""" config = load_yaml_config(TRAVIS_CONFIG_FILE) - config['deploy']['password'] = dict(secure=encrypted_password) + config["deploy"]["password"] = dict(secure=encrypted_password) save_yaml_config(TRAVIS_CONFIG_FILE, config) - line = ('# This file was autogenerated and will overwrite' - ' each time you run travis_pypi_setup.py\n') + line = ( + "# This file was autogenerated and will overwrite" + " each time you run travis_pypi_setup.py\n" + ) prepend_line(TRAVIS_CONFIG_FILE, line) @@ -110,18 +113,23 @@ def main(args): password. """ public_key = fetch_public_key(args.repo) - password = args.password or getpass('PyPI password: ') + password = args.password or getpass("PyPI password: ") update_travis_deploy_password(encrypt(public_key, password.encode())) print("Wrote encrypted password to .travis.yml -- you're ready to deploy") -if '__main__' == __name__: +if "__main__" == __name__: import argparse + parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('--repo', default=GITHUB_REPO, - help='GitHub repo (default: %s)' % GITHUB_REPO) - parser.add_argument('--password', - help='PyPI password (will prompt if not provided)') + parser.add_argument( + "--repo", + default=GITHUB_REPO, + help="GitHub repo (default: %s)" % GITHUB_REPO, + ) + parser.add_argument( + "--password", help="PyPI password (will prompt if not provided)" + ) args = parser.parse_args() main(args)