-
Notifications
You must be signed in to change notification settings - Fork 0
/
PSO_GH.py
117 lines (102 loc) · 3.92 KB
/
PSO_GH.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import numpy as np
class PSO(object):
"""
Class implementing PSO algorithm.
"""
def __init__(self, func, init_pos, n_particles):
"""
Initialize the key variables.
Args:
func (function): the fitness function to optimize.
init_pos (array-like): the initial position to kick off the
optimization process.
n_particles (int): the number of particles of the swarm.
"""
self.func = func
self.n_particles = n_particles
self.init_pos = np.array(init_pos)
self.particle_dim = len(init_pos)
# Initialize particle positions using a uniform distribution
self.particles_pos = np.random.uniform(size=(n_particles, self.particle_dim)) \
* self.init_pos
# Initialize particle velocities using a uniform distribution
self.velocities = np.random.uniform(size=(n_particles, self.particle_dim))
# Initialize the best positions
self.g_best = init_pos
self.p_best = self.particles_pos
def update_position(self, x, v):
"""
Update particle position.
Args:
x (array-like): particle current position.
v (array-like): particle current velocity.
Returns:
The updated position (array-like).
"""
x = np.array(x)
v = np.array(v)
new_x = x + v
return new_x
def update_velocity(self, x, v, p_best, g_best, c0=0.5, c1=1.5, w=0.75):
"""
Update particle velocity.
Args:
x (array-like): particle current position.
v (array-like): particle current velocity.
p_best (array-like): the best position found so far for a particle.
g_best (array-like): the best position regarding
all the particles found so far.
c0 (float): the cognitive scaling constant.
c1 (float): the social scaling constant.
w (float): the inertia weight
Returns:
The updated velocity (array-like).
"""
x = np.array(x)
v = np.array(v)
assert x.shape == v.shape, 'Position and velocity must have same shape'
# a random number between 0 and 1.
r = np.random.uniform()
p_best = np.array(p_best)
g_best = np.array(g_best)
new_v = w*v + c0 * r * (p_best - x) + c1 * r * (g_best - x)
return new_v
def optimize(self, maxiter=200):
"""
Run the PSO optimization process untill the stoping criteria is met.
Case for minimization. The aim is to minimize the cost function.
Args:
maxiter (int): the maximum number of iterations before stopping
the optimization.
Returns:
The best solution found (array-like).
"""
for _ in range(maxiter):
for i in range(self.n_particles):
x = self.particles_pos[i]
v = self.velocities[i]
p_best = self.p_best[i]
self.velocities[i] = self.update_velocity(x, v, p_best, self.g_best)
self.particles_pos[i] = self.update_position(x, v)
# Update the best position for particle i
if self.func(self.particles_pos[i]) < self.func(p_best):
self.p_best[i] = self.particles_pos[i]
# Update the best position overall
if self.func(self.particles_pos[i]) < self.func(self.g_best):
self.g_best = self.particles_pos[i]
return self.g_best, self.func(self.g_best)
# Example of the sphere function
def sphere(pos):
"""
In 3D: f(x,y) = -cos(x)*cos(y)*e^(-(x-pi)**2-(y-pi)**2)
"""
x = pos[0]
y = pos[1]
return -np.cos(x)*np.cos(y)*np.exp(-(x-np.pi)**2-(y-np.pi)**2)
if __name__ == '__main__':
init_pos = [10,10]
PSO_s = PSO(func=sphere, init_pos=init_pos, n_particles=50)
res_s = PSO_s.optimize()
print("Easom function")
print(f'x = {res_s[0]}') # x = [-0.00025538 -0.00137996 0.00248555]
print(f'f = {res_s[1]}') # f = 8.14748063004205e-06