diff --git a/docs/examples/tutorials/basic_optimization.ipynb b/docs/examples/tutorials/basic_optimization.ipynb index 3f08b12c..17d0a82a 100644 --- a/docs/examples/tutorials/basic_optimization.ipynb +++ b/docs/examples/tutorials/basic_optimization.ipynb @@ -57,17 +57,17 @@ "name": "stderr", "output_type": "stream", "text": [ - "2019-05-18 15:39:13,096 - pyswarms.single.global_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n", - "pyswarms.single.global_best: 100%|██████████|1000/1000, best_cost=1.09e-41\n", - "2019-05-18 15:39:25,448 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 1.093473857947962e-41, best pos: [3.27682830e-21 4.43998725e-22]\n" + "2022-06-15 20:30:29,083 - pyswarms.single.global_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n", + "pyswarms.single.global_best: 100%|██████████|1000/1000, best_cost=2.11e-44\n", + "2022-06-15 20:30:30,741 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 2.113549046343125e-44, best pos: [ 4.27475005e-24 -1.45317642e-22]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 3.02 s, sys: 774 ms, total: 3.79 s\n", - "Wall time: 12.4 s\n" + "CPU times: user 1.58 s, sys: 690 ms, total: 2.27 s\n", + "Wall time: 1.67 s\n" ] } ], @@ -106,17 +106,17 @@ "name": "stderr", "output_type": "stream", "text": [ - "2019-05-18 15:39:25,476 - pyswarms.single.local_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2}\n", - "pyswarms.single.local_best: 100%|██████████|1000/1000, best_cost=3.28e-41\n", - "2019-05-18 15:39:37,110 - pyswarms.single.local_best - INFO - Optimization finished | best cost: 3.275639739592901e-41, best pos: [-5.62944989e-21 -1.40094066e-21]\n" + "2022-06-15 20:30:32,269 - pyswarms.single.local_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9, 'k': 2, 'p': 2}\n", + "pyswarms.single.local_best: 100%|██████████|1000/1000, best_cost=7.47e-41\n", + "2022-06-15 20:30:34,533 - pyswarms.single.local_best - INFO - Optimization finished | best cost: 7.468717233493547e-41, best pos: [ 2.48289631e-21 -8.27782569e-21]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 1.93 s, sys: 271 ms, total: 2.2 s\n", - "Wall time: 11.6 s\n" + "CPU times: user 2.36 s, sys: 741 ms, total: 3.1 s\n", + "Wall time: 2.28 s\n" ] } ], @@ -179,17 +179,17 @@ "name": "stderr", "output_type": "stream", "text": [ - "2019-05-18 15:39:37,279 - pyswarms.single.global_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n", + "2022-06-15 20:30:38,419 - pyswarms.single.global_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n", "pyswarms.single.global_best: 100%|██████████|1000/1000, best_cost=0 \n", - "2019-05-18 15:39:48,976 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 0.0, best pos: [-1.11729550e-09 3.10827139e-09]\n" + "2022-06-15 20:30:40,267 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 0.0, best pos: [-2.90016642e-09 -9.57646361e-10]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 1.95 s, sys: 254 ms, total: 2.21 s\n", - "Wall time: 11.7 s\n" + "CPU times: user 1.96 s, sys: 628 ms, total: 2.59 s\n", + "Wall time: 1.89 s\n" ] } ], @@ -257,9 +257,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "2019-05-18 15:39:49,204 - pyswarms.single.global_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n", - "pyswarms.single.global_best: 100%|██████████|1000/1000, best_cost=7.02e-10\n", - "2019-05-18 15:40:01,463 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 7.019703679797182e-10, best pos: [1.0000264 1.00005302]\n" + "2022-06-15 20:30:43,771 - pyswarms.single.global_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n", + "pyswarms.single.global_best: 100%|██████████|1000/1000, best_cost=1.67e-22\n", + "2022-06-15 20:30:46,380 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 1.6717623626876796e-22, best pos: [1. 1.]\n" ] } ], @@ -294,9 +294,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "2019-05-18 15:40:01,475 - pyswarms.single.global_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n", - "pyswarms.single.global_best: 100%|██████████|1000/1000, best_cost=0 \n", - "2019-05-18 15:40:13,805 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 0.0, best pos: [1. 1.]\n" + "2022-06-15 20:30:49,187 - pyswarms.single.global_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n", + "pyswarms.single.global_best: 100%|██████████|1000/1000, best_cost=7.89e-31\n", + "2022-06-15 20:30:51,293 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 7.888609052210118e-31, best pos: [1. 1.]\n" ] } ], @@ -321,21 +321,107 @@ "name": "stderr", "output_type": "stream", "text": [ - "2019-05-18 15:40:13,819 - pyswarms.single.global_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n", - "pyswarms.single.global_best: 100%|██████████|1000/1000, best_cost=0\n", - "2019-05-18 15:40:25,963 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 0.0, best pos: [1. 1.]\n" + "2022-06-15 20:30:57,250 - pyswarms.single.global_best - INFO - Optimize for 1000 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n", + "pyswarms.single.global_best: 100%|██████████|1000/1000, best_cost=7.89e-31\n", + "2022-06-15 20:30:59,256 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 7.888609052210118e-31, best pos: [1. 1.]\n" ] } ], "source": [ "cost, pos = optimizer.optimize(rosenbrock_with_args, 1000, a=1, b=100)" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Modifying reporter at iterations" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "def reporter_callback(swarm, reporter):\n", + " \"A custom callback function\"\n", + " reporter.hook(swarm=swarm) #add the default behaviour (postfix to tqdm)\n", + " print('Best position:', swarm.best_pos)\n", + " return\n", + "\n", + "# 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": 13, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-06-15 20:32:31,697 - pyswarms.single.global_best - INFO - Optimize for 10 iters with {'c1': 0.5, 'c2': 0.3, 'w': 0.9}\n", + "pyswarms.single.global_best: 100%|██████████|10/10, best_cost=0.424\n", + "2022-06-15 20:32:31,717 - pyswarms.single.global_best - INFO - Optimization finished | best cost: 0.4237618526034055, best pos: [-0.03887785 0.02516484]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Best position: [1.8470209 3.1831133]\n", + "Best position: [0.9647154 0.67466656]\n", + "Best position: [-0.80333013 0.03822154]\n", + "Best position: [-0.80333013 0.03822154]\n", + "Best position: [0.89995086 0.89942345]\n", + "Best position: [0.89995086 0.89942345]\n", + "Best position: [0.89995086 0.89942345]\n", + "Best position: [0.89995086 0.89942345]\n", + "Best position: [-0.03887785 0.02516484]\n", + "Best position: [-0.03887785 0.02516484]\n", + "CPU times: user 24.1 ms, sys: 12 ms, total: 36.2 ms\n", + "Wall time: 26 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "# Initialize swarm\n", + "options = {'c1': 0.5, 'c2': 0.3, 'w':0.9}\n", + "\n", + "# Call instance of PSO with bounds argument\n", + "optimizer = ps.single.GlobalBestPSO(\n", + " n_particles=10, \n", + " dimensions=2, \n", + " options=options, \n", + " bounds=bounds,\n", + " reporter_callback=reporter_callback,\n", + ")\n", + "\n", + "# Perform optimization\n", + "cost, pos = optimizer.optimize(fx.rastrigin, iters=10)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "anaconda-cloud": {}, + "interpreter": { + "hash": "f513a0bf0d27faed0401583855d8d7225d1dab65dd440ea970d3f25fb025c381" + }, "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3.9.7 ('base')", "language": "python", "name": "python3" }, @@ -349,7 +435,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.8" + "version": "3.9.7" } }, "nbformat": 4, diff --git a/pyswarms/backend/handlers.py b/pyswarms/backend/handlers.py index 61680f5c..09249147 100644 --- a/pyswarms/backend/handlers.py +++ b/pyswarms/backend/handlers.py @@ -556,7 +556,7 @@ def __init__(self, strategy): * exp_decay: Decreases the parameter exponentially between limits. - + * lin_variation: Decreases/increases the parameter linearly between limits. @@ -584,14 +584,14 @@ def __init__(self, strategy): # more updates using new_options .. note:: - As of pyswarms v1.3.0, you will need to create your own optimization loop to change the default ending + As of pyswarms v1.3.0, you will need to create your own optimization loop to change the default ending options and other arguments for each strategy in all of the handlers on this page. A more comprehensive tutorial is also present `here`_ for interested users. - + .. _here: https://pyswarms.readthedocs.io/en/latest/examples/tutorials/options_handler.html - - + + Attributes ---------- @@ -625,12 +625,12 @@ def __call__(self, start_opts, **kwargs): def exp_decay(self, start_opts, opt, **kwargs): """Exponentially decreasing between :math:`w_{start}` and :math:`w_{end}` The velocity is adjusted such that the following equation holds: - + Defaults: :math:`d_{1}=2, d_{2}=7, w^{end} = 0.4, c^{end}_{1} = 0.8 * c^{start}_{1}, c^{end}_{2} = c^{start}_{2}` .. math:: w = (w^{start}-w^{end}-d_{1})exp(\\frac{1}{1+ \\frac{d_{2}.iter}{iter^{max}}}) - + Ref: Li, H.-R., & Gao, Y.-L. (2009). Particle Swarm Optimization Algorithm with Exponent Decreasing Inertia Weight and Stochastic Mutation. 2009 Second International Conference on Information and Computing Science. doi:10.1109/icic.2009.24 @@ -670,14 +670,14 @@ def exp_decay(self, start_opts, opt, **kwargs): def lin_variation(self, start_opts, opt, **kwargs): """ Linearly decreasing/increasing between :math:`w_{start}` and :math:`w_{end}` - + Defaults: :math:`w^{end} = 0.4, c^{end}_{1} = 0.8 * c^{start}_{1}, c^{end}_{2} = c^{start}_{2}` - + .. math:: w = w^{end}+(w^{start}-w^{end}) \\frac{iter^{max}-iter}{iter^{max}} - Ref: Xin, Jianbin, Guimin Chen, and Yubao Hai. "A particle swarm optimizer with - multi-stage linearly-decreasing inertia weight." 2009 International joint conference + Ref: Xin, Jianbin, Guimin Chen, and Yubao Hai. "A particle swarm optimizer with + multi-stage linearly-decreasing inertia weight." 2009 International joint conference on computational sciences and optimization. Vol. 1. IEEE, 2009. """ @@ -709,11 +709,11 @@ def random(self, start_opts, opt, **kwargs): .. math:: w = start + (end-start)*rand(0,1) - + Ref: R.C. Eberhart, Y.H. Shi, Tracking and optimizing dynamic systems with particle swarms, in: Congress on Evolutionary Computation, Korea, 2001 """ - + start = start_opts[opt] if opt in kwargs["end_opts"]: end = kwargs["end_opts"][opt] diff --git a/pyswarms/discrete/binary.py b/pyswarms/discrete/binary.py index ed20b8f3..a614077d 100644 --- a/pyswarms/discrete/binary.py +++ b/pyswarms/discrete/binary.py @@ -78,6 +78,7 @@ def __init__( vh_strategy="unmodified", ftol=-np.inf, ftol_iter=1, + reporter_callback=None, ): """Initialize the swarm @@ -120,9 +121,18 @@ def __init__( number of iterations over which the relative error in objective_func(best_pos) is acceptable for convergence. Default is :code:`1` + reporter_callback : callable, optional + callback function to call at end of each iteration. The signature should + be: + :code:`reporter_callback(swarm, reporter)` + :code:`None` will print the best cost as postfix in tqdm. """ # Initialize logger self.rep = Reporter(logger=logging.getLogger(__name__)) + if reporter_callback is None: + self.reporter_callback = self.rep.hook + else: + self.reporter_callback = reporter_callback # Assign k-neighbors and p-value as attributes self.k, self.p = options["k"], options["p"] # Initialize parent class @@ -205,7 +215,7 @@ def optimize( ) if verbose: # Print to console - self.rep.hook(best_cost=self.swarm.best_cost) + self.reporter_callback(swarm=self.swarm, reporter=self.rep) # Save to history hist = self.ToHistory( best_cost=self.swarm.best_cost, diff --git a/pyswarms/single/general_optimizer.py b/pyswarms/single/general_optimizer.py index a46d3ed6..ec8d220a 100644 --- a/pyswarms/single/general_optimizer.py +++ b/pyswarms/single/general_optimizer.py @@ -88,6 +88,7 @@ def __init__( ftol=-np.inf, ftol_iter=1, init_pos=None, + reporter_callback=None, ): """Initialize the swarm @@ -166,6 +167,11 @@ def __init__( init_pos : numpy.ndarray, optional option to explicitly set the particles' initial positions. Set to :code:`None` if you wish to generate the particles randomly. + reporter_callback : callable, optional + callback function to call at end of each iteration. The signature should + be: + :code:`reporter_callback(swarm, reporter)` + :code:`None` will print the best cost as postfix in tqdm. """ super(GeneralOptimizerPSO, self).__init__( n_particles, @@ -182,6 +188,10 @@ def __init__( oh_strategy = {} # Initialize logger self.rep = Reporter(logger=logging.getLogger(__name__)) + if reporter_callback is None: + self.reporter_callback = self.rep.hook + else: + self.reporter_callback = reporter_callback # Initialize the resettable attributes self.reset() # Initialize the topology and check for type @@ -254,7 +264,7 @@ def optimize( ) # Print to console if verbose: - self.rep.hook(best_cost=self.swarm.best_cost) + self.reporter_callback(swarm=self.swarm, reporter=self.rep) hist = self.ToHistory( best_cost=self.swarm.best_cost, mean_pbest_cost=np.mean(self.swarm.pbest_cost), diff --git a/pyswarms/single/global_best.py b/pyswarms/single/global_best.py index 3392bfb3..45b4d521 100644 --- a/pyswarms/single/global_best.py +++ b/pyswarms/single/global_best.py @@ -86,6 +86,7 @@ def __init__( ftol=-np.inf, ftol_iter=1, init_pos=None, + reporter_callback=None, ): """Initialize the swarm @@ -130,6 +131,11 @@ def __init__( init_pos : numpy.ndarray, optional option to explicitly set the particles' initial positions. Set to :code:`None` if you wish to generate the particles randomly. + reporter_callback : callable, optional + callback function to call at end of each iteration. The signature should + be: + :code:`reporter_callback(swarm, reporter)` + :code:`None` will print the best cost as postfix in tqdm. """ super(GlobalBestPSO, self).__init__( n_particles=n_particles, @@ -147,6 +153,10 @@ def __init__( oh_strategy = {} # Initialize logger self.rep = Reporter(logger=logging.getLogger(__name__)) + if reporter_callback is None: + self.reporter_callback = self.rep.hook + else: + self.reporter_callback = reporter_callback # Initialize the resettable attributes self.reset() # Initialize the topology @@ -213,7 +223,7 @@ def optimize( self.swarm.best_pos, self.swarm.best_cost = self.top.compute_gbest(self.swarm) # fmt: on if verbose: - self.rep.hook(best_cost=self.swarm.best_cost) + self.reporter_callback(swarm=self.swarm, reporter=self.rep) # Save to history hist = self.ToHistory( best_cost=self.swarm.best_cost, diff --git a/pyswarms/single/local_best.py b/pyswarms/single/local_best.py index 146442d7..412f8611 100644 --- a/pyswarms/single/local_best.py +++ b/pyswarms/single/local_best.py @@ -96,6 +96,7 @@ def __init__( ftol_iter=1, init_pos=None, static=False, + reporter_callback=None, ): """Initialize the swarm @@ -150,6 +151,11 @@ def __init__( static: bool a boolean that decides whether the Ring topology used is static or dynamic. Default is `False` + reporter_callback : callable, optional + callback function to call at end of each iteration. The signature should + be: + :code:`reporter_callback(swarm, reporter)` + :code:`None` will print the best cost as postfix in tqdm. """ if oh_strategy is None: oh_strategy = {} @@ -171,6 +177,10 @@ def __init__( ) # Initialize logger self.rep = Reporter(logger=logging.getLogger(__name__)) + if reporter_callback is None: + self.reporter_callback = self.rep.hook + else: + self.reporter_callback = reporter_callback # Initialize the resettable attributes self.reset() # Initialize the topology @@ -241,7 +251,8 @@ def optimize( self.swarm, p=self.p, k=self.k ) if verbose: - self.rep.hook(best_cost=np.min(self.swarm.best_cost)) + # self.rep.hook(best_cost=np.min(self.swarm.best_cost)) + self.reporter_callback(swarm=self.swarm, reporter=self.rep) # Save to history hist = self.ToHistory( best_cost=self.swarm.best_cost, diff --git a/pyswarms/utils/functions/single_obj.py b/pyswarms/utils/functions/single_obj.py index aa34a2ca..97c7fa01 100644 --- a/pyswarms/utils/functions/single_obj.py +++ b/pyswarms/utils/functions/single_obj.py @@ -67,7 +67,7 @@ def ackley(x): d = x.shape[1] j = ( - -20.0 * np.exp(-0.2 * np.sqrt((1 / d) * (x ** 2).sum(axis=1))) + -20.0 * np.exp(-0.2 * np.sqrt((1 / d) * (x**2).sum(axis=1))) - np.exp((1 / float(d)) * np.cos(2 * np.pi * x).sum(axis=1)) + 20.0 + np.exp(1) @@ -112,8 +112,8 @@ def beale(x): y_ = x[:, 1] j = ( (1.5 - x_ + x_ * y_) ** 2.0 - + (2.25 - x_ + x_ * y_ ** 2.0) ** 2.0 - + (2.625 - x_ + x_ * y_ ** 3.0) ** 2.0 + + (2.25 - x_ + x_ * y_**2.0) ** 2.0 + + (2.625 - x_ + x_ * y_**3.0) ** 2.0 ) return j @@ -198,7 +198,7 @@ def bukin6(x): x_ = x[:, 0] y_ = x[:, 1] - j = 100 * np.sqrt(np.absolute(y_ - 0.01 * x_ ** 2.0)) + 0.01 * np.absolute( + j = 100 * np.sqrt(np.absolute(y_ - 0.01 * x_**2.0)) + 0.01 * np.absolute( x_ + 10 ) @@ -250,7 +250,7 @@ def crossintray(x): np.abs( np.sin(x_) * np.sin(y_) - * np.exp(np.abs(100 - (np.sqrt(x_ ** 2 + y_ ** 2) / np.pi))) + * np.exp(np.abs(100 - (np.sqrt(x_**2 + y_**2) / np.pi))) ) + 1, 0.1, @@ -398,10 +398,10 @@ def goldstein(x): * ( 19 - 14 * x_ - + 3 * x_ ** 2.0 + + 3 * x_**2.0 - 14 * y_ + 6 * x_ * y_ - + 3 * y_ ** 2.0 + + 3 * y_**2.0 ) ) * ( 30 @@ -409,10 +409,10 @@ def goldstein(x): * ( 18 - 32 * x_ - + 12 * x_ ** 2.0 + + 12 * x_**2.0 + 48 * y_ - 36 * x_ * y_ - + 27 * y_ ** 2.0 + + 27 * y_**2.0 ) ) @@ -460,7 +460,7 @@ def himmelblau(x): x_ = x[:, 0] y_ = x[:, 1] - j = (x_ ** 2 + y_ - 11) ** 2 + (x_ + y_ ** 2 - 7) ** 2 + j = (x_**2 + y_ - 11) ** 2 + (x_ + y_**2 - 7) ** 2 return j @@ -509,7 +509,7 @@ def holdertable(x): j = -np.abs( np.sin(x_) * np.cos(y_) - * np.exp(np.abs(1 - np.sqrt(x_ ** 2 + y_ ** 2) / np.pi)) + * np.exp(np.abs(1 - np.sqrt(x_**2 + y_**2) / np.pi)) ) return j @@ -589,7 +589,7 @@ def matyas(x): x_ = x[:, 0] y_ = x[:, 1] - j = 0.26 * (x_ ** 2.0 + y_ ** 2.0) - 0.48 * x_ * y_ + j = 0.26 * (x_**2.0 + y_**2.0) - 0.48 * x_ * y_ return j @@ -622,7 +622,7 @@ def rastrigin(x): ) d = x.shape[1] - j = 10.0 * d + (x ** 2.0 - 10.0 * np.cos(2.0 * np.pi * x)).sum(axis=1) + j = 10.0 * d + (x**2.0 - 10.0 * np.cos(2.0 * np.pi * x)).sum(axis=1) return j @@ -691,8 +691,8 @@ def schaffer2(x): x_ = x[:, 0] y_ = x[:, 1] j = 0.5 + ( - (np.sin(x_ ** 2.0 - y_ ** 2.0) ** 2.0 - 0.5) - / ((1 + 0.001 * (x_ ** 2.0 + y_ ** 2.0)) ** 2.0) + (np.sin(x_**2.0 - y_**2.0) ** 2.0 - 0.5) + / ((1 + 0.001 * (x_**2.0 + y_**2.0)) ** 2.0) ) return j @@ -714,7 +714,7 @@ def sphere(x): numpy.ndarray computed cost of size :code:`(n_particles, )` """ - j = (x ** 2.0).sum(axis=1) + j = (x**2.0).sum(axis=1) return j @@ -759,6 +759,6 @@ def threehump(x): x_ = x[:, 0] y_ = x[:, 1] - j = 2 * x_ ** 2 - 1.05 * (x_ ** 4) + (x_ ** 6) / 6 + x_ * y_ + y_ ** 2 + j = 2 * x_**2 - 1.05 * (x_**4) + (x_**6) / 6 + x_ * y_ + y_**2 return j diff --git a/pyswarms/utils/reporter/reporter.py b/pyswarms/utils/reporter/reporter.py index b7c6a132..0a8deafb 100644 --- a/pyswarms/utils/reporter/reporter.py +++ b/pyswarms/utils/reporter/reporter.py @@ -4,6 +4,7 @@ import logging.config import os import pprint +import numpy as np # Import modules import yaml @@ -233,4 +234,6 @@ def hook(self, *args, **kwargs): best_cost = compute() rep.hook(best_cost=best_cost) """ - self.t.set_postfix(*args, **kwargs) + # Default behaviour only outputs best cost + swarm = kwargs.get("swarm") + self.t.set_postfix(dict(best_cost=np.min(swarm.best_cost))) diff --git a/tests/optimizers/test_general_optimizer.py b/tests/optimizers/test_general_optimizer.py index cdb72476..b72c1e39 100644 --- a/tests/optimizers/test_general_optimizer.py +++ b/tests/optimizers/test_general_optimizer.py @@ -106,7 +106,7 @@ def test_obj_incorrect_kwargs(self, obj_with_args, optimizer): cost, pos = optimizer.optimize(obj_with_args, 1000, c=1, d=100) def test_general_correct_pos(self, options, optimizer): - """ Test to check general optimiser returns the correct position corresponding to the best cost """ + """Test to check general optimiser returns the correct position corresponding to the best cost""" cost, pos = optimizer.optimize(sphere, iters=5) # find best pos from history min_cost_idx = np.argmin(optimizer.cost_history) diff --git a/tests/optimizers/test_global_best.py b/tests/optimizers/test_global_best.py index 1f32fc67..ba93ca55 100644 --- a/tests/optimizers/test_global_best.py +++ b/tests/optimizers/test_global_best.py @@ -31,10 +31,26 @@ def optimizer_reset(self, options): return opt def test_global_correct_pos(self, options): - """ Test to check global optimiser returns the correct position corresponding to the best cost """ + """Test to check global optimiser returns the correct position corresponding to the best cost""" opt = GlobalBestPSO(n_particles=10, dimensions=2, options=options) cost, pos = opt.optimize(sphere, iters=5) # find best pos from history min_cost_idx = np.argmin(opt.cost_history) min_pos_idx = np.argmin(sphere(opt.pos_history[min_cost_idx])) assert np.array_equal(opt.pos_history[min_cost_idx][min_pos_idx], pos) + + def test_global_correct_pos_with_custom_reporter(self, options, capfd): + """Test if custom reporter callback is printing to screen""" + + def custom_reporter_cb(swarm, reporter): + print("First position: ", swarm.best_pos[0]) + + opt = GlobalBestPSO( + n_particles=10, + dimensions=2, + options=options, + reporter_callback=custom_reporter_cb, + ) + cost, pos = opt.optimize(sphere, iters=5) + out, err = capfd.readouterr() + assert "First position" in out diff --git a/tests/optimizers/test_local_best.py b/tests/optimizers/test_local_best.py index 3650e697..6503a956 100644 --- a/tests/optimizers/test_local_best.py +++ b/tests/optimizers/test_local_best.py @@ -31,7 +31,7 @@ def optimizer_reset(self, options): return opt def test_local_correct_pos(self, options): - """ Test to check local optimiser returns the correct position corresponding to the best cost """ + """Test to check local optimiser returns the correct position corresponding to the best cost""" opt = LocalBestPSO(n_particles=10, dimensions=2, options=options) cost, pos = opt.optimize(sphere, iters=5) # find best pos from history