<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Options Handler Tutorial
Varying options with time is a well regarded technique in particle swarm optimization for faster convergence and
better solutions. This class exposes methods to do the same.
In this example, we will demonstrate some common variation techniques along with some visualisation.
- oh_strategy
Step1:  Let's create some optimizers for comparison. Here, we're going to use Global-best PSO to find the minima
of a sphere function. As usual, we simply create an instance of its class pyswarms.single.GlobalBestPSO
by passing the required parameters that we will use. Then, we'll call the optimize() method for 100 iterations for both and visualise the results
Step2:  Comparing the cost history
To plot the cost history, we simply obtain the cost_history from the optimizer class and pass it to the cost_history function. In addition, we can obtain the following histories from the same class
Step3:  The rapid decay of the inertia weight contributes significantly to the overall best cost and position. It also converges a lot faster.
The next part shows the explanation for this with an animation
Comparing animations
The plotters module offers two methods to perform animation, plot_contour(). This method plot the particles in a 2-D space.
The objective function contours are added using the Mesher class.
Step4:  Plotting in 2-D space
We can obtain the swarm's position history using the pos_history attribute from the optimizer instance. To plot a 2D-contour, simply pass this together with the Mesher to the plot_contour() function. In addition, we can also mark the global minima of the sphere function, (0,0), to visualize the swarm's "target".
Step5:  Compare the two animations. Observe the convergence time and particle overshoot in both figures.
Left
Step6:  In the next cell, you can play around with the start and end options, maximum iterations and the function itself to compare the outputs like above.
<ASSISTANT_TASK:>
Python Code:
# Import modules
import matplotlib.pyplot as plt
import numpy as np
from IPython.display import Image
# Import PySwarms
import pyswarms as ps
from pyswarms.utils.functions import single_obj as fx
from pyswarms.utils.plotters import (plot_cost_history, plot_contour)
from pyswarms.backend.handlers import OptionsHandler
Explanation: Options Handler Tutorial
Varying options with time is a well regarded technique in particle swarm optimization for faster convergence and
better solutions. This class exposes methods to do the same.
In this example, we will demonstrate some common variation techniques along with some visualisation.
- oh_strategy: a dictionary containing the strategies for each option
- end_opts: a dictionary containing the ending options for each option
- plot_cost_history: for plotting the cost history of a swarm given a matrix
- plot_contour: for plotting swarm trajectories of a 2D-swarm in two-dimensional space
End of explanation
options = {'c1':0.5, 'c2':0.3, 'w':0.9}  # starting options
optimizer_without_handle=ps.single.GlobalBestPSO(n_particles=50, dimensions=2, options=options)
optimizer_with_handle = ps.single.GlobalBestPSO(n_particles=50, dimensions=2, options=options, oh_strategy={"w":'exp_decay', 'c1':'lin_variation'})
cost, pos = optimizer_without_handle.optimize(fx.sphere, iters=100)
cost_h, pos_h = optimizer_with_handle.optimize(fx.sphere, iters=100)
Explanation: Let's create some optimizers for comparison. Here, we're going to use Global-best PSO to find the minima
of a sphere function. As usual, we simply create an instance of its class pyswarms.single.GlobalBestPSO
by passing the required parameters that we will use. Then, we'll call the optimize() method for 100 iterations for both and visualise the results
End of explanation
fig, (ax, ax_h) = plt.subplots(ncols=2, nrows=1)
fig.set_size_inches(15,7)
plot_cost_history(ax=ax, cost_history=optimizer_without_handle.cost_history)
plot_cost_history(ax=ax_h, cost_history=optimizer_with_handle.cost_history)
ax.set_title("Cost history without inertia decay")
ax_h.set_title("Cost history with exponential intertia decay")
plt.show()
Explanation: Comparing the cost history
To plot the cost history, we simply obtain the cost_history from the optimizer class and pass it to the cost_history function. In addition, we can obtain the following histories from the same class:
- mean_neighbor_history: average local best history of all neighbors throughout optimization
- mean_pbest_history: average personal best of the particles throughout optimization
End of explanation
from pyswarms.utils.plotters.formatters import Mesher
# Initialize mesher with sphere function
m = Mesher(func=fx.sphere)
Explanation: The rapid decay of the inertia weight contributes significantly to the overall best cost and position. It also converges a lot faster.
The next part shows the explanation for this with an animation
Comparing animations
The plotters module offers two methods to perform animation, plot_contour(). This method plot the particles in a 2-D space.
The objective function contours are added using the Mesher class.
End of explanation
%%capture
# Make and save animation
animation = plot_contour(pos_history=optimizer_without_handle.pos_history,
                         mesher=m,
                         mark=(0,0))
animation_h = plot_contour(pos_history=optimizer_with_handle.pos_history,
                         mesher=m,
                         mark=(0,0))
# Enables us to view it in a Jupyter notebook
animation.save('ani.gif', writer='imagemagick', fps=10)
animation_h.save('ani_h.gif', writer='imagemagick', fps=10)
Explanation: Plotting in 2-D space
We can obtain the swarm's position history using the pos_history attribute from the optimizer instance. To plot a 2D-contour, simply pass this together with the Mesher to the plot_contour() function. In addition, we can also mark the global minima of the sphere function, (0,0), to visualize the swarm's "target".
End of explanation
from pyswarms.backend.operators import compute_pbest, compute_objective_function
def optimize(objective_func, maxiters, oh_strategy,start_opts, end_opts):
    opt = ps.single.GlobalBestPSO(n_particles=50, dimensions=2, options=start_opts, oh_strategy=oh_strategy)
    swarm = opt.swarm
    opt.bh.memory = swarm.position
    opt.vh.memory = swarm.position
    swarm.pbest_cost = np.full(opt.swarm_size[0], np.
    inf)
    for i in range(maxiters):
        # Compute cost for current position and personal best
        swarm.current_cost =  compute_objective_function(swarm, objective_func)
        swarm.pbest_pos, swarm.pbest_cost = compute_pbest(swarm)
        # Set best_cost_yet_found for ftol
        best_cost_yet_found = swarm.best_cost
        swarm.best_pos, swarm.best_cost = opt.top.compute_gbest(swarm)
        # Perform options update
        swarm.options = opt.oh( opt.options, iternow=i, itermax=maxiters, end_opts=end_opts )
        print("Iteration:", i," Options: ", swarm.options)    # print to see variation
        # Perform velocity and position updates
        swarm.velocity = opt.top.compute_velocity(
            swarm, opt.velocity_clamp, opt.vh, opt.bounds
        )
        swarm.position = opt.top.compute_position(
            swarm, opt.bounds, opt.bh
        )
    # Obtain the final best_cost and the final best_position
    final_best_cost = swarm.best_cost.copy()
    final_best_pos = swarm.pbest_pos[
        swarm.pbest_cost.argmin()
    ].copy()
    return final_best_cost, final_best_pos
Explanation: Compare the two animations. Observe the convergence time and particle overshoot in both figures.
Left: Without handle
Right: With handle
<img src="ani.gif" width="450" align="left">
<img src="ani_h.gif" width="450" align="right">
Customizing ending options
As of the current version(1.2.0), you'll need to create your own optimization loop to keep custom ending options.
The next block shows a basic implementation of this without logging etc.
End of explanation
function = fx.rosenbrock    # optimum at [1,1]
maxiters = 100
start_opts = {'c1':2.5, 'c2':0.5, 'w':0.9}
end_opts= {'c1':0.5, 'c2':2.5, 'w':0.4}     # Ref:[1]
oh_strategy={ "w":'exp_decay', "c1":'nonlin_mod',"c2":'lin_variation'}
cost, pos=optimize(function, maxiters, oh_strategy, start_opts, end_opts)
print("Best cost = ", cost)
print("Best position = ", pos)
Explanation: In the next cell, you can play around with the start and end options, maximum iterations and the function itself to compare the outputs like above.
End of explanation
<END_TASK>