Custom_PSO / custom_pso.py
raaraya's picture
Upload 6 files
7aab566 verified
'''
--------------------------------------------------------------
Custom PSO algorithm for continuous domains
--------------------------------------------------------------
Autor: Rodrigo Araya
Email: [email protected]
'''
import math
import numpy as np
import pandas as pd
from F_newton import F_newton
from F_coulomb import F_coulomb
import plotly.graph_objects as go
import plotly.express as px
def Random_(problem, x_, auto_reduce_search_space=False):
""" This solver generates a random solution for each particle. Additionally, it is also possible to
apply an exploitation method where the search space is reduced on each iteration.
Args:
problem (dic): Dictionary that include: objective function, lower bound and upper bound of each variable and optimal solution
x_ (array(size=())): Current position of each particle
auto_reduce_search_space (bool, optional): If True, it update the lower and upper bounds in a way to reduce the search space. Defaults to False.
Returns:
Stemp, S_f: New positions for each particle and their performance after being evaluated with the objective function.
"""
nPart = x_.shape[0]
nVar = x_.shape[1]
if auto_reduce_search_space:
Lo = np.min(x_, axis=0)
Up = np.max(x_, axis=0)
else:
Lo = np.zeros(nVar)
Up = np.ones(nVar)
new_x = np.random.uniform(low=Lo, high=Up, size=(nPart, nVar))
Stemp = np.zeros((nPart,nVar))
for k in range(nPart):
for i in range(nVar):
Stemp[k][i] = new_x[k][i]
if Stemp[k][i] > Up[i]:
Stemp[k][i] = Up[i]
elif Stemp[k][i] < Lo[i]:
Stemp[k][i] = Lo[i]
f,S_r,maximize = mp_evaluator(problem, Stemp)
S_f = np.zeros((nPart,1))
for i in range(len(S_r)):
S_f[i] = f[i]
return Stemp, S_f
def F_newton_(problem, x_, m, Lo, Up, G=0.00001, keep_best=True, weight_method='Linear', t=1.0, max_mass=100.0):
_, _, new_x = F_newton(x_, m, minimize=True, G=G, keep_best=keep_best, weight_method=weight_method, t=t, max_mass=max_mass)
nPart=x_.shape[0]
nVar=x_.shape[1]
Stemp = np.zeros((nPart,nVar))
for k in range(nPart):
for i in range(nVar):
Stemp[k][i] = new_x[k][i]
if Stemp[k][i] > Up[i]:
Stemp[k][i] = Up[i]
elif Stemp[k][i] < Lo[i]:
Stemp[k][i] = Lo[i]
f,S_r,maximize = mp_evaluator(problem, Stemp)
S_f = np.zeros((nPart,1))
for i in range(len(S_r)):
S_f[i] = f[i]
return Stemp, S_f
def F_coulomb_(problem, x_, v, q, P, Lo, Up, k=0.00001, weight_method='Linear', t=1.0, max_q=100.0):
_, _, v, new_x = F_coulomb(x_, v, q, P=P, minimize=True, k=k, weight_method=weight_method, t=t, max_q=max_q)
nPart=x_.shape[0]
nVar=x_.shape[1]
Stemp = np.zeros((nPart,nVar))
for k in range(nPart):
for i in range(nVar):
Stemp[k][i] = new_x[k][i]
if Stemp[k][i] > Up[i]:
Stemp[k][i] = Up[i]
elif Stemp[k][i] < Lo[i]:
Stemp[k][i] = Lo[i]
f,S_r,maximize = mp_evaluator(problem, Stemp)
S_f = np.zeros((nPart,1))
for i in range(len(S_r)):
S_f[i] = f[i]
return Stemp, v, S_f
def evaluator(problem, x):
# Dado que se trabaja bajo el dominio [0, 1] para cada variable, se debe crear una funcion que regrese a los valores a los dominios originales
# Ejemplo (ndim=2): si se tiene el dominio original [-5, 5] y [-2, 2] para la variables x1, x2 y se cambio a [0, 1] y [0, 1] se vuelve al original tras:
# y1=ax+b -> -5 = a*0+b -> b=-5
# y1=ax+b -> 5 = a*1+-5 -> a=10
# y1=10*x+-5
# y2=ax+b -> -2 = a*0+b -> b=-2
# y2=ax+b -> 2 = a*1+-2 -> a=4
# y2=4*x+-2
# Luego se aplica y1(x1) e y2(x2) respectivamente. Extendible a n dimensiones.
# Dado que [0, 1] no cambia, se generaliza la formula b=lb y a=ub-lb -> y_{i} = (ub-lb)_{i}*x + lb_{i}
lb = [var[0] for var in problem['bounds']]
ub = [var[1] for var in problem['bounds']]
x = [(ub[ind]-lb[ind])*i+lb[ind] for ind, i in enumerate(x)]
# calculate fitness
f = problem['f'](x)
fitness = dict(Obj=f)
return fitness
def mp_evaluator(problem, x):
results = [evaluator(problem, c) for c in x]
f = [r['Obj'] for r in results]
# maximization or minimization problem
maximize = False
return (f, [r for r in results],maximize)
def correct_x(problem, x_):
lb = [var[0] for var in problem['bounds']]
ub = [var[1] for var in problem['bounds']]
x = np.empty(x_.shape)
for ind, row in enumerate(x_):
corr_row = np.array([(ub[ind]-lb[ind])*i+lb[ind] for ind, i in enumerate(row)])
x[ind]=corr_row
return x
def custom_pso(problem, nPart, nVar, maxiter, G=0.00001, k=0.0001, keep_best=True, weight_method='Linear', t=1.0, seed=0, max_mass=100.0, solver='Newton', P=3, max_q=100.0, auto_reduce_search_space=False, dinamic=False):
"""The procedure of this algorithm is as follows:
1. Generate a file of size nSize=nPart.
2. Generate nPart initial solutions. Each solution contains nVar variables.
3. Evaluate the nPart solutions and add them to the file ordered from best to worst solution.
4. While the termination condition is not met (iterations > maxiter):
4.1 Generate new solutions using some solver. Options = ['Random', 'Newton', 'Coulomb']
4.2 Add new solutions to the file.
4.3 Remove duplicate solutions.
4.4 Evaluate solutions and sort from best to worst solution.
4.5 Keep in the file the nPar best solutions.
4.6 Save iteration results in a history (dataframe).
4.7 Evaluate termination condition. If negative, return to step 4.1.
Args:
problem (dic): Dictionary that include: objective function, lower bound and upper bound of each variable and optimal solution
nPart (_type_): Quantity of particles
nVar (_type_): Quantity of variables
maxiter (_type_): Maximum number of iterations.
seed (int, optional): set the generation of random numbers. Defaults to 0.
solver (str, optional): solver to apply. Defaults to 'Newton'. Options=['Random', 'Newton', 'Coulomb'].
Random Solver:
auto_reduce_search_space (bool, optional): If True, it update the lower and upper bounds in a way to reduce the search space. Defaults to False.
Newton Solver:
G (float, optional): Gravitational constant. Defaults to 0.00001.
keep_best (bool, optional): It will keep the best value obtained in each iteration. Defaults to True.
weight_method (str, optional): method to reassign particle mass. Defaults to 'Linear'. Options=['Linear', 'Quadratic', 'Exponential'].
t (float, optional): time. Defaults to 1.0.
max_mass (float, optional): upper bound of mass to assing. Defaults to 100.0.
dinamic (bool, optional): It will change the max_mass value depending on the current iteration and difference between best and worst value obteined. Defaults to False.
Coulomb Solver:
P (int): quantity of electric fields (the best P particles become electric fields)
max_q (float, optional): upper bound of electric charge to assing. Defaults to 100.0.
weight_method (str, optional): method to reassign electric charges. Defaults to 'Linear'. Options=['Linear', 'Quadratic', 'Exponential'].
k (float, optional): electric constant. Defaults to 0.0001.
t (float, optional): time. Defaults to 1.0.
dinamic (bool, optional): It will change the max_q value depending on the current iteration and difference between best and worst value obteined. Defaults to False.
Returns:
df, best_var, best_sol: dataframe contening data from all iterations, the best variables and the best value obtained
"""
# number of variables
parameters_v = [f'x{i+1}' for i in range(nVar)]
# number of variables
nVar = len(parameters_v)
# size of solution archive
nSize = nPart
# number of Particules
nPart = nPart
# maximum iterations
maxiter = maxiter
# bounds of variables
Up = [1]*nVar
Lo = [0]*nVar
# dinamic q
din_max_q=max_q
# dinamic mass
din_max_mass = max_mass
# initilize matrices
S = np.zeros((nSize,nVar))
S_f = np.zeros((nSize,1))
# initial velocity
v = np.zeros((nSize,nVar))
# history
columns_ = ['iter']
for i in parameters_v: columns_.append(i)
columns_.append('f')
df = pd.DataFrame(columns=columns_)
# generate first random solution
#np.random.seed(seed)
Srand = np.random.uniform(low=0,high=1,size=(nPart, nVar))
f,S_r,maximize = mp_evaluator(problem, Srand)
for i in range(len(S_r)):
S_f[i] = f[i]
# add responses and "fitness" column to solution
S = np.hstack((Srand, v, S_f))
# sort according to fitness (last column)
S = sorted(S, key=lambda row: row[-1],reverse = maximize)
S = np.array(S)
# save each iteration
iter_n = np.full((nPart, 1), 0.0)
x_ = S[:, 0:nVar]
x = correct_x(problem, x_)
res = np.reshape(S[:, -1], (nPart, 1))
rows=np.hstack((iter_n, x, res))
df_new = pd.DataFrame(rows, columns=columns_)
df = pd.concat([df, df_new])
iterations=1
# iterations
while True:
# get a new solution
if solver == "Random":
Stemp, S_f = Random_(problem, S[:, :nVar], auto_reduce_search_space=auto_reduce_search_space)
elif solver=="Newton":
din_mass=0
if dinamic:
din_mass = ((maxiter-iterations)/(maxiter))*(np.max(S_f)-np.min(S_f))
else:
din_mass=max_mass
m = np.reshape(S[:, -1], (nPart, 1))
Stemp, S_f = F_newton_(problem, S[:, :nVar], m, Lo, Up, G=G, keep_best=keep_best, weight_method=weight_method, t=t, max_mass=din_mass)
elif solver == "Coulomb":
din_q=0
if dinamic:
din_q = ((maxiter-iterations)/(maxiter))*(np.max(S_f)-np.min(S_f))
else:
din_q=max_q
q = np.reshape(S[:, -1], (nPart, 1))
Stemp, v, S_f = F_coulomb_(problem, S[:, :nVar], v, q, P, Lo, Up, k=k, weight_method=weight_method, t=t, max_q=din_q)
# add responses and "fitness" column to solution
Ssample = np.hstack((Stemp, v, S_f))
# add new solutions in the solutions table
Solution_temp = np.vstack((S,Ssample))
# delate duplicated rows
Solution_temp = np.unique(Solution_temp, axis=0)
# sort according to "fitness"
Solution_temp = sorted(Solution_temp, key=lambda row: row[-1],reverse = maximize)
Solution_temp = np.array(Solution_temp)
# keep best solutions
S = Solution_temp[:nSize][:]
# save each iteration
iter_n = np.full((nPart, 1), iterations)
x_ = S[:, 0:nVar]
x = correct_x(problem, x_)
res = np.reshape(S[:, -1], (nPart, 1))
rows=np.hstack((iter_n, x, res))
df_new = pd.DataFrame(rows, columns=columns_)
df = pd.concat([df, df_new])
iterations += 1
if iterations > maxiter:
break
best_sol = np.min(df['f'])
ind_best_sol = np.argmin(df['f'])
best_var = df.iloc[ind_best_sol, 1:len(parameters_v)+1]
return df, best_var, best_sol
# Test Functions.
# Adapted from "https://www.sfu.ca/~ssurjano/optimization.html"
def Ackley(x, a=20.0, b=0.2, c=2.0*np.pi):
d = len(x)
sum1 = np.sum(np.square(x))
sum2 = np.sum(np.array([np.cos(c*i) for i in x]))
term1 = -a * np.exp(-b * np.sqrt(sum1 / d))
term2 = -np.exp(sum2 / d)
return term1 + term2 + a + np.exp(1)
def sixth_Bukin(x):
return 100 * np.sqrt(np.abs(x[1] - 0.01*x[0]**2)) + 0.01*np.abs(x[0] + 10)
def Cross_in_Tray(x):
return -0.0001 * math.pow(np.abs(np.sin(x[0]) * np.sin(x[1]) * np.exp(np.abs(100.0 - np.sqrt(x[0]**2 + x[1]**2)/np.pi)))+1.0, 0.1)
def Drop_Wave(x):
return -1.0*(1.0 + np.cos(12.0 * np.sqrt(x[0]**2 + x[1]**2))) / (0.5 * (x[0]**2 + x[1]**2) + 2.0)
def Eggholder(x):
return -(x[1] + 47.0) * np.sin(np.sqrt(np.abs(x[1] + x[0]/2 + 47.0))) - x[0] * np.sin(np.sqrt(np.abs(x[0] - (x[1] + 47.0))))
def Griewank(x):
sum_part=0.0
prod_part=1.0
for i, xi in enumerate(x):
sum_part += xi/4000.0
prod_part *= np.cos(xi/np.sqrt(i+1))
return sum_part - prod_part + 1.0
def Holder_Table(x):
return -np.abs(np.sin(x[0])*np.cos(x[1])*np.exp(np.abs(1.0-(np.sqrt(x[0]**2 + x[1]**2)/np.pi))))
def Levy(x):
# d dimensions
w1 = 1.0 + (x[0]-1.0)/4.0
wd = 1.0 + (x[-1]-1.0)/4.0
sum_part = 0.0
for i, xi in enumerate(x):
wi = 1.0 + (xi-1.0)/4.0
sum_part += ((wi-1.0)**2)*(1.0 + 10.0*math.pow(np.sin(np.pi*wi+1.0), 2))
return math.pow(np.sin(np.pi*w1), 2) + sum_part + ((wd-1.0)**2)*(1.0 + math.pow(np.sin(2*np.pi*wd), 2))
def Rastrigin(x):
# d dimensions
d = len(x)
sum_part = 0.0
for i, xi in enumerate(x):
sum_part += (xi**2) - 10.0*np.cos(2*np.pi*xi)
return 10*d + sum_part
def second_Schaffe(x):
return 0.5 + (math.pow(np.sin(x[0]**2 + x[1]**2), 2)-0.5)/(1.0 + 0.001*(x[0]**2 + x[1]**2))**2
def fourth_Schaffer(x):
return 0.5 + (math.pow(np.cos(np.abs(x[0]**2 - x[1]**2)), 2)-0.5)/(1.0 + 0.001*(x[0]**2 + x[1]**2))**2
def Schwefel(x):
# d dimensions
d = len(x)
sum_part = 0.0
for xi in x:
sum_part += xi*np.sin(np.sqrt(np.abs(xi)))
return 418.9829*d - sum_part
def Shubert(x):
sum_1 = 0.0
sum_2 = 0.0
for i in np.arange(5):
i = float(i + 1)
sum_1 += i*np.cos((i+1)*x[0] + i)
sum_2 += i*np.cos((i+1)*x[1] + i)
return sum_1*sum_2
def Styblinski_Tang(x):
f = (sum([math.pow(i,4)-16*math.pow(i,2)+5*i for i in x])/2)
return f
def Easom(x):
f = np.cos(x[0])*np.cos(x[1])*np.exp(-(math.pow(x[0]-np.pi, 2) + math.pow(x[1]-np.pi, 2)))
return f
def Bohachevsky(x):
f = x[0]**2 + 2*x[1]**2 -0.3*np.cos(3*np.pi*x[0]) - 0.4*np.cos(4*np.pi*x[1]) + 0.7
return f
def Perm_d_beta(x, d=2, beta=4):
f = 0.0
for i in range(d):
for j in range(d):
f += ((j+1) + beta)*(x[j]**(i+1) - (1/(j+1)**(i+1)))**2
return f
def Rotated_Hyper_Ellipsoid(x, d=2):
f = 0.0
for i in range(d):
for j in range(i+1):
f += x[j]**2
return f
def Sum_of_Different_Powers(x, d=2):
f = 0.0
for i in range(d):
f += np.abs(x[i])**i+1+1
return f
def SUM_SQUARES(x, d=2):
f = 0.0
for i in range(d):
f += (i+1)*x[i]**2
return f
def TRID(x, d=2):
sum_1 = 0.0
sum_2 = 0.0
for i in range(d):
sum_1 += (x[i] - 1)**2
for i in range(d-1):
sum_2 += x[i+1]*x[i]
f = sum_1 + sum_2
return f
def BOOTH(x):
f = (x[0] + 2*x[1] -7)**2 + (2*x[0] + x[1] - 5)**2
return f
def Matyas(x):
f = 0.26*(x[0]**2 + x[1]**2) - 0.48*x[0]*x[1]
return f
def MCCORMICK(x):
f = np.sin(x[0] + x[1]) + (x[0] - x[1])**2 - 1.5*x[0] + 2.5*x[1] + 1
return f
def Power_Sum(x, d=2, b=[8, 18, 44, 114]):
f = 0.0
for i in range(d):
sum_1 = 0.0
for j in range(d):
sum_1 += x[j]**(i+1)
f += (sum_1 - b[i])**2
return f
def Zakharov(x, d=2):
f = 0.0
sum_1 = 0.0
sum_2 = 0.0
sum_3 = 0.0
for i in range(d):
sum_1 += x[i]**2
sum_2 += 0.5*(i+1)*x[i]
sum_3 += 0.5*(i+1)*x[i]
f = sum_1 + sum_2**2 + sum_3**4
return f
def THREE_HUMP_CAMEL(x):
f = 2*x[0]**2 - 1.05*x[0]**4 + (x[0]**6/6) + x[0]*x[1] + x[1]**2
return f
def SIX_HUMP_CAMEL(x):
f = (4 - 2.1*x[0] + (x[0]**4)/3)*x[0]**2 + x[0]*x[1] + (-4 + 4*x[1]**2)*x[1]**2
return f
def DIXON_PRICE(x, d=2):
sum_1 = 0.0
for i in range(d-1):
i = i + 1
sum_1 += (i+1)*(2*x[i]**2 - x[i-1])**2
f = (x[0] - 1)**2 + sum_1
return f
def ROSENBROCK(x, d=2):
f = 0.0
for i in range(d-1):
f += 100*(x[i+1] - x[i]**2)**2 + (x[i] - 1)**2
return f
def DE_JONG(x):
a = [[-32, -16, 0, 16, 32, -32, -16, 0, 16, 32, -32, -16, 0, 16, 32, -32, -16, 0, 16, 32, -32, -16, 0, 16, 32],
[-32, -32, -32, -32, -32, -16, -16, -16, -16, -16, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32]]
sum_1 = 0.0
for i in range(25):
sum_1 += 1/((i+1) + (x[0] - a[0][i])**6 + (x[1] - a[1][i])**6)
f = (0.002 + sum_1)**(-1)
return f
def MICHALEWICZ(x, d=2, m=10):
f = 0.0
for i in range(d):
f += np.sin(x[i])*np.sin(((i+1)*x[i]**2)/np.pi)**(2*m)
f = -f
return f
def BEALE(x):
f = (1.5 - x[0] + x[0]*x[1])**2 + (2.25 - x[0] + x[0]*x[1]**2)**2 + (2.625 - x[0] + x[0]*x[1]**3)**2
return f
def BRANIN(x):
a=1
b=5.1/(4*(np.pi)**2)
c = 5/np.pi
r = 6
s = 10
t = 1/(8*np.pi)
f = a*(x[1] - b*x[0]**2 + c*x[0] - r)**2 + s*(1 - t)*np.cos(x[0]) + s
return f
def GOLDSTEIN_PRICE(x):
f = (1 + ((x[0] + x[1] + 1)**2)*(19 - 14*x[0] + 3*x[0]**2 - 14*x[1] + 6*x[0]*x[1] + 3*x[1]**2))*(30 + ((2*x[0] - 3*x[1])**2)*(18 - 32*x[0] + 12*x[0]**2 + 48*x[1] - 36*x[0]*x[1] + 27*x[1]**2))
return f
def PERM_D_BETA(x, d=2, beta=1):
f = 0.0
for i in range(d):
sum_1 = 0
for j in range(d):
sum_1 += ((j+1)**(i+1) + beta)*((x[j]/(j+1))**(i+1) - 1)
f += sum_1
return f
class test_functions():
def __init__(self) -> None:
self.Ackley_ = {'name':'Ackley', 'f':Ackley, 'bounds':[[-32.768, 32.768], [-32.768, 32.768]], 'opt':[[0.0, 0.0], 0.0]}
self.sixth_Bukin_ = {'name':'sixth_Bukin', 'f':sixth_Bukin, 'bounds':[[-15.0, -5.0], [-3.0, 3.0]], 'opt':[[-10.0, 1.0], 0.0]}
self.Cross_in_Tray_ = {'name':'Cross_in_Tray', 'f':Cross_in_Tray, 'bounds':[[-10.0, 10.0], [-10.0, 10.0]], 'opt':[[[1.3491, -1.3491], [1.3491, 1.3491], [-1.3491, 1.3491], [-1.3491, -1.3491]], -2.06261]}
self.Drop_Wave_ = {'name':'Drop_Wave', 'f':Drop_Wave, 'bounds':[[-5.12, 5.12], [-5.12, 5.12]], 'opt':[[0, 0], -1.0]}
self.Eggholder_ = {'name':'Eggholder', 'f':Eggholder, 'bounds':[[-512.0, 512.0], [-512.0, 512.0]], 'opt':[[512.404, 512.404], -959.6407]}
self.Griewank_ = {'name':'Griewank', 'f':Griewank, 'bounds':[[-600.0, 600.0], [-600.0, 600.0]], 'opt':[[0.0, 0.0], 0.0]}
self.Holder_Table_ = {'name':'Holder_Table', 'f':Holder_Table, 'bounds':[[-10.0, 10.0], [-10.0, 10.0]], 'opt':[[[8.05502, 9.66459], [8.05502, -9.66459], [-8.05502, 9.66459], [-8.05502, -9.66459]], -19.2085]}
self.Levy_ = {'name':'Levy', 'f':Levy, 'bounds':[[-10.0, 10.0], [-10.0, 10.0]], 'opt':[[1.0, 1.0], 0.0]}
self.Rastrigin_ = {'name':'Rastrigin', 'f':Rastrigin, 'bounds':[[-5.12, 5.12], [-5.12, 5.12]], 'opt':[[0.0, 0.0], 0.0]}
self.second_Schaffe_ = {'name':'second_Schaffe', 'f':second_Schaffe, 'bounds':[[-100.0, 100.0], [-100.0, 100.0]], 'opt':[[0.0, 0.0], 0.0]}
self.fourth_Schaffer_ = {'name':'fourth_Schaffer', 'f':fourth_Schaffer, 'bounds':[[-100.0, 100.0], [-100.0, 100.0]], 'opt':[[0.0, 0.0], 0.0]}
self.Schwefel_ = {'name':'Schwefel', 'f':Schwefel, 'bounds':[[-500.0, 500.0], [-500.0, 500.0]], 'opt':[[420.9687, 420.9687], 0.0]}
self.Shubert_ = {'name':'Shubert', 'f':Shubert, 'bounds':[[-10.0, 10.0], [-10.0, 10.0]], 'opt':[[0.0, 0.0], -186.7309]}
self.Styblinski_Tang_ = {'name':'Styblinski_Tang', 'f':Styblinski_Tang, 'bounds':[[-5, 5], [-5, 5]]}
self.Easom_ = {'name':'Easom', 'f':Easom, 'bounds':[[-3, 3], [-3, 3]]}
self.Bohachevsky_ = {'name':'Bohachevsky', 'f':Bohachevsky, 'bounds':[[-100.0, 100.0], [-100.0, 100.0]], 'opt':[[0, 0], 0]}
self.Perm_d_beta_ = {'name':'Perm_d_beta', 'f':Perm_d_beta, 'bounds':[[-2.0, 2.0], [-2.0, 2.0]], 'opt':[[1, 0.5], 0]}
self.Rotated_Hyper_Ellipsoid_ = {'name':'Rotated_Hyper_Ellipsoid', 'f':Rotated_Hyper_Ellipsoid, 'bounds':[[-65.536, 65.536], [-65.536, 65.536]], 'opt':[[0.0, 0.0], 0]}
self.Sum_of_Different_Powers_ = {'name':'Sum_of_Different_Powers', 'f':Sum_of_Different_Powers, 'bounds':[[-1, 1], [-1, 1]], 'opt':[[0.0, 0.0], 0]}
self.SUM_SQUARES_ = {'name':'SUM_SQUARES', 'f':SUM_SQUARES, 'bounds':[[-10, 10], [-10, 10]], 'opt':[[0.0, 0.0], 0]}
self.TRID_ = {'name':'TRID', 'f':TRID, 'bounds':[[-4, 4], [-4, 4]], 'opt':[[2, 2], -2]}
self.BOOTH_ = {'name':'BOOTH', 'f':BOOTH, 'bounds':[[-10, 10], [-10, 10]], 'opt':[[1, 3], 0]}
self.Matyas_ = {'name':'Matyas', 'f':Matyas, 'bounds':[[-10, 10], [-10, 10]], 'opt':[[0, 0], 0]}
self.MCCORMICK_ = {'name':'MCCORMICK', 'f':MCCORMICK, 'bounds':[[-1.5, 4], [-3, 4]], 'opt':[[-0.54719, -1.54719], -1.9133]}
self.Power_Sum_ = {'name':'Power_Sum', 'f':Power_Sum, 'bounds':[[0, 2], [0, 2]]}
self.Zakharov_ = {'name':'Zakharov', 'f':Zakharov, 'bounds':[[-5, 10], [-5, 10]], 'opt':[[0.0, 0.0], 0.0]}
self.THREE_HUMP_CAMEL_ = {'name':'THREE_HUMP_CAMEL', 'f':THREE_HUMP_CAMEL, 'bounds':[[-5, 5], [-5, 5]], 'opt':[[0.0, 0.0], 0.0]}
self.SIX_HUMP_CAMEL_ = {'name':'SIX_HUMP_CAMEL', 'f':SIX_HUMP_CAMEL, 'bounds':[[-3, 3], [-2, 2]], 'opt':[[0.0898, -0.7126], -1.0316]}
self.DIXON_PRICE_ = {'name':'DIXON_PRICE', 'f':DIXON_PRICE, 'bounds':[[-10, 10], [-10, 10]], 'opt':[[1, 1/np.sqrt(2)], 0]}
self.ROSENBROCK_ = {'name':'ROSENBROCK', 'f':ROSENBROCK, 'bounds':[[-5, 10], [-5, 10]], 'opt':[[1, 1], 0]}
self.DE_JONG_ = {'name':'DE_JONG', 'f':DE_JONG, 'bounds':[[-65.536, 65.536], [-65.536, 65.536]]}
self.MICHALEWICZ_ = {'name':'MICHALEWICZ', 'f':MICHALEWICZ, 'bounds':[[0, np.pi], [0, np.pi]], 'opt':[[2.2, 1.57], -1.8013]}
self.BEALE_ = {'name':'BEALE', 'f':BEALE, 'bounds':[[-4.5, 4.5], [-4.5, 4.5]], 'opt':[[3, 0.5], 0]}
self.BRANIN_ = {'name':'BRANIN', 'f':BRANIN, 'bounds':[[-5, 10], [0, 15]], 'opt':[[-np.pi, 12.275], 0.397887]}
self.GOLDSTEIN_PRICE_ = {'name':'GOLDSTEIN_PRICE', 'f':GOLDSTEIN_PRICE, 'bounds':[[-2, 2], [-2, 2]], 'opt':[[0, -1], 3]}
self.PERM_D_BETA_ = {'name':'PERM_D_BETA', 'f':PERM_D_BETA, 'bounds':[[-2, 2], [-2, 2]], 'opt':[[1, 2], 0]}
self.dictionary = {'Ackley': self.Ackley_,
'sixth_Bukin':self.sixth_Bukin_,
'Cross_in_Tray':self.Cross_in_Tray_,
'Drop_Wave':self.Drop_Wave_,
'Eggholder':self.Eggholder_,
'Griewank':self.Griewank_,
'Holder_Table':self.Holder_Table_,
'Levy':self.Levy_,
'Rastrigin':self.Rastrigin_,
'second_Schaffe':self.second_Schaffe_,
'fourth_Schaffer':self.fourth_Schaffer_,
'Schwefel':self.Schwefel_,
'Shubert':self.Shubert_,
'Styblinski_Tang':self.Styblinski_Tang_,
'Easom':self.Easom_,
'Bohachevsky':self.Bohachevsky_,
'Perm_d_beta':self.Perm_d_beta_,
'Rotated_Hyper_Ellipsoid':self.Rotated_Hyper_Ellipsoid_,
'Sum_of_Different_Powers': self.Sum_of_Different_Powers_,
'SUM_SQUARES':self.SUM_SQUARES_,
'TRID':self.TRID_,
'BOOTH': self.BOOTH_,
'Matyas':self.Matyas_,
'MCCORMICK': self.MCCORMICK_,
'Power_Sum':self.Power_Sum_,
'Zakharov':self.Zakharov_,
'THREE_HUMP_CAMEL' :self.THREE_HUMP_CAMEL_,
'SIX_HUMP_CAMEL': self.SIX_HUMP_CAMEL_,
'DIXON_PRICE': self.DIXON_PRICE_,
'ROSENBROCK_': self.ROSENBROCK_,
'DE_JONG':self.DE_JONG_,
'MICHALEWICZ': self.MICHALEWICZ_,
'BEALE':self.BEALE_,
'BRANIN': self.BRANIN_,
'GOLDSTEIN_PRICE':self.GOLDSTEIN_PRICE_,
'PERM_D_BETA':self.PERM_D_BETA_}
self.whole_list = list(self.dictionary.keys())
def plotly_graph(problem, df=None):
function=problem['f']
x_lb=problem['bounds'][0][0]
x_ub=problem['bounds'][0][1]
y_lb=problem['bounds'][1][0]
y_ub=problem['bounds'][1][1]
x = np.linspace(x_lb, x_ub, 100)
y = np.linspace(y_lb, y_ub, 100)
z = np.empty((100, 100))
for ind_y, j in enumerate(y):
for ind_x, i in enumerate(x):
z[ind_y][ind_x] = function(np.array([i, j]))
steps_ = int(np.max(df['iter']))
fig1 = go.Figure(data=[go.Surface(x=x, y=y, z=z)])
for step in range(steps_):
points = df[df['iter']==step]
points_x = list(points['x1'])
points_y = list(points['x2'])
points_z = list(points['f'])
fig1.add_scatter3d(x=np.array(points_x), y=np.array(points_y), z=np.array(points_z), mode='markers', visible=False, marker=dict(size=5, color="white", line=dict(width=1, color="black")))
fig1.update_layout(title=f"f = {step}")
# Create figure
fig = go.Figure(data=[go.Scatter3d(x=[], y=[], z=[],
mode="markers",
marker=dict(size=5, color="white", line=dict(width=1, color="black"))
), fig1.data[0]]
)
# Frames
frames = [go.Frame(data=[go.Scatter3d(x=k['x'],
y=k['y'],
z=k['z']
), fig1.data[0]
],
traces= [0],
name=f'frame{ind}'
) for ind, k in enumerate(fig1.data[1:])
]
fig.update(frames=frames)
def frame_args(duration):
return {
"frame": {"duration": duration},
"mode": "immediate",
"fromcurrent": True,
"transition": {"duration": duration, "easing": "linear"},
}
sliders = [
{"pad": {"b": 10, "t": 60},
"len": 0.9,
"x": 0.1,
"y": 0,
"steps": [
{"args": [[f.name], frame_args(0)],
"label": str(k),
"method": "animate",
} for k, f in enumerate(fig.frames)
]
}
]
fig.update_layout(
updatemenus = [{"buttons":[
{
"args": [None, frame_args(150)],
"label": "Play",
"method": "animate",
},
{
"args": [[None], frame_args(150)],
"label": "Pause",
"method": "animate",
}],
"direction": "left",
"pad": {"r": 10, "t": 70},
"type": "buttons",
"x": 0.1,
"y": 0,
}
],
sliders=sliders
)
fig.update_layout(sliders=sliders)
fig.write_html('animation.html')
return fig
problem=test_functions().PERM_D_BETA_
df, best_var, best_sol = custom_pso(problem, 20, 2, maxiter=100, solver="Newton", k=0.000000001, G=0.00000001, t=1.0, max_q=0.01, auto_reduce_search_space=True, dinamic=True)
#plotly_graph(problem, df)
print(best_sol)