Spaces:
Runtime error
Runtime error
Upload 6 files
Browse files- Coulomb.jpg +0 -0
- F_coulomb.py +164 -0
- F_newton.py +152 -0
- Newton.jpg +0 -0
- Random.jpg +0 -0
- custom_pso.py +706 -0
Coulomb.jpg
ADDED
|
F_coulomb.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
|
| 3 |
+
def normaliazed_direction(ori, des):
|
| 4 |
+
dir_ = des-ori
|
| 5 |
+
nor_dir_ = dir_/np.sqrt(np.sum(dir_**2))
|
| 6 |
+
nor_dir_=np.nan_to_num(nor_dir_)
|
| 7 |
+
return nor_dir_
|
| 8 |
+
|
| 9 |
+
def distance(ori, des):
|
| 10 |
+
dis_ = des-ori
|
| 11 |
+
return dis_
|
| 12 |
+
|
| 13 |
+
def acc(F, m):
|
| 14 |
+
Npar=F.shape[0]
|
| 15 |
+
Nvar=F.shape[1]
|
| 16 |
+
# Acceleration Matrix
|
| 17 |
+
Ac = np.full((Npar, Nvar), 0.0)
|
| 18 |
+
for ind_r, row in enumerate(Ac):
|
| 19 |
+
for ind_c, col in enumerate(row):
|
| 20 |
+
Ac[ind_r][ind_c]=F[ind_r][ind_c]/m[ind_r]
|
| 21 |
+
return Ac
|
| 22 |
+
|
| 23 |
+
def F_coulomb(x, v, q, P, minimize=True, k=0.0001, weight_method='Linear', t=1.0, max_q=100.0):
|
| 24 |
+
""" The procedure that generates the new positions of the particles is based on how particles with positive and negative charges move
|
| 25 |
+
in electric fields. Thus, the procedure will be as follows:
|
| 26 |
+
|
| 27 |
+
1. n particles are created at random positions within the search space.
|
| 28 |
+
2. Each particle is assigned a positive charge type.
|
| 29 |
+
3. The magnitude of each particle's charge is directly related to the objective function.
|
| 30 |
+
3.1 Assignment Methods -> Linear, Exponential, Quadratic (better assignment methods can be explored)
|
| 31 |
+
3.2 Simply put, a solution range is established and adjusted to a charge range between 0 to max_q according to some assignment method.
|
| 32 |
+
4. Each particle holds a velocity. These start at rest but will change over the iterations of the algorithm.
|
| 33 |
+
5. The P particles with the best values obtained from the iteration will remain at rest and emit an electric field of opposite sign (negative) attracting the rest.
|
| 34 |
+
5.1 Let E = k*Q/r^2 be the magnetic field at a point located at a distance r from the source.
|
| 35 |
+
5.2 Let Fe be the electric force between the magnetic field and the particle -> Fe = E*q0 where q0 is the particle's charge.
|
| 36 |
+
5.3 Let Fij be the force produced between particle i and j -> Fij = k*qi*qj/(r^2) where r is the distance between the particles, qi and qj are the charges of i and j.
|
| 37 |
+
5.4 Thus, the resultant forces of particle i are FRi = sum_{p=1}^P k*Qp*Qi/(rip^2) + sum_{j=P+1}^n k*Qi*Qj/(rij^2)
|
| 38 |
+
5.5 Moreover, by Newton's Law, F=m*a -> Fe=m*a. Thus, the velocities of each particle are calculated vf=vi+a*t -> vf = vi + (FRi/m)*t
|
| 39 |
+
5.6 The positions are updated as follows x = vi*t + (a*t^2)/2 -> x = vi*t + (FRi/m)*(t^2)/2
|
| 40 |
+
|
| 41 |
+
Finally, if the particles are too close, it could cause a problem. If rij^2 << 0, then the electric force would be too strong, leading
|
| 42 |
+
the particles to abruptly separate from each other. To avoid this behavior, a small distance (0.00000001) is established. If the distance
|
| 43 |
+
between two particles is smaller than that distance, it will be considered that both particles have collided. Then, if more than half of
|
| 44 |
+
the particles have collided, we will apply a random function to generate new solutions over a reduced search space.
|
| 45 |
+
|
| 46 |
+
Args:
|
| 47 |
+
x (array(size=(Npar, Nvar)): current particle positions
|
| 48 |
+
v (array(size=(Npar, Nvar)): current particle velocity
|
| 49 |
+
q (array(size=(Npar, 1))): current electric charge of each particle
|
| 50 |
+
P (int): quantity of electric fields (the best P particles become electric fields)
|
| 51 |
+
minimize (bool, optional): solver objective. Defaults to True.
|
| 52 |
+
k (float, optional): electric constant. Defaults to 0.0001.
|
| 53 |
+
weight_method (str, optional): method to reassign electric charges. Defaults to 'Linear'. Options=['Linear', 'Quadratic', 'Exponential'].
|
| 54 |
+
t (float, optional): time. Defaults to 1.0.
|
| 55 |
+
max_q (float, optional): upper bound of electric charge to assing. Defaults to 100.0.
|
| 56 |
+
|
| 57 |
+
Returns:
|
| 58 |
+
F_total, Ac, vf, new_pos: returns the force obtained on each particle, their acceleration, their velocities
|
| 59 |
+
and their new positions
|
| 60 |
+
"""
|
| 61 |
+
|
| 62 |
+
Npar=x.shape[0]
|
| 63 |
+
Nvar=x.shape[1]
|
| 64 |
+
|
| 65 |
+
# Distance Matrix
|
| 66 |
+
dis = []
|
| 67 |
+
for ind_r, row in enumerate(x):
|
| 68 |
+
for ind_c, col in enumerate(x):
|
| 69 |
+
dis.append(distance(x[ind_r], x[ind_c]))
|
| 70 |
+
dis=np.array(dis).reshape((Npar,Npar,Nvar))
|
| 71 |
+
|
| 72 |
+
# Direction Matrix
|
| 73 |
+
d = []
|
| 74 |
+
for ind_r, row in enumerate(x):
|
| 75 |
+
for ind_c, col in enumerate(x):
|
| 76 |
+
d.append(normaliazed_direction(x[ind_r], x[ind_c]))
|
| 77 |
+
d=np.array(d).reshape((Npar,Npar,Nvar))
|
| 78 |
+
|
| 79 |
+
colisioned_part = []
|
| 80 |
+
r_2 = np.zeros((Npar, Npar))
|
| 81 |
+
for ind_r, row in enumerate(dis):
|
| 82 |
+
for ind_c, col in enumerate(dis):
|
| 83 |
+
value = dis[ind_r][ind_c]
|
| 84 |
+
value_2 = value**2
|
| 85 |
+
value_sum = np.sum(value_2)
|
| 86 |
+
if value_sum < 0.00000001: # Particles have practically collided. Notice later that fe=0.0 ahead.
|
| 87 |
+
r_2[ind_r][ind_c] = 0.0
|
| 88 |
+
if ind_r != ind_c:
|
| 89 |
+
colisioned_part.append(ind_c)
|
| 90 |
+
else:
|
| 91 |
+
r_2[ind_r][ind_c] = value_sum
|
| 92 |
+
colisioned_part_ = np.unique(np.array(colisioned_part))
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
# Each particle is assigned an electric charge magnitude based on the solution provided by the particle.
|
| 96 |
+
q=np.array(q)
|
| 97 |
+
min_value = q[0]
|
| 98 |
+
max_value = q[-1]
|
| 99 |
+
if minimize:
|
| 100 |
+
q = -1.0*(q-max_value-1.0)
|
| 101 |
+
max_value = q[0]
|
| 102 |
+
|
| 103 |
+
if weight_method=="Linear":
|
| 104 |
+
# We adjust the charges according to the following range [0, max_q].
|
| 105 |
+
q = (q/max_value)*max_q
|
| 106 |
+
reverse_ind = [len(q)-i-1 for i in range(len(q))] # It is inverted to give more charge to the particles that are further away.
|
| 107 |
+
q = q[reverse_ind]
|
| 108 |
+
|
| 109 |
+
elif weight_method=="Quadratic":
|
| 110 |
+
# We adjust the charges according to the following range [0, max_q].
|
| 111 |
+
q_2=q**2
|
| 112 |
+
q=(q_2/np.max(q_2))*max_q
|
| 113 |
+
reverse_ind = [len(q)-i-1 for i in range(len(q))] # It is inverted to give more charge to the particles that are further away.
|
| 114 |
+
q = q[reverse_ind]
|
| 115 |
+
|
| 116 |
+
elif weight_method=="Exponential":
|
| 117 |
+
# We adjust the charges according to the following range [0, max_q].
|
| 118 |
+
q_exp=np.array([np.exp(i) for i in q])
|
| 119 |
+
q=(q_exp/np.max(q_exp))*max_q
|
| 120 |
+
reverse_ind = [len(q)-i-1 for i in range(len(q))] # It is inverted to give more charge to the particles that are further away.
|
| 121 |
+
q = q[reverse_ind]
|
| 122 |
+
|
| 123 |
+
Npar=d.shape[0]
|
| 124 |
+
Nvar=d.shape[2]
|
| 125 |
+
F=np.full((Npar, Npar, Nvar), 0.0)
|
| 126 |
+
for ind_r, row in enumerate(dis):
|
| 127 |
+
for ind_c, col in enumerate(row):
|
| 128 |
+
# The magnitude of the electric force Fe is calculated.
|
| 129 |
+
d_2=r_2[ind_r][ind_c]
|
| 130 |
+
if d_2==0:
|
| 131 |
+
Fe=0.0
|
| 132 |
+
else:
|
| 133 |
+
q1=q[ind_r]
|
| 134 |
+
q2=q[ind_c]
|
| 135 |
+
Fe=float(k*q1*q2/d_2)
|
| 136 |
+
if ind_r >= P and ind_c >= P: # Repulsive forces are generated between particles of the same sign.
|
| 137 |
+
F[ind_r][ind_c]=-1.0*Fe*d[ind_r][ind_c]
|
| 138 |
+
else: # There is attraction between particles and electric fields.
|
| 139 |
+
F[ind_r][ind_c]=Fe*d[ind_r][ind_c]
|
| 140 |
+
F[:P, :P] = 0.0
|
| 141 |
+
F_total = np.sum(F, axis=1)
|
| 142 |
+
F_total[:P]=0.0
|
| 143 |
+
# Remember that F=ma -> m1*a1 = m2*a2. So, if m1>m2 -> a2>a1 -> Particles with greater mass have less acceleration.
|
| 144 |
+
# For this method, the weight of the particle is not important, so we will set them all to be equal to 1.0.
|
| 145 |
+
m=np.ones(Npar)
|
| 146 |
+
# vf = acc + vi*t
|
| 147 |
+
Ac=acc(F_total, m)
|
| 148 |
+
vf = Ac + t*v
|
| 149 |
+
Ac[:P]=0.0
|
| 150 |
+
vf[:P]=0.0 # The velocity of the magnetic fields is set to 0.0.
|
| 151 |
+
# Finally, Xf = xi + vi*t + 0.5*acc*(t^2) (Final Position)
|
| 152 |
+
x__=v*t + 0.5*Ac*(t**2)
|
| 153 |
+
new_pos = x + x__
|
| 154 |
+
|
| 155 |
+
# If more than half of the particles have collided, those that have collided will move randomly within the reduced search space.
|
| 156 |
+
max_crash_part=Npar/2
|
| 157 |
+
if len(colisioned_part_)>max_crash_part:
|
| 158 |
+
lo = np.min(new_pos, axis=0)
|
| 159 |
+
up = np.max(new_pos, axis=0)
|
| 160 |
+
for i in colisioned_part_:
|
| 161 |
+
new_pos[i] = np.random.uniform(low=lo, high=up, size=(1, Nvar))
|
| 162 |
+
|
| 163 |
+
return F_total, Ac, vf, new_pos
|
| 164 |
+
|
F_newton.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
|
| 3 |
+
def normaliazed_direction(ori, des):
|
| 4 |
+
dir_ = des-ori
|
| 5 |
+
nor_dir_ = dir_/np.sqrt(np.sum(dir_**2))
|
| 6 |
+
nor_dir_=np.nan_to_num(nor_dir_)
|
| 7 |
+
return nor_dir_
|
| 8 |
+
|
| 9 |
+
def distance(ori, des):
|
| 10 |
+
dis_ = des-ori
|
| 11 |
+
return dis_
|
| 12 |
+
|
| 13 |
+
def acc(F, m):
|
| 14 |
+
Npar=F.shape[0]
|
| 15 |
+
Nvar=F.shape[1]
|
| 16 |
+
# Matriz de aceleracion
|
| 17 |
+
Ac = np.full((Npar, Nvar), 0.0)
|
| 18 |
+
for ind_r, row in enumerate(Ac):
|
| 19 |
+
for ind_c, col in enumerate(row):
|
| 20 |
+
Ac[ind_r][ind_c]=F[ind_r][ind_c]/m[ind_r]
|
| 21 |
+
return Ac
|
| 22 |
+
|
| 23 |
+
def F_newton(x_, m, minimize=True, G=0.0001, keep_best=False, weight_method='Linear', t=1.0, max_mass=100.0):
|
| 24 |
+
""" The procedure that generates the new positions of the particles is based on how bodies are attracted to each other
|
| 25 |
+
through an attractive force (universal law of gravitation). Thus, the procedure will be as follows:
|
| 26 |
+
|
| 27 |
+
1. n particles are created at random positions within the search space.
|
| 28 |
+
2. Each particle is assigned a mass based on the solution provided by the particle.
|
| 29 |
+
2.1 The better the solution provided by the particle, the greater the assigned mass.
|
| 30 |
+
2.2 Assignment methods -> Linear, Exponential, Quadratic (further discussion on better assignment methods can be explored).
|
| 31 |
+
2.2.1 In simple terms, a range of solutions is established and adjusted to a charge range between 0 to max_mass according to some assignment method.
|
| 32 |
+
3. Let Fij be the force produced between particle i and j -> Fij = G*mi*mj/(r^2) where r is the distance between the particles, mi and mj are the masses of i and j.
|
| 33 |
+
3.1 Thus, the resulting force on particle i is FRi = Σ{j=1} G*mi*mj/(rij^2).
|
| 34 |
+
3.2 Additionally, by Newton's Law, F = m*a -> a = F/m. Thus, the velocities of each particle are calculated as vf = vi + a*t -> vf = vi + (F/m)*t.
|
| 35 |
+
3.3 Finally, the positions are updated as follows: x' = x + vi*t + (a*t^2)/2 -> x' = x + vi*t + (F/m)*(t^2)/2.
|
| 36 |
+
3.4 Applying the assumption vi=0 -> x' = x + (F/m)*(t^2)/2.
|
| 37 |
+
|
| 38 |
+
Args:
|
| 39 |
+
x_ (array(size=(Npar, Nvar)): current particle positions
|
| 40 |
+
m (array(size=(Npar, 1))): current mass of each particle
|
| 41 |
+
minimize (bool, optional): solver objective. Defaults to True.
|
| 42 |
+
G (float, optional): gravitational constant. Defaults to 0.0001.
|
| 43 |
+
keep_best (bool, optional): It will save the best value obtained in each iteration. Defaults to False.
|
| 44 |
+
weight_method (str, optional): method to reassign mass. Defaults to 'Linear'. Options=['Linear', 'Quadratic', 'Exponential'].
|
| 45 |
+
t (float, optional): time. Defaults to 1.0.
|
| 46 |
+
max_mass (float, optional): upper bound of mass to assing. Defaults to 100.0.
|
| 47 |
+
|
| 48 |
+
Returns:
|
| 49 |
+
F_total, Ac, new_pos: returns the force obtained on each particle, their acceleration,
|
| 50 |
+
and their new positions
|
| 51 |
+
"""
|
| 52 |
+
Npar=x_.shape[0]
|
| 53 |
+
Nvar=x_.shape[1]
|
| 54 |
+
|
| 55 |
+
# Distance Matrix
|
| 56 |
+
dis = []
|
| 57 |
+
for ind_r, row in enumerate(x_):
|
| 58 |
+
for ind_c, col in enumerate(x_):
|
| 59 |
+
dis.append(distance(x_[ind_r], x_[ind_c]))
|
| 60 |
+
dis=np.array(dis).reshape((Npar,Npar,Nvar))
|
| 61 |
+
|
| 62 |
+
# Direction Matrix
|
| 63 |
+
d = []
|
| 64 |
+
for ind_r, row in enumerate(x_):
|
| 65 |
+
for ind_c, col in enumerate(x_):
|
| 66 |
+
d.append(normaliazed_direction(x_[ind_r], x_[ind_c]))
|
| 67 |
+
d=np.array(d).reshape((Npar,Npar,Nvar))
|
| 68 |
+
|
| 69 |
+
colisioned_part = []
|
| 70 |
+
r_2 = np.zeros((Npar, Npar))
|
| 71 |
+
for ind_r, row in enumerate(dis):
|
| 72 |
+
for ind_c, col in enumerate(dis):
|
| 73 |
+
value = dis[ind_r][ind_c]
|
| 74 |
+
value_2 = value**2
|
| 75 |
+
value_sum = np.sum(value_2)
|
| 76 |
+
if value_sum < 0.00000001: # Particles have practically collided. Notice later that F_=0.0 ahead.
|
| 77 |
+
r_2[ind_r][ind_c] = 0.0
|
| 78 |
+
if ind_r != ind_c:
|
| 79 |
+
colisioned_part.append(ind_c)
|
| 80 |
+
else:
|
| 81 |
+
r_2[ind_r][ind_c] = value_sum
|
| 82 |
+
colisioned_part_ = np.unique(np.array(colisioned_part))
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
# Each particle is assigned a mass magnitude based on the solution provided by the particle.
|
| 86 |
+
m=np.array(m)
|
| 87 |
+
min_value = m[0]
|
| 88 |
+
max_value = m[-1]
|
| 89 |
+
|
| 90 |
+
if minimize:
|
| 91 |
+
m = -1.0*(m-max_value-1.0)
|
| 92 |
+
max_value = m[0]
|
| 93 |
+
|
| 94 |
+
if weight_method=="Linear":
|
| 95 |
+
# We adjust the mass according to the following range [0, max_mass].
|
| 96 |
+
m = (m/max_value)*max_mass
|
| 97 |
+
reverse_ind = [len(m)-i-1 for i in range(len(m))]
|
| 98 |
+
m = m[reverse_ind]
|
| 99 |
+
|
| 100 |
+
elif weight_method=="Quadratic":
|
| 101 |
+
# We adjust the mass according to the following range [0, max_mass].
|
| 102 |
+
m_2=m**2
|
| 103 |
+
m=(m_2/np.max(m_2))*max_mass
|
| 104 |
+
reverse_ind = [len(m)-i-1 for i in range(len(m))]
|
| 105 |
+
m = m[reverse_ind]
|
| 106 |
+
|
| 107 |
+
elif weight_method=="Exponential":
|
| 108 |
+
# We adjust the mass according to the following range [0, max_mass].
|
| 109 |
+
m_exp=np.array([np.exp(i) for i in m])
|
| 110 |
+
m=(m_exp/np.max(m_exp))*max_mass
|
| 111 |
+
reverse_ind = [len(m)-i-1 for i in range(len(m))]
|
| 112 |
+
m = m[reverse_ind]
|
| 113 |
+
|
| 114 |
+
m = np.nan_to_num(m, nan=0.0001)
|
| 115 |
+
Npar=d.shape[0]
|
| 116 |
+
Nvar=d.shape[2]
|
| 117 |
+
F=np.full((Npar, Npar, Nvar), 0.0)
|
| 118 |
+
for ind_r, row in enumerate(dis):
|
| 119 |
+
for ind_c, col in enumerate(row):
|
| 120 |
+
# The magnitude of the attraction force F_ is calculated.
|
| 121 |
+
d_2=r_2[ind_r][ind_c]
|
| 122 |
+
if d_2==0:
|
| 123 |
+
F_=0.0
|
| 124 |
+
else:
|
| 125 |
+
m1=m[ind_r]
|
| 126 |
+
m2=m[ind_c]
|
| 127 |
+
F_=float(G*m1*m2/d_2)
|
| 128 |
+
F[ind_r][ind_c]=F_*d[ind_r][ind_c]
|
| 129 |
+
F_total = np.sum(F, axis=1)
|
| 130 |
+
# Note: Between two particles, the attractive forces will be the same, but not their accelerations.
|
| 131 |
+
# Remember that F = M * A -> m1 * a1 = m2 * a2, so if m1 > m2 -> a2 > a1 -> Particles with greater mass have lower acceleration.Ac=acc(F_total, m)
|
| 132 |
+
Ac=acc(F_total, m)
|
| 133 |
+
Ac = np.nan_to_num(Ac, nan=0.0)
|
| 134 |
+
|
| 135 |
+
# Finally, Xf = xi + vi * t + 0.5 * acc * (t^2) (Final Position), but if the particles always start at rest (vi=0) -> xf = 0.5 * acc * (t^2).
|
| 136 |
+
x__ = 0.5*Ac*(t**2)
|
| 137 |
+
new_pos=x_ + x__
|
| 138 |
+
|
| 139 |
+
if keep_best==True:
|
| 140 |
+
best_ind = np.argmin(m)
|
| 141 |
+
Ac[best_ind]=0.0
|
| 142 |
+
new_pos=x_ + 0.5*Ac*(t**2)
|
| 143 |
+
|
| 144 |
+
# If more than half of the particles have collided, those that have collided will move randomly within the reduced search space.
|
| 145 |
+
max_crash_part=Npar/2
|
| 146 |
+
if len(colisioned_part_)>max_crash_part:
|
| 147 |
+
lo = np.min(new_pos, axis=0)
|
| 148 |
+
up = np.max(new_pos, axis=0)
|
| 149 |
+
for i in colisioned_part_:
|
| 150 |
+
new_pos[i] = np.random.uniform(low=lo, high=up, size=(1, Nvar))
|
| 151 |
+
|
| 152 |
+
return F_total, Ac, new_pos
|
Newton.jpg
ADDED
|
Random.jpg
ADDED
|
custom_pso.py
ADDED
|
@@ -0,0 +1,706 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'''
|
| 2 |
+
--------------------------------------------------------------
|
| 3 |
+
Custom PSO algorithm for continuous domains
|
| 4 |
+
--------------------------------------------------------------
|
| 5 |
+
Autor: Rodrigo Araya
|
| 6 |
+
Email: [email protected]
|
| 7 |
+
'''
|
| 8 |
+
|
| 9 |
+
import math
|
| 10 |
+
import numpy as np
|
| 11 |
+
import pandas as pd
|
| 12 |
+
from F_newton import F_newton
|
| 13 |
+
from F_coulomb import F_coulomb
|
| 14 |
+
import plotly.graph_objects as go
|
| 15 |
+
import plotly.express as px
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def Random_(problem, x_, auto_reduce_search_space=False):
|
| 19 |
+
""" This solver generates a random solution for each particle. Additionally, it is also possible to
|
| 20 |
+
apply an exploitation method where the search space is reduced on each iteration.
|
| 21 |
+
|
| 22 |
+
Args:
|
| 23 |
+
problem (dic): Dictionary that include: objective function, lower bound and upper bound of each variable and optimal solution
|
| 24 |
+
x_ (array(size=())): Current position of each particle
|
| 25 |
+
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.
|
| 26 |
+
|
| 27 |
+
Returns:
|
| 28 |
+
Stemp, S_f: New positions for each particle and their performance after being evaluated with the objective function.
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
nPart = x_.shape[0]
|
| 33 |
+
nVar = x_.shape[1]
|
| 34 |
+
|
| 35 |
+
if auto_reduce_search_space:
|
| 36 |
+
Lo = np.min(x_, axis=0)
|
| 37 |
+
Up = np.max(x_, axis=0)
|
| 38 |
+
else:
|
| 39 |
+
Lo = np.zeros(nVar)
|
| 40 |
+
Up = np.ones(nVar)
|
| 41 |
+
|
| 42 |
+
new_x = np.random.uniform(low=Lo, high=Up, size=(nPart, nVar))
|
| 43 |
+
|
| 44 |
+
Stemp = np.zeros((nPart,nVar))
|
| 45 |
+
for k in range(nPart):
|
| 46 |
+
for i in range(nVar):
|
| 47 |
+
Stemp[k][i] = new_x[k][i]
|
| 48 |
+
if Stemp[k][i] > Up[i]:
|
| 49 |
+
Stemp[k][i] = Up[i]
|
| 50 |
+
elif Stemp[k][i] < Lo[i]:
|
| 51 |
+
Stemp[k][i] = Lo[i]
|
| 52 |
+
f,S_r,maximize = mp_evaluator(problem, Stemp)
|
| 53 |
+
|
| 54 |
+
S_f = np.zeros((nPart,1))
|
| 55 |
+
|
| 56 |
+
for i in range(len(S_r)):
|
| 57 |
+
S_f[i] = f[i]
|
| 58 |
+
return Stemp, S_f
|
| 59 |
+
|
| 60 |
+
def F_newton_(problem, x_, m, Lo, Up, G=0.00001, keep_best=True, weight_method='Linear', t=1.0, max_mass=100.0):
|
| 61 |
+
_, _, new_x = F_newton(x_, m, minimize=True, G=G, keep_best=keep_best, weight_method=weight_method, t=t, max_mass=max_mass)
|
| 62 |
+
nPart=x_.shape[0]
|
| 63 |
+
nVar=x_.shape[1]
|
| 64 |
+
Stemp = np.zeros((nPart,nVar))
|
| 65 |
+
for k in range(nPart):
|
| 66 |
+
for i in range(nVar):
|
| 67 |
+
Stemp[k][i] = new_x[k][i]
|
| 68 |
+
if Stemp[k][i] > Up[i]:
|
| 69 |
+
Stemp[k][i] = Up[i]
|
| 70 |
+
elif Stemp[k][i] < Lo[i]:
|
| 71 |
+
Stemp[k][i] = Lo[i]
|
| 72 |
+
f,S_r,maximize = mp_evaluator(problem, Stemp)
|
| 73 |
+
|
| 74 |
+
S_f = np.zeros((nPart,1))
|
| 75 |
+
|
| 76 |
+
for i in range(len(S_r)):
|
| 77 |
+
S_f[i] = f[i]
|
| 78 |
+
return Stemp, S_f
|
| 79 |
+
|
| 80 |
+
def F_coulomb_(problem, x_, v, q, P, Lo, Up, k=0.00001, weight_method='Linear', t=1.0, max_q=100.0):
|
| 81 |
+
_, _, v, new_x = F_coulomb(x_, v, q, P=P, minimize=True, k=k, weight_method=weight_method, t=t, max_q=max_q)
|
| 82 |
+
nPart=x_.shape[0]
|
| 83 |
+
nVar=x_.shape[1]
|
| 84 |
+
Stemp = np.zeros((nPart,nVar))
|
| 85 |
+
for k in range(nPart):
|
| 86 |
+
for i in range(nVar):
|
| 87 |
+
Stemp[k][i] = new_x[k][i]
|
| 88 |
+
if Stemp[k][i] > Up[i]:
|
| 89 |
+
Stemp[k][i] = Up[i]
|
| 90 |
+
elif Stemp[k][i] < Lo[i]:
|
| 91 |
+
Stemp[k][i] = Lo[i]
|
| 92 |
+
f,S_r,maximize = mp_evaluator(problem, Stemp)
|
| 93 |
+
|
| 94 |
+
S_f = np.zeros((nPart,1))
|
| 95 |
+
|
| 96 |
+
for i in range(len(S_r)):
|
| 97 |
+
S_f[i] = f[i]
|
| 98 |
+
return Stemp, v, S_f
|
| 99 |
+
|
| 100 |
+
def evaluator(problem, x):
|
| 101 |
+
# 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
|
| 102 |
+
# 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:
|
| 103 |
+
# y1=ax+b -> -5 = a*0+b -> b=-5
|
| 104 |
+
# y1=ax+b -> 5 = a*1+-5 -> a=10
|
| 105 |
+
# y1=10*x+-5
|
| 106 |
+
# y2=ax+b -> -2 = a*0+b -> b=-2
|
| 107 |
+
# y2=ax+b -> 2 = a*1+-2 -> a=4
|
| 108 |
+
# y2=4*x+-2
|
| 109 |
+
# Luego se aplica y1(x1) e y2(x2) respectivamente. Extendible a n dimensiones.
|
| 110 |
+
# Dado que [0, 1] no cambia, se generaliza la formula b=lb y a=ub-lb -> y_{i} = (ub-lb)_{i}*x + lb_{i}
|
| 111 |
+
lb = [var[0] for var in problem['bounds']]
|
| 112 |
+
ub = [var[1] for var in problem['bounds']]
|
| 113 |
+
x = [(ub[ind]-lb[ind])*i+lb[ind] for ind, i in enumerate(x)]
|
| 114 |
+
# calculate fitness
|
| 115 |
+
f = problem['f'](x)
|
| 116 |
+
fitness = dict(Obj=f)
|
| 117 |
+
return fitness
|
| 118 |
+
|
| 119 |
+
def mp_evaluator(problem, x):
|
| 120 |
+
results = [evaluator(problem, c) for c in x]
|
| 121 |
+
f = [r['Obj'] for r in results]
|
| 122 |
+
# maximization or minimization problem
|
| 123 |
+
maximize = False
|
| 124 |
+
return (f, [r for r in results],maximize)
|
| 125 |
+
|
| 126 |
+
def correct_x(problem, x_):
|
| 127 |
+
lb = [var[0] for var in problem['bounds']]
|
| 128 |
+
ub = [var[1] for var in problem['bounds']]
|
| 129 |
+
x = np.empty(x_.shape)
|
| 130 |
+
for ind, row in enumerate(x_):
|
| 131 |
+
corr_row = np.array([(ub[ind]-lb[ind])*i+lb[ind] for ind, i in enumerate(row)])
|
| 132 |
+
x[ind]=corr_row
|
| 133 |
+
return x
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
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):
|
| 138 |
+
"""The procedure of this algorithm is as follows:
|
| 139 |
+
1. Generate a file of size nSize=nPart.
|
| 140 |
+
2. Generate nPart initial solutions. Each solution contains nVar variables.
|
| 141 |
+
3. Evaluate the nPart solutions and add them to the file ordered from best to worst solution.
|
| 142 |
+
4. While the termination condition is not met (iterations > maxiter):
|
| 143 |
+
4.1 Generate new solutions using some solver. Options = ['Random', 'Newton', 'Coulomb']
|
| 144 |
+
4.2 Add new solutions to the file.
|
| 145 |
+
4.3 Remove duplicate solutions.
|
| 146 |
+
4.4 Evaluate solutions and sort from best to worst solution.
|
| 147 |
+
4.5 Keep in the file the nPar best solutions.
|
| 148 |
+
4.6 Save iteration results in a history (dataframe).
|
| 149 |
+
4.7 Evaluate termination condition. If negative, return to step 4.1.
|
| 150 |
+
|
| 151 |
+
Args:
|
| 152 |
+
problem (dic): Dictionary that include: objective function, lower bound and upper bound of each variable and optimal solution
|
| 153 |
+
nPart (_type_): Quantity of particles
|
| 154 |
+
nVar (_type_): Quantity of variables
|
| 155 |
+
maxiter (_type_): Maximum number of iterations.
|
| 156 |
+
seed (int, optional): set the generation of random numbers. Defaults to 0.
|
| 157 |
+
solver (str, optional): solver to apply. Defaults to 'Newton'. Options=['Random', 'Newton', 'Coulomb'].
|
| 158 |
+
|
| 159 |
+
Random Solver:
|
| 160 |
+
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.
|
| 161 |
+
|
| 162 |
+
Newton Solver:
|
| 163 |
+
G (float, optional): Gravitational constant. Defaults to 0.00001.
|
| 164 |
+
keep_best (bool, optional): It will keep the best value obtained in each iteration. Defaults to True.
|
| 165 |
+
weight_method (str, optional): method to reassign particle mass. Defaults to 'Linear'. Options=['Linear', 'Quadratic', 'Exponential'].
|
| 166 |
+
t (float, optional): time. Defaults to 1.0.
|
| 167 |
+
max_mass (float, optional): upper bound of mass to assing. Defaults to 100.0.
|
| 168 |
+
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.
|
| 169 |
+
|
| 170 |
+
Coulomb Solver:
|
| 171 |
+
P (int): quantity of electric fields (the best P particles become electric fields)
|
| 172 |
+
max_q (float, optional): upper bound of electric charge to assing. Defaults to 100.0.
|
| 173 |
+
weight_method (str, optional): method to reassign electric charges. Defaults to 'Linear'. Options=['Linear', 'Quadratic', 'Exponential'].
|
| 174 |
+
k (float, optional): electric constant. Defaults to 0.0001.
|
| 175 |
+
t (float, optional): time. Defaults to 1.0.
|
| 176 |
+
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.
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
Returns:
|
| 180 |
+
df, best_var, best_sol: dataframe contening data from all iterations, the best variables and the best value obtained
|
| 181 |
+
"""
|
| 182 |
+
|
| 183 |
+
# number of variables
|
| 184 |
+
parameters_v = [f'x{i+1}' for i in range(nVar)]
|
| 185 |
+
|
| 186 |
+
# number of variables
|
| 187 |
+
nVar = len(parameters_v)
|
| 188 |
+
|
| 189 |
+
# size of solution archive
|
| 190 |
+
nSize = nPart
|
| 191 |
+
|
| 192 |
+
# number of Particules
|
| 193 |
+
nPart = nPart
|
| 194 |
+
|
| 195 |
+
# maximum iterations
|
| 196 |
+
maxiter = maxiter
|
| 197 |
+
|
| 198 |
+
# bounds of variables
|
| 199 |
+
Up = [1]*nVar
|
| 200 |
+
Lo = [0]*nVar
|
| 201 |
+
|
| 202 |
+
# dinamic q
|
| 203 |
+
din_max_q=max_q
|
| 204 |
+
|
| 205 |
+
# dinamic mass
|
| 206 |
+
din_max_mass = max_mass
|
| 207 |
+
|
| 208 |
+
# initilize matrices
|
| 209 |
+
S = np.zeros((nSize,nVar))
|
| 210 |
+
S_f = np.zeros((nSize,1))
|
| 211 |
+
|
| 212 |
+
# initial velocity
|
| 213 |
+
v = np.zeros((nSize,nVar))
|
| 214 |
+
|
| 215 |
+
# history
|
| 216 |
+
columns_ = ['iter']
|
| 217 |
+
for i in parameters_v: columns_.append(i)
|
| 218 |
+
columns_.append('f')
|
| 219 |
+
df = pd.DataFrame(columns=columns_)
|
| 220 |
+
|
| 221 |
+
# generate first random solution
|
| 222 |
+
#np.random.seed(seed)
|
| 223 |
+
Srand = np.random.uniform(low=0,high=1,size=(nPart, nVar))
|
| 224 |
+
f,S_r,maximize = mp_evaluator(problem, Srand)
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
for i in range(len(S_r)):
|
| 228 |
+
S_f[i] = f[i]
|
| 229 |
+
|
| 230 |
+
# add responses and "fitness" column to solution
|
| 231 |
+
S = np.hstack((Srand, v, S_f))
|
| 232 |
+
# sort according to fitness (last column)
|
| 233 |
+
S = sorted(S, key=lambda row: row[-1],reverse = maximize)
|
| 234 |
+
S = np.array(S)
|
| 235 |
+
|
| 236 |
+
# save each iteration
|
| 237 |
+
iter_n = np.full((nPart, 1), 0.0)
|
| 238 |
+
x_ = S[:, 0:nVar]
|
| 239 |
+
x = correct_x(problem, x_)
|
| 240 |
+
res = np.reshape(S[:, -1], (nPart, 1))
|
| 241 |
+
rows=np.hstack((iter_n, x, res))
|
| 242 |
+
df_new = pd.DataFrame(rows, columns=columns_)
|
| 243 |
+
df = pd.concat([df, df_new])
|
| 244 |
+
|
| 245 |
+
iterations=1
|
| 246 |
+
|
| 247 |
+
# iterations
|
| 248 |
+
while True:
|
| 249 |
+
# get a new solution
|
| 250 |
+
if solver == "Random":
|
| 251 |
+
Stemp, S_f = Random_(problem, S[:, :nVar], auto_reduce_search_space=auto_reduce_search_space)
|
| 252 |
+
|
| 253 |
+
elif solver=="Newton":
|
| 254 |
+
din_mass=0
|
| 255 |
+
if dinamic:
|
| 256 |
+
din_mass = ((maxiter-iterations)/(maxiter))*(np.max(S_f)-np.min(S_f))
|
| 257 |
+
else:
|
| 258 |
+
din_mass=max_mass
|
| 259 |
+
|
| 260 |
+
m = np.reshape(S[:, -1], (nPart, 1))
|
| 261 |
+
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)
|
| 262 |
+
|
| 263 |
+
elif solver == "Coulomb":
|
| 264 |
+
din_q=0
|
| 265 |
+
if dinamic:
|
| 266 |
+
din_q = ((maxiter-iterations)/(maxiter))*(np.max(S_f)-np.min(S_f))
|
| 267 |
+
else:
|
| 268 |
+
din_q=max_q
|
| 269 |
+
q = np.reshape(S[:, -1], (nPart, 1))
|
| 270 |
+
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)
|
| 271 |
+
|
| 272 |
+
# add responses and "fitness" column to solution
|
| 273 |
+
Ssample = np.hstack((Stemp, v, S_f))
|
| 274 |
+
|
| 275 |
+
# add new solutions in the solutions table
|
| 276 |
+
Solution_temp = np.vstack((S,Ssample))
|
| 277 |
+
|
| 278 |
+
# delate duplicated rows
|
| 279 |
+
Solution_temp = np.unique(Solution_temp, axis=0)
|
| 280 |
+
|
| 281 |
+
# sort according to "fitness"
|
| 282 |
+
Solution_temp = sorted(Solution_temp, key=lambda row: row[-1],reverse = maximize)
|
| 283 |
+
Solution_temp = np.array(Solution_temp)
|
| 284 |
+
|
| 285 |
+
# keep best solutions
|
| 286 |
+
S = Solution_temp[:nSize][:]
|
| 287 |
+
|
| 288 |
+
# save each iteration
|
| 289 |
+
iter_n = np.full((nPart, 1), iterations)
|
| 290 |
+
x_ = S[:, 0:nVar]
|
| 291 |
+
x = correct_x(problem, x_)
|
| 292 |
+
res = np.reshape(S[:, -1], (nPart, 1))
|
| 293 |
+
rows=np.hstack((iter_n, x, res))
|
| 294 |
+
df_new = pd.DataFrame(rows, columns=columns_)
|
| 295 |
+
df = pd.concat([df, df_new])
|
| 296 |
+
|
| 297 |
+
iterations += 1
|
| 298 |
+
if iterations > maxiter:
|
| 299 |
+
break
|
| 300 |
+
|
| 301 |
+
best_sol = np.min(df['f'])
|
| 302 |
+
ind_best_sol = np.argmin(df['f'])
|
| 303 |
+
best_var = df.iloc[ind_best_sol, 1:len(parameters_v)+1]
|
| 304 |
+
return df, best_var, best_sol
|
| 305 |
+
|
| 306 |
+
# Test Functions.
|
| 307 |
+
# Adapted from "https://www.sfu.ca/~ssurjano/optimization.html"
|
| 308 |
+
|
| 309 |
+
def Ackley(x, a=20.0, b=0.2, c=2.0*np.pi):
|
| 310 |
+
d = len(x)
|
| 311 |
+
sum1 = np.sum(np.square(x))
|
| 312 |
+
sum2 = np.sum(np.array([np.cos(c*i) for i in x]))
|
| 313 |
+
term1 = -a * np.exp(-b * np.sqrt(sum1 / d))
|
| 314 |
+
term2 = -np.exp(sum2 / d)
|
| 315 |
+
return term1 + term2 + a + np.exp(1)
|
| 316 |
+
|
| 317 |
+
def sixth_Bukin(x):
|
| 318 |
+
return 100 * np.sqrt(np.abs(x[1] - 0.01*x[0]**2)) + 0.01*np.abs(x[0] + 10)
|
| 319 |
+
|
| 320 |
+
def Cross_in_Tray(x):
|
| 321 |
+
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)
|
| 322 |
+
|
| 323 |
+
def Drop_Wave(x):
|
| 324 |
+
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)
|
| 325 |
+
|
| 326 |
+
def Eggholder(x):
|
| 327 |
+
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))))
|
| 328 |
+
|
| 329 |
+
def Griewank(x):
|
| 330 |
+
sum_part=0.0
|
| 331 |
+
prod_part=1.0
|
| 332 |
+
for i, xi in enumerate(x):
|
| 333 |
+
sum_part += xi/4000.0
|
| 334 |
+
prod_part *= np.cos(xi/np.sqrt(i+1))
|
| 335 |
+
return sum_part - prod_part + 1.0
|
| 336 |
+
|
| 337 |
+
def Holder_Table(x):
|
| 338 |
+
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))))
|
| 339 |
+
|
| 340 |
+
def Levy(x):
|
| 341 |
+
# d dimensions
|
| 342 |
+
w1 = 1.0 + (x[0]-1.0)/4.0
|
| 343 |
+
wd = 1.0 + (x[-1]-1.0)/4.0
|
| 344 |
+
sum_part = 0.0
|
| 345 |
+
for i, xi in enumerate(x):
|
| 346 |
+
wi = 1.0 + (xi-1.0)/4.0
|
| 347 |
+
sum_part += ((wi-1.0)**2)*(1.0 + 10.0*math.pow(np.sin(np.pi*wi+1.0), 2))
|
| 348 |
+
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))
|
| 349 |
+
|
| 350 |
+
def Rastrigin(x):
|
| 351 |
+
# d dimensions
|
| 352 |
+
d = len(x)
|
| 353 |
+
sum_part = 0.0
|
| 354 |
+
for i, xi in enumerate(x):
|
| 355 |
+
sum_part += (xi**2) - 10.0*np.cos(2*np.pi*xi)
|
| 356 |
+
return 10*d + sum_part
|
| 357 |
+
|
| 358 |
+
def second_Schaffe(x):
|
| 359 |
+
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
|
| 360 |
+
|
| 361 |
+
def fourth_Schaffer(x):
|
| 362 |
+
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
|
| 363 |
+
|
| 364 |
+
def Schwefel(x):
|
| 365 |
+
# d dimensions
|
| 366 |
+
d = len(x)
|
| 367 |
+
sum_part = 0.0
|
| 368 |
+
for xi in x:
|
| 369 |
+
sum_part += xi*np.sin(np.sqrt(np.abs(xi)))
|
| 370 |
+
return 418.9829*d - sum_part
|
| 371 |
+
|
| 372 |
+
def Shubert(x):
|
| 373 |
+
sum_1 = 0.0
|
| 374 |
+
sum_2 = 0.0
|
| 375 |
+
for i in np.arange(5):
|
| 376 |
+
i = float(i + 1)
|
| 377 |
+
sum_1 += i*np.cos((i+1)*x[0] + i)
|
| 378 |
+
sum_2 += i*np.cos((i+1)*x[1] + i)
|
| 379 |
+
return sum_1*sum_2
|
| 380 |
+
|
| 381 |
+
def Styblinski_Tang(x):
|
| 382 |
+
f = (sum([math.pow(i,4)-16*math.pow(i,2)+5*i for i in x])/2)
|
| 383 |
+
return f
|
| 384 |
+
|
| 385 |
+
def Easom(x):
|
| 386 |
+
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)))
|
| 387 |
+
return f
|
| 388 |
+
|
| 389 |
+
def Bohachevsky(x):
|
| 390 |
+
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
|
| 391 |
+
return f
|
| 392 |
+
|
| 393 |
+
def Perm_d_beta(x, d=2, beta=4):
|
| 394 |
+
f = 0.0
|
| 395 |
+
for i in range(d):
|
| 396 |
+
for j in range(d):
|
| 397 |
+
f += ((j+1) + beta)*(x[j]**(i+1) - (1/(j+1)**(i+1)))**2
|
| 398 |
+
return f
|
| 399 |
+
|
| 400 |
+
def Rotated_Hyper_Ellipsoid(x, d=2):
|
| 401 |
+
f = 0.0
|
| 402 |
+
for i in range(d):
|
| 403 |
+
for j in range(i+1):
|
| 404 |
+
f += x[j]**2
|
| 405 |
+
return f
|
| 406 |
+
|
| 407 |
+
def Sum_of_Different_Powers(x, d=2):
|
| 408 |
+
f = 0.0
|
| 409 |
+
for i in range(d):
|
| 410 |
+
f += np.abs(x[i])**i+1+1
|
| 411 |
+
return f
|
| 412 |
+
|
| 413 |
+
def SUM_SQUARES(x, d=2):
|
| 414 |
+
f = 0.0
|
| 415 |
+
for i in range(d):
|
| 416 |
+
f += (i+1)*x[i]**2
|
| 417 |
+
return f
|
| 418 |
+
|
| 419 |
+
def TRID(x, d=2):
|
| 420 |
+
sum_1 = 0.0
|
| 421 |
+
sum_2 = 0.0
|
| 422 |
+
for i in range(d):
|
| 423 |
+
sum_1 += (x[i] - 1)**2
|
| 424 |
+
for i in range(d-1):
|
| 425 |
+
sum_2 += x[i+1]*x[i]
|
| 426 |
+
f = sum_1 + sum_2
|
| 427 |
+
return f
|
| 428 |
+
|
| 429 |
+
def BOOTH(x):
|
| 430 |
+
f = (x[0] + 2*x[1] -7)**2 + (2*x[0] + x[1] - 5)**2
|
| 431 |
+
return f
|
| 432 |
+
|
| 433 |
+
def Matyas(x):
|
| 434 |
+
f = 0.26*(x[0]**2 + x[1]**2) - 0.48*x[0]*x[1]
|
| 435 |
+
return f
|
| 436 |
+
|
| 437 |
+
def MCCORMICK(x):
|
| 438 |
+
f = np.sin(x[0] + x[1]) + (x[0] - x[1])**2 - 1.5*x[0] + 2.5*x[1] + 1
|
| 439 |
+
return f
|
| 440 |
+
|
| 441 |
+
def Power_Sum(x, d=2, b=[8, 18, 44, 114]):
|
| 442 |
+
f = 0.0
|
| 443 |
+
for i in range(d):
|
| 444 |
+
sum_1 = 0.0
|
| 445 |
+
for j in range(d):
|
| 446 |
+
sum_1 += x[j]**(i+1)
|
| 447 |
+
f += (sum_1 - b[i])**2
|
| 448 |
+
return f
|
| 449 |
+
|
| 450 |
+
def Zakharov(x, d=2):
|
| 451 |
+
f = 0.0
|
| 452 |
+
sum_1 = 0.0
|
| 453 |
+
sum_2 = 0.0
|
| 454 |
+
sum_3 = 0.0
|
| 455 |
+
for i in range(d):
|
| 456 |
+
sum_1 += x[i]**2
|
| 457 |
+
sum_2 += 0.5*(i+1)*x[i]
|
| 458 |
+
sum_3 += 0.5*(i+1)*x[i]
|
| 459 |
+
f = sum_1 + sum_2**2 + sum_3**4
|
| 460 |
+
return f
|
| 461 |
+
|
| 462 |
+
def THREE_HUMP_CAMEL(x):
|
| 463 |
+
f = 2*x[0]**2 - 1.05*x[0]**4 + (x[0]**6/6) + x[0]*x[1] + x[1]**2
|
| 464 |
+
return f
|
| 465 |
+
|
| 466 |
+
def SIX_HUMP_CAMEL(x):
|
| 467 |
+
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
|
| 468 |
+
return f
|
| 469 |
+
|
| 470 |
+
def DIXON_PRICE(x, d=2):
|
| 471 |
+
sum_1 = 0.0
|
| 472 |
+
for i in range(d-1):
|
| 473 |
+
i = i + 1
|
| 474 |
+
sum_1 += (i+1)*(2*x[i]**2 - x[i-1])**2
|
| 475 |
+
f = (x[0] - 1)**2 + sum_1
|
| 476 |
+
return f
|
| 477 |
+
|
| 478 |
+
def ROSENBROCK(x, d=2):
|
| 479 |
+
f = 0.0
|
| 480 |
+
for i in range(d-1):
|
| 481 |
+
f += 100*(x[i+1] - x[i]**2)**2 + (x[i] - 1)**2
|
| 482 |
+
return f
|
| 483 |
+
|
| 484 |
+
def DE_JONG(x):
|
| 485 |
+
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],
|
| 486 |
+
[-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]]
|
| 487 |
+
sum_1 = 0.0
|
| 488 |
+
for i in range(25):
|
| 489 |
+
sum_1 += 1/((i+1) + (x[0] - a[0][i])**6 + (x[1] - a[1][i])**6)
|
| 490 |
+
f = (0.002 + sum_1)**(-1)
|
| 491 |
+
return f
|
| 492 |
+
|
| 493 |
+
def MICHALEWICZ(x, d=2, m=10):
|
| 494 |
+
f = 0.0
|
| 495 |
+
for i in range(d):
|
| 496 |
+
f += np.sin(x[i])*np.sin(((i+1)*x[i]**2)/np.pi)**(2*m)
|
| 497 |
+
f = -f
|
| 498 |
+
return f
|
| 499 |
+
|
| 500 |
+
def BEALE(x):
|
| 501 |
+
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
|
| 502 |
+
return f
|
| 503 |
+
|
| 504 |
+
def BRANIN(x):
|
| 505 |
+
a=1
|
| 506 |
+
b=5.1/(4*(np.pi)**2)
|
| 507 |
+
c = 5/np.pi
|
| 508 |
+
r = 6
|
| 509 |
+
s = 10
|
| 510 |
+
t = 1/(8*np.pi)
|
| 511 |
+
f = a*(x[1] - b*x[0]**2 + c*x[0] - r)**2 + s*(1 - t)*np.cos(x[0]) + s
|
| 512 |
+
return f
|
| 513 |
+
|
| 514 |
+
def GOLDSTEIN_PRICE(x):
|
| 515 |
+
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))
|
| 516 |
+
return f
|
| 517 |
+
|
| 518 |
+
def PERM_D_BETA(x, d=2, beta=1):
|
| 519 |
+
f = 0.0
|
| 520 |
+
for i in range(d):
|
| 521 |
+
sum_1 = 0
|
| 522 |
+
for j in range(d):
|
| 523 |
+
sum_1 += ((j+1)**(i+1) + beta)*((x[j]/(j+1))**(i+1) - 1)
|
| 524 |
+
f += sum_1
|
| 525 |
+
return f
|
| 526 |
+
|
| 527 |
+
class test_functions():
|
| 528 |
+
def __init__(self) -> None:
|
| 529 |
+
self.Ackley_ = {'name':'Ackley', 'f':Ackley, 'bounds':[[-32.768, 32.768], [-32.768, 32.768]], 'opt':[[0.0, 0.0], 0.0]}
|
| 530 |
+
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]}
|
| 531 |
+
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]}
|
| 532 |
+
self.Drop_Wave_ = {'name':'Drop_Wave', 'f':Drop_Wave, 'bounds':[[-5.12, 5.12], [-5.12, 5.12]], 'opt':[[0, 0], -1.0]}
|
| 533 |
+
self.Eggholder_ = {'name':'Eggholder', 'f':Eggholder, 'bounds':[[-512.0, 512.0], [-512.0, 512.0]], 'opt':[[512.404, 512.404], -959.6407]}
|
| 534 |
+
self.Griewank_ = {'name':'Griewank', 'f':Griewank, 'bounds':[[-600.0, 600.0], [-600.0, 600.0]], 'opt':[[0.0, 0.0], 0.0]}
|
| 535 |
+
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]}
|
| 536 |
+
self.Levy_ = {'name':'Levy', 'f':Levy, 'bounds':[[-10.0, 10.0], [-10.0, 10.0]], 'opt':[[1.0, 1.0], 0.0]}
|
| 537 |
+
self.Rastrigin_ = {'name':'Rastrigin', 'f':Rastrigin, 'bounds':[[-5.12, 5.12], [-5.12, 5.12]], 'opt':[[0.0, 0.0], 0.0]}
|
| 538 |
+
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]}
|
| 539 |
+
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]}
|
| 540 |
+
self.Schwefel_ = {'name':'Schwefel', 'f':Schwefel, 'bounds':[[-500.0, 500.0], [-500.0, 500.0]], 'opt':[[420.9687, 420.9687], 0.0]}
|
| 541 |
+
self.Shubert_ = {'name':'Shubert', 'f':Shubert, 'bounds':[[-10.0, 10.0], [-10.0, 10.0]], 'opt':[[0.0, 0.0], -186.7309]}
|
| 542 |
+
self.Styblinski_Tang_ = {'name':'Styblinski_Tang', 'f':Styblinski_Tang, 'bounds':[[-5, 5], [-5, 5]]}
|
| 543 |
+
self.Easom_ = {'name':'Easom', 'f':Easom, 'bounds':[[-3, 3], [-3, 3]]}
|
| 544 |
+
self.Bohachevsky_ = {'name':'Bohachevsky', 'f':Bohachevsky, 'bounds':[[-100.0, 100.0], [-100.0, 100.0]], 'opt':[[0, 0], 0]}
|
| 545 |
+
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]}
|
| 546 |
+
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]}
|
| 547 |
+
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]}
|
| 548 |
+
self.SUM_SQUARES_ = {'name':'SUM_SQUARES', 'f':SUM_SQUARES, 'bounds':[[-10, 10], [-10, 10]], 'opt':[[0.0, 0.0], 0]}
|
| 549 |
+
self.TRID_ = {'name':'TRID', 'f':TRID, 'bounds':[[-4, 4], [-4, 4]], 'opt':[[2, 2], -2]}
|
| 550 |
+
self.BOOTH_ = {'name':'BOOTH', 'f':BOOTH, 'bounds':[[-10, 10], [-10, 10]], 'opt':[[1, 3], 0]}
|
| 551 |
+
self.Matyas_ = {'name':'Matyas', 'f':Matyas, 'bounds':[[-10, 10], [-10, 10]], 'opt':[[0, 0], 0]}
|
| 552 |
+
self.MCCORMICK_ = {'name':'MCCORMICK', 'f':MCCORMICK, 'bounds':[[-1.5, 4], [-3, 4]], 'opt':[[-0.54719, -1.54719], -1.9133]}
|
| 553 |
+
self.Power_Sum_ = {'name':'Power_Sum', 'f':Power_Sum, 'bounds':[[0, 2], [0, 2]]}
|
| 554 |
+
self.Zakharov_ = {'name':'Zakharov', 'f':Zakharov, 'bounds':[[-5, 10], [-5, 10]], 'opt':[[0.0, 0.0], 0.0]}
|
| 555 |
+
self.THREE_HUMP_CAMEL_ = {'name':'THREE_HUMP_CAMEL', 'f':THREE_HUMP_CAMEL, 'bounds':[[-5, 5], [-5, 5]], 'opt':[[0.0, 0.0], 0.0]}
|
| 556 |
+
self.SIX_HUMP_CAMEL_ = {'name':'SIX_HUMP_CAMEL', 'f':SIX_HUMP_CAMEL, 'bounds':[[-3, 3], [-2, 2]], 'opt':[[0.0898, -0.7126], -1.0316]}
|
| 557 |
+
self.DIXON_PRICE_ = {'name':'DIXON_PRICE', 'f':DIXON_PRICE, 'bounds':[[-10, 10], [-10, 10]], 'opt':[[1, 1/np.sqrt(2)], 0]}
|
| 558 |
+
self.ROSENBROCK_ = {'name':'ROSENBROCK', 'f':ROSENBROCK, 'bounds':[[-5, 10], [-5, 10]], 'opt':[[1, 1], 0]}
|
| 559 |
+
self.DE_JONG_ = {'name':'DE_JONG', 'f':DE_JONG, 'bounds':[[-65.536, 65.536], [-65.536, 65.536]]}
|
| 560 |
+
self.MICHALEWICZ_ = {'name':'MICHALEWICZ', 'f':MICHALEWICZ, 'bounds':[[0, np.pi], [0, np.pi]], 'opt':[[2.2, 1.57], -1.8013]}
|
| 561 |
+
self.BEALE_ = {'name':'BEALE', 'f':BEALE, 'bounds':[[-4.5, 4.5], [-4.5, 4.5]], 'opt':[[3, 0.5], 0]}
|
| 562 |
+
self.BRANIN_ = {'name':'BRANIN', 'f':BRANIN, 'bounds':[[-5, 10], [0, 15]], 'opt':[[-np.pi, 12.275], 0.397887]}
|
| 563 |
+
self.GOLDSTEIN_PRICE_ = {'name':'GOLDSTEIN_PRICE', 'f':GOLDSTEIN_PRICE, 'bounds':[[-2, 2], [-2, 2]], 'opt':[[0, -1], 3]}
|
| 564 |
+
self.PERM_D_BETA_ = {'name':'PERM_D_BETA', 'f':PERM_D_BETA, 'bounds':[[-2, 2], [-2, 2]], 'opt':[[1, 2], 0]}
|
| 565 |
+
self.dictionary = {'Ackley': self.Ackley_,
|
| 566 |
+
'sixth_Bukin':self.sixth_Bukin_,
|
| 567 |
+
'Cross_in_Tray':self.Cross_in_Tray_,
|
| 568 |
+
'Drop_Wave':self.Drop_Wave_,
|
| 569 |
+
'Eggholder':self.Eggholder_,
|
| 570 |
+
'Griewank':self.Griewank_,
|
| 571 |
+
'Holder_Table':self.Holder_Table_,
|
| 572 |
+
'Levy':self.Levy_,
|
| 573 |
+
'Rastrigin':self.Rastrigin_,
|
| 574 |
+
'second_Schaffe':self.second_Schaffe_,
|
| 575 |
+
'fourth_Schaffer':self.fourth_Schaffer_,
|
| 576 |
+
'Schwefel':self.Schwefel_,
|
| 577 |
+
'Shubert':self.Shubert_,
|
| 578 |
+
'Styblinski_Tang':self.Styblinski_Tang_,
|
| 579 |
+
'Easom':self.Easom_,
|
| 580 |
+
'Bohachevsky':self.Bohachevsky_,
|
| 581 |
+
'Perm_d_beta':self.Perm_d_beta_,
|
| 582 |
+
'Rotated_Hyper_Ellipsoid':self.Rotated_Hyper_Ellipsoid_,
|
| 583 |
+
'Sum_of_Different_Powers': self.Sum_of_Different_Powers_,
|
| 584 |
+
'SUM_SQUARES':self.SUM_SQUARES_,
|
| 585 |
+
'TRID':self.TRID_,
|
| 586 |
+
'BOOTH': self.BOOTH_,
|
| 587 |
+
'Matyas':self.Matyas_,
|
| 588 |
+
'MCCORMICK': self.MCCORMICK_,
|
| 589 |
+
'Power_Sum':self.Power_Sum_,
|
| 590 |
+
'Zakharov':self.Zakharov_,
|
| 591 |
+
'THREE_HUMP_CAMEL' :self.THREE_HUMP_CAMEL_,
|
| 592 |
+
'SIX_HUMP_CAMEL': self.SIX_HUMP_CAMEL_,
|
| 593 |
+
'DIXON_PRICE': self.DIXON_PRICE_,
|
| 594 |
+
'ROSENBROCK_': self.ROSENBROCK_,
|
| 595 |
+
'DE_JONG':self.DE_JONG_,
|
| 596 |
+
'MICHALEWICZ': self.MICHALEWICZ_,
|
| 597 |
+
'BEALE':self.BEALE_,
|
| 598 |
+
'BRANIN': self.BRANIN_,
|
| 599 |
+
'GOLDSTEIN_PRICE':self.GOLDSTEIN_PRICE_,
|
| 600 |
+
'PERM_D_BETA':self.PERM_D_BETA_}
|
| 601 |
+
self.whole_list = list(self.dictionary.keys())
|
| 602 |
+
|
| 603 |
+
|
| 604 |
+
def plotly_graph(problem, df=None):
|
| 605 |
+
function=problem['f']
|
| 606 |
+
x_lb=problem['bounds'][0][0]
|
| 607 |
+
x_ub=problem['bounds'][0][1]
|
| 608 |
+
y_lb=problem['bounds'][1][0]
|
| 609 |
+
y_ub=problem['bounds'][1][1]
|
| 610 |
+
|
| 611 |
+
x = np.linspace(x_lb, x_ub, 100)
|
| 612 |
+
y = np.linspace(y_lb, y_ub, 100)
|
| 613 |
+
z = np.empty((100, 100))
|
| 614 |
+
for ind_y, j in enumerate(y):
|
| 615 |
+
for ind_x, i in enumerate(x):
|
| 616 |
+
z[ind_y][ind_x] = function(np.array([i, j]))
|
| 617 |
+
|
| 618 |
+
steps_ = int(np.max(df['iter']))
|
| 619 |
+
|
| 620 |
+
fig1 = go.Figure(data=[go.Surface(x=x, y=y, z=z)])
|
| 621 |
+
for step in range(steps_):
|
| 622 |
+
points = df[df['iter']==step]
|
| 623 |
+
points_x = list(points['x1'])
|
| 624 |
+
points_y = list(points['x2'])
|
| 625 |
+
points_z = list(points['f'])
|
| 626 |
+
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")))
|
| 627 |
+
fig1.update_layout(title=f"f = {step}")
|
| 628 |
+
|
| 629 |
+
# Create figure
|
| 630 |
+
fig = go.Figure(data=[go.Scatter3d(x=[], y=[], z=[],
|
| 631 |
+
mode="markers",
|
| 632 |
+
marker=dict(size=5, color="white", line=dict(width=1, color="black"))
|
| 633 |
+
), fig1.data[0]]
|
| 634 |
+
)
|
| 635 |
+
|
| 636 |
+
# Frames
|
| 637 |
+
frames = [go.Frame(data=[go.Scatter3d(x=k['x'],
|
| 638 |
+
y=k['y'],
|
| 639 |
+
z=k['z']
|
| 640 |
+
), fig1.data[0]
|
| 641 |
+
],
|
| 642 |
+
traces= [0],
|
| 643 |
+
name=f'frame{ind}'
|
| 644 |
+
) for ind, k in enumerate(fig1.data[1:])
|
| 645 |
+
]
|
| 646 |
+
|
| 647 |
+
fig.update(frames=frames)
|
| 648 |
+
|
| 649 |
+
def frame_args(duration):
|
| 650 |
+
return {
|
| 651 |
+
"frame": {"duration": duration},
|
| 652 |
+
"mode": "immediate",
|
| 653 |
+
"fromcurrent": True,
|
| 654 |
+
"transition": {"duration": duration, "easing": "linear"},
|
| 655 |
+
}
|
| 656 |
+
|
| 657 |
+
|
| 658 |
+
sliders = [
|
| 659 |
+
{"pad": {"b": 10, "t": 60},
|
| 660 |
+
"len": 0.9,
|
| 661 |
+
"x": 0.1,
|
| 662 |
+
"y": 0,
|
| 663 |
+
|
| 664 |
+
"steps": [
|
| 665 |
+
{"args": [[f.name], frame_args(0)],
|
| 666 |
+
"label": str(k),
|
| 667 |
+
"method": "animate",
|
| 668 |
+
} for k, f in enumerate(fig.frames)
|
| 669 |
+
]
|
| 670 |
+
}
|
| 671 |
+
]
|
| 672 |
+
|
| 673 |
+
fig.update_layout(
|
| 674 |
+
|
| 675 |
+
updatemenus = [{"buttons":[
|
| 676 |
+
{
|
| 677 |
+
"args": [None, frame_args(150)],
|
| 678 |
+
"label": "Play",
|
| 679 |
+
"method": "animate",
|
| 680 |
+
},
|
| 681 |
+
{
|
| 682 |
+
"args": [[None], frame_args(150)],
|
| 683 |
+
"label": "Pause",
|
| 684 |
+
"method": "animate",
|
| 685 |
+
}],
|
| 686 |
+
|
| 687 |
+
"direction": "left",
|
| 688 |
+
"pad": {"r": 10, "t": 70},
|
| 689 |
+
"type": "buttons",
|
| 690 |
+
"x": 0.1,
|
| 691 |
+
"y": 0,
|
| 692 |
+
}
|
| 693 |
+
],
|
| 694 |
+
sliders=sliders
|
| 695 |
+
)
|
| 696 |
+
|
| 697 |
+
fig.update_layout(sliders=sliders)
|
| 698 |
+
fig.write_html('animation.html')
|
| 699 |
+
return fig
|
| 700 |
+
|
| 701 |
+
|
| 702 |
+
problem=test_functions().PERM_D_BETA_
|
| 703 |
+
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)
|
| 704 |
+
#plotly_graph(problem, df)
|
| 705 |
+
|
| 706 |
+
print(best_sol)
|