Commit
•
7775b72
1
Parent(s):
47d7fb1
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,500 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import math
|
3 |
+
import matplotlib.pyplot as plt
|
4 |
+
from io import BytesIO
|
5 |
+
from PIL import Image
|
6 |
+
import gradio as gr
|
7 |
+
from mpl_toolkits.mplot3d import Axes3D
|
8 |
+
|
9 |
+
class Objective:
|
10 |
+
def Evaluate(self, p):
|
11 |
+
return -5.0*np.exp(-0.5*((p[0]+2.2)**2/0.4+(p[1]-4.3)**2/0.4)) + -2.0*np.exp(-0.5*((p[0]-2.2)**2/0.4+(p[1]+4.3)**2/0.4))
|
12 |
+
|
13 |
+
# Create an instance of the Objective class
|
14 |
+
obj = Objective()
|
15 |
+
|
16 |
+
# Evaluate the fitness of a position
|
17 |
+
position = np.array([-2.2, 4.3])
|
18 |
+
fitness = obj.Evaluate(position)
|
19 |
+
|
20 |
+
print(f"The fitness of the position {position} is {fitness}")
|
21 |
+
|
22 |
+
class Bounds:
|
23 |
+
def __init__(self, lower, upper, enforce="clip"):
|
24 |
+
self.lower = np.array(lower)
|
25 |
+
self.upper = np.array(upper)
|
26 |
+
self.enforce = enforce.lower()
|
27 |
+
|
28 |
+
def Upper(self):
|
29 |
+
return self.upper
|
30 |
+
|
31 |
+
def Lower(self):
|
32 |
+
return self.lower
|
33 |
+
|
34 |
+
def Limits(self, pos):
|
35 |
+
npart, ndim = pos.shape
|
36 |
+
for i in range(npart):
|
37 |
+
for j in range(ndim):
|
38 |
+
if pos[i, j] < self.lower[j]:
|
39 |
+
if self.enforce == "clip":
|
40 |
+
pos[i, j] = self.lower[j]
|
41 |
+
elif self.enforce == "resample":
|
42 |
+
pos[i, j] = self.lower[j] + np.random.random() * (self.upper[j] - self.lower[j])
|
43 |
+
elif pos[i, j] > self.upper[j]:
|
44 |
+
if self.enforce == "clip":
|
45 |
+
pos[i, j] = self.upper[j]
|
46 |
+
elif self.enforce == "resample":
|
47 |
+
pos[i, j] = self.lower[j] + np.random.random() * (self.upper[j] - self.lower[j])
|
48 |
+
pos[i] = self.Validate(pos[i])
|
49 |
+
return pos
|
50 |
+
|
51 |
+
def Validate(self, pos):
|
52 |
+
return pos
|
53 |
+
|
54 |
+
# Define the bounds
|
55 |
+
lower_bounds = [-6, -6]
|
56 |
+
upper_bounds = [6, 6]
|
57 |
+
|
58 |
+
# Create an instance of the Bounds class
|
59 |
+
bounds = Bounds(lower_bounds, upper_bounds, enforce="clip")
|
60 |
+
|
61 |
+
# Define a set of positions
|
62 |
+
positions = np.array([[15, 15], [-15, -15], [5, 15], [15, 5]])
|
63 |
+
|
64 |
+
# Enforce the bounds on the positions
|
65 |
+
valid_positions = bounds.Limits(positions)
|
66 |
+
|
67 |
+
print(f"Valid positions: {valid_positions}")
|
68 |
+
|
69 |
+
# Define the bounds
|
70 |
+
lower_bounds = [-6, -6]
|
71 |
+
upper_bounds = [6, 6]
|
72 |
+
|
73 |
+
# Create an instance of the Bounds class
|
74 |
+
bounds = Bounds(lower_bounds, upper_bounds, enforce="resample")
|
75 |
+
|
76 |
+
# Define a set of positions
|
77 |
+
positions = np.array([[15, 15], [-15, -15], [5, 15], [15, 5]])
|
78 |
+
|
79 |
+
# Enforce the bounds on the positions
|
80 |
+
valid_positions = bounds.Limits(positions)
|
81 |
+
|
82 |
+
print(f"Valid positions: {valid_positions}")
|
83 |
+
|
84 |
+
class QuasiRandomInitializer:
|
85 |
+
def __init__(self, npart=10, ndim=2, bounds=None, k=1, jitter=0.0):
|
86 |
+
self.npart = npart
|
87 |
+
self.ndim = ndim
|
88 |
+
self.bounds = bounds
|
89 |
+
self.k = k
|
90 |
+
self.jitter = jitter
|
91 |
+
self.primes = [
|
92 |
+
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
|
93 |
+
101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197,
|
94 |
+
199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
|
95 |
+
317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439,
|
96 |
+
443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571,
|
97 |
+
577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659
|
98 |
+
]
|
99 |
+
|
100 |
+
def Halton(self, i, b):
|
101 |
+
f = 1.0
|
102 |
+
r = 0
|
103 |
+
while i > 0:
|
104 |
+
f = f / b
|
105 |
+
r = r + f * (i % b)
|
106 |
+
i = math.floor(i / b)
|
107 |
+
return r
|
108 |
+
|
109 |
+
def InitializeSwarm(self):
|
110 |
+
self.swarm = np.zeros((self.npart, self.ndim))
|
111 |
+
lo = np.zeros(self.ndim)
|
112 |
+
hi = np.ones(self.ndim)
|
113 |
+
if self.bounds is not None:
|
114 |
+
lo = self.bounds.Lower()
|
115 |
+
hi = self.bounds.Upper()
|
116 |
+
|
117 |
+
for i in range(self.npart):
|
118 |
+
for j in range(self.ndim):
|
119 |
+
h = self.Halton(i + self.k, self.primes[j % len(self.primes)])
|
120 |
+
q = self.jitter * (np.random.random() - 0.5)
|
121 |
+
self.swarm[i, j] = lo[j] + (hi[j] - lo[j]) * h + q
|
122 |
+
|
123 |
+
if self.bounds is not None:
|
124 |
+
self.swarm = self.bounds.Limits(self.swarm)
|
125 |
+
|
126 |
+
return self.swarm
|
127 |
+
|
128 |
+
# Define the bounds
|
129 |
+
lower_bounds = [-6, -6]
|
130 |
+
upper_bounds = [6, 6]
|
131 |
+
bounds = Bounds(lower_bounds, upper_bounds, enforce="clip")
|
132 |
+
|
133 |
+
# Create an instance of the QuasiRandomInitializer class
|
134 |
+
init = QuasiRandomInitializer(npart=50, ndim=2, bounds=bounds)
|
135 |
+
|
136 |
+
# Initialize the swarm
|
137 |
+
swarm_positions = init.InitializeSwarm()
|
138 |
+
|
139 |
+
print(f"Initial swarm positions: {swarm_positions}")
|
140 |
+
|
141 |
+
# Define the bounds
|
142 |
+
lower_bounds = [-6, -6]
|
143 |
+
upper_bounds = [6, 6]
|
144 |
+
bounds = Bounds(lower_bounds, upper_bounds, enforce="resample")
|
145 |
+
|
146 |
+
# Create an instance of the QuasiRandomInitializer class
|
147 |
+
init = QuasiRandomInitializer(npart=50, ndim=2, bounds=bounds)
|
148 |
+
|
149 |
+
# Initialize the swarm
|
150 |
+
swarm_positions = init.InitializeSwarm()
|
151 |
+
|
152 |
+
print(f"Initial swarm positions: {swarm_positions}")
|
153 |
+
|
154 |
+
class GWO:
|
155 |
+
def __init__(self, obj, eta=2.0, npart=10, ndim=2, max_iter=200,tol=None,init=None,done=None,bounds=None):
|
156 |
+
self.obj = obj
|
157 |
+
self.npart = npart
|
158 |
+
self.ndim = ndim
|
159 |
+
self.max_iter = max_iter
|
160 |
+
self.init = init
|
161 |
+
self.done = done
|
162 |
+
self.bounds = bounds
|
163 |
+
self.tol = tol
|
164 |
+
self.eta = eta
|
165 |
+
self.initialized = False
|
166 |
+
|
167 |
+
def Initialize(self):
|
168 |
+
"""Set up the swarm"""
|
169 |
+
|
170 |
+
self.initialized = True
|
171 |
+
self.iterations = 0
|
172 |
+
|
173 |
+
self.pos = self.init.InitializeSwarm() # initial swarm positions
|
174 |
+
self.vpos= np.zeros(self.npart)
|
175 |
+
for i in range(self.npart):
|
176 |
+
self.vpos[i] = self.obj.Evaluate(self.pos[i])
|
177 |
+
|
178 |
+
# Initialize the list to store positions at each iteration
|
179 |
+
self.all_positions = []
|
180 |
+
self.all_positions.append(self.pos.copy()) # Store the initial positions
|
181 |
+
|
182 |
+
# Swarm bests
|
183 |
+
self.gidx = []
|
184 |
+
self.gbest = []
|
185 |
+
self.gpos = []
|
186 |
+
self.giter = []
|
187 |
+
idx = np.argmin(self.vpos)
|
188 |
+
self.gidx.append(idx)
|
189 |
+
self.gbest.append(self.vpos[idx])
|
190 |
+
self.gpos.append(self.pos[idx].copy())
|
191 |
+
self.giter.append(0)
|
192 |
+
|
193 |
+
# 1st, 2nd, and 3rd best positions
|
194 |
+
idx = np.argsort(self.vpos)
|
195 |
+
self.alpha = self.pos[idx[0]].copy()
|
196 |
+
self.valpha= self.vpos[idx[0]]
|
197 |
+
self.beta = self.pos[idx[1]].copy()
|
198 |
+
self.vbeta = self.vpos[idx[1]]
|
199 |
+
self.delta = self.pos[idx[2]].copy()
|
200 |
+
self.vdelta= self.vpos[idx[2]]
|
201 |
+
|
202 |
+
# *** Gradio app method optimize created [leveraged vis-a-vis optimize function on the outside of the underlying anatomy of GWO class] ***
|
203 |
+
def optimize(self):
|
204 |
+
"""
|
205 |
+
Run a full optimization and return the best positions and fitness values.
|
206 |
+
This method is designed to be used with Gradio.
|
207 |
+
"""
|
208 |
+
# Initialize the swarm
|
209 |
+
self.Initialize()
|
210 |
+
|
211 |
+
# Lists to store the best positions and fitness values at each step
|
212 |
+
best_positions = []
|
213 |
+
best_fitness = []
|
214 |
+
|
215 |
+
# Main loop
|
216 |
+
while not self.Done():
|
217 |
+
self.Step() # Perform an optimization step
|
218 |
+
# Update best_positions and best_fitness with the current best values
|
219 |
+
best_positions.append(self.gbest[-1])
|
220 |
+
best_fitness.append(self.gpos[-1])
|
221 |
+
|
222 |
+
# Print the best positions and fitness found
|
223 |
+
print("Best Positions:", best_positions)
|
224 |
+
print("Best Fitness:", best_fitness)
|
225 |
+
|
226 |
+
# Return the best positions and fitness after the optimization
|
227 |
+
return best_positions, best_fitness
|
228 |
+
|
229 |
+
def Step(self):
|
230 |
+
"""Do one swarm step"""
|
231 |
+
|
232 |
+
# a from eta ... zero (default eta is 2)
|
233 |
+
a = self.eta - self.eta*(self.iterations/self.max_iter)
|
234 |
+
|
235 |
+
# Update everyone
|
236 |
+
for i in range(self.npart):
|
237 |
+
A = 2*a*np.random.random(self.ndim) - a
|
238 |
+
C = 2*np.random.random(self.ndim)
|
239 |
+
Dalpha = np.abs(C*self.alpha - self.pos[i])
|
240 |
+
X1 = self.alpha - A*Dalpha
|
241 |
+
|
242 |
+
A = 2*a*np.random.random(self.ndim) - a
|
243 |
+
C = 2*np.random.random(self.ndim)
|
244 |
+
Dbeta = np.abs(C*self.beta - self.pos[i])
|
245 |
+
X2 = self.beta - A*Dbeta
|
246 |
+
|
247 |
+
A = 2*a*np.random.random(self.ndim) - a
|
248 |
+
C = 2*np.random.random(self.ndim)
|
249 |
+
Ddelta = np.abs(C*self.delta - self.pos[i])
|
250 |
+
X3 = self.delta - A*Ddelta
|
251 |
+
|
252 |
+
self.pos[i,:] = (X1+X2+X3) / 3.0
|
253 |
+
|
254 |
+
# Keep in bounds
|
255 |
+
if (self.bounds != None):
|
256 |
+
self.pos = self.bounds.Limits(self.pos)
|
257 |
+
|
258 |
+
# Get objective function values and check for new leaders
|
259 |
+
for i in range(self.npart):
|
260 |
+
self.vpos[i] = self.obj.Evaluate(self.pos[i])
|
261 |
+
|
262 |
+
# new alpha?
|
263 |
+
if (self.vpos[i] < self.valpha):
|
264 |
+
self.vdelta = self.vbeta
|
265 |
+
self.delta = self.beta.copy()
|
266 |
+
self.vbeta = self.valpha
|
267 |
+
self.beta = self.alpha.copy()
|
268 |
+
self.valpha = self.vpos[i]
|
269 |
+
self.alpha = self.pos[i].copy()
|
270 |
+
|
271 |
+
# new beta?
|
272 |
+
if (self.vpos[i] > self.valpha) and (self.vpos[i] < self.vbeta):
|
273 |
+
self.vdelta = self.vbeta
|
274 |
+
self.delta = self.beta.copy()
|
275 |
+
self.vbeta = self.vpos[i]
|
276 |
+
self.beta = self.pos[i].copy()
|
277 |
+
|
278 |
+
# new delta?
|
279 |
+
if (self.vpos[i] > self.valpha) and (self.vpos[i] < self.vbeta) and (self.vpos[i] < self.vdelta):
|
280 |
+
self.vdelta = self.vpos[i]
|
281 |
+
self.delta = self.pos[i].copy()
|
282 |
+
|
283 |
+
# is alpha new swarm best?
|
284 |
+
if (self.valpha < self.gbest[-1]):
|
285 |
+
self.gidx.append(i)
|
286 |
+
self.gbest.append(self.valpha)
|
287 |
+
np.save('best_fitness.npy', np.array(self.gbest))
|
288 |
+
self.gpos.append(self.alpha.copy())
|
289 |
+
np.save('best_positions.npy', np.array(self.gpos))
|
290 |
+
# Save the positions at the current iteration
|
291 |
+
self.all_positions.append(self.pos.copy())
|
292 |
+
np.save('all_positions.npy', np.array(self.all_positions), allow_pickle=True)
|
293 |
+
self.giter.append(self.iterations)
|
294 |
+
|
295 |
+
self.iterations += 1
|
296 |
+
|
297 |
+
def Done(self):
|
298 |
+
"""Check if we are done"""
|
299 |
+
|
300 |
+
if (self.done == None):
|
301 |
+
if (self.tol == None):
|
302 |
+
return (self.iterations == self.max_iter)
|
303 |
+
else:
|
304 |
+
return (self.gbest[-1] < self.tol) or (self.iterations == self.max_iter)
|
305 |
+
else:
|
306 |
+
return self.done.Done(self.gbest,
|
307 |
+
gpos=self.gpos,
|
308 |
+
pos=self.pos,
|
309 |
+
max_iter=self.max_iter,
|
310 |
+
iteration=self.iterations)
|
311 |
+
|
312 |
+
def Evaluate(self, pos):
|
313 |
+
p = np.zeros(self.npart)
|
314 |
+
for i in range(self.npart):
|
315 |
+
p[i] = self.obj.Evaluate(pos[i])
|
316 |
+
return p
|
317 |
+
|
318 |
+
def Results(self):
|
319 |
+
if (not self.initialized):
|
320 |
+
return None
|
321 |
+
return {
|
322 |
+
"npart": self.npart,
|
323 |
+
"ndim": self.ndim,
|
324 |
+
"max_iter": self.max_iter,
|
325 |
+
"iterations": self.iterations,
|
326 |
+
"tol": self.tol,
|
327 |
+
"eta": self.eta,
|
328 |
+
"gbest": self.gbest,
|
329 |
+
"giter": self.giter,
|
330 |
+
"gpos": self.gpos,
|
331 |
+
"gidx": self.gidx,
|
332 |
+
"pos": self.pos,
|
333 |
+
"vpos": self.vpos
|
334 |
+
}
|
335 |
+
def plot_contour_and_wolves(self, wolf_positions):
|
336 |
+
# Define the objective function
|
337 |
+
def objective_function(x, y):
|
338 |
+
return -5.0*np.exp(-0.5*((x+2.2)**2/0.4+(y-4.3)**2/0.4)) + -2.0*np.exp(-0.5*((x-2.2)**2/0.4+(y+4.3)**2/0.4))
|
339 |
+
|
340 |
+
best_postions_npy = np.load('best_positions.npy')
|
341 |
+
|
342 |
+
wolf_positions = best_positions_npy
|
343 |
+
|
344 |
+
# Determine the search space boundaries based on the wolf positions
|
345 |
+
x_min, x_max = wolf_positions[:, 0].min() - 1, wolf_positions[:, 0].max() + 1
|
346 |
+
y_min, y_max = wolf_positions[:, 1].min() - 1, wolf_positions[:, 1].max() + 1
|
347 |
+
|
348 |
+
# Generate a grid of points within the determined search space
|
349 |
+
x = np.linspace(x_min, x_max, 100)
|
350 |
+
y = np.linspace(y_min, y_max, 100)
|
351 |
+
X, Y = np.meshgrid(x, y)
|
352 |
+
|
353 |
+
# Evaluate the objective function on the grid
|
354 |
+
Z = objective_function(X, Y)
|
355 |
+
|
356 |
+
# Plot the contour map
|
357 |
+
plt.figure(figsize=(10, 8))
|
358 |
+
contour = plt.contour(X, Y, Z, levels=20, cmap='viridis')
|
359 |
+
plt.colorbar(contour)
|
360 |
+
|
361 |
+
# Plot the wolf positions
|
362 |
+
plt.plot(wolf_positions[:, 0], wolf_positions[:, 1], 'ro', markersize=5, label='Wolves')
|
363 |
+
|
364 |
+
# Set plot title and labels
|
365 |
+
plt.title('Contour Map of Wolves Oscillating Over Search Space')
|
366 |
+
plt.xlabel('x')
|
367 |
+
plt.ylabel('y')
|
368 |
+
plt.legend()
|
369 |
+
|
370 |
+
# Set the x and y limits of the plot based on the determined search space
|
371 |
+
plt.xlim(x_min, x_max)
|
372 |
+
plt.ylim(y_min, y_max)
|
373 |
+
|
374 |
+
# Convert the plot to a PIL Image and return it
|
375 |
+
buf = BytesIO()
|
376 |
+
plt.savefig(buf, format='png')
|
377 |
+
buf.seek(0)
|
378 |
+
plt.close() # Close the figure to free up memory
|
379 |
+
return Image.open(buf)
|
380 |
+
|
381 |
+
def Dispersion(self):
|
382 |
+
"""Calculate the dispersion of the swarm"""
|
383 |
+
x, y = self.gpos[:, 0], self.gpos[:, 1]
|
384 |
+
dx = x.max() - x.min()
|
385 |
+
dy = y.max() - y.min()
|
386 |
+
return (dx + dy) / 2.0
|
387 |
+
|
388 |
+
def plot_dispersion(self):
|
389 |
+
"""Plot the dispersion over time"""
|
390 |
+
# Assuming self.giter stores the iteration number at which each best position was found
|
391 |
+
# and self.gbest stores the corresponding best fitness values
|
392 |
+
dispersion_values = [self.Dispersion() for _ in range(self.max_iter)]
|
393 |
+
|
394 |
+
plt.figure(figsize=(10, 6))
|
395 |
+
plt.plot(range(self.max_iter), dispersion_values, label='Dispersion')
|
396 |
+
plt.xlabel('Iteration')
|
397 |
+
plt.ylabel('Dispersion')
|
398 |
+
plt.title('Evolution of Dispersion')
|
399 |
+
plt.legend()
|
400 |
+
plt.show()
|
401 |
+
|
402 |
+
# Convert the plot to a PIL Image and return it
|
403 |
+
buf = BytesIO()
|
404 |
+
plt.savefig(buf, format='png')
|
405 |
+
buf.seek(0)
|
406 |
+
plt.close() # Close the figure to free up memory
|
407 |
+
return Image.open(buf)
|
408 |
+
|
409 |
+
def plot_dispersion_heatmap(self, x_range, y_range, grid_size=100):
|
410 |
+
"""Plot a heatmap of dispersion over a grid of positions"""
|
411 |
+
x_values = np.linspace(x_range[0], x_range[1], grid_size)
|
412 |
+
y_values = np.linspace(y_range[0], y_range[1], grid_size)
|
413 |
+
X, Y = np.meshgrid(x_values, y_values)
|
414 |
+
positions = np.vstack([X.ravel(), Y.ravel()]).T
|
415 |
+
|
416 |
+
# Calculate dispersion for each position in the grid
|
417 |
+
dispersion_values = np.array([self.Dispersion(pos) for pos in positions])
|
418 |
+
Z = dispersion_values.reshape(X.shape)
|
419 |
+
|
420 |
+
plt.figure(figsize=(10, 8))
|
421 |
+
plt.imshow(Z, extent=(x_range[0], x_range[1], y_range[0], y_range[1]), origin='lower', cmap='viridis')
|
422 |
+
plt.colorbar(label='Dispersion')
|
423 |
+
plt.title('Heatmap of Dispersion')
|
424 |
+
plt.xlabel('X')
|
425 |
+
plt.ylabel('Y')
|
426 |
+
plt.show()
|
427 |
+
|
428 |
+
# Convert the plot to a PIL Image and return it
|
429 |
+
buf = BytesIO()
|
430 |
+
plt.savefig(buf, format='png')
|
431 |
+
buf.seek(0)
|
432 |
+
plt.close() # Close the figure to free up memory
|
433 |
+
return Image.open(buf)
|
434 |
+
|
435 |
+
|
436 |
+
|
437 |
+
|
438 |
+
|
439 |
+
def optimize(npart, ndim, max_iter):
|
440 |
+
# Initialize the GWO algorithm with the provided parameters
|
441 |
+
gwo = GWO(obj=obj, npart=npart, ndim=ndim, max_iter=max_iter, init=init, bounds=bounds)
|
442 |
+
|
443 |
+
# Run the optimization
|
444 |
+
best_positions, best_fitness = gwo.optimize()
|
445 |
+
|
446 |
+
# Get the best fitness and positions at the last iteration
|
447 |
+
last_best_fitness = best_fitness[-1]
|
448 |
+
last_best_positions = best_positions[-1]
|
449 |
+
|
450 |
+
# Format the output strings
|
451 |
+
best_fitness_text = f"Best Positions: {last_best_fitness}"
|
452 |
+
best_positions_text = f"Best Fitness: {last_best_positions}"
|
453 |
+
|
454 |
+
# Get the contour plot as a PIL Image
|
455 |
+
contour_plot = gwo.plot_contour_and_wolves(wolf_positions)
|
456 |
+
|
457 |
+
# Calculate the dispersion
|
458 |
+
dispersion = gwo.Dispersion()
|
459 |
+
|
460 |
+
# Format the output strings
|
461 |
+
best_fitness_text = f"Best Positions: {last_best_fitness}"
|
462 |
+
best_positions_text = f"Best Fitness: {last_best_positions}"
|
463 |
+
dispersion_text = f"Dispersion: {dispersion}"
|
464 |
+
|
465 |
+
# Plot the dispersion over time
|
466 |
+
dispersion_plot = gwo.plot_dispersion()
|
467 |
+
|
468 |
+
# Plot the dispersion heatmap
|
469 |
+
dispersion_heatmap_plot = gwo.plot_dispersion_heatmap(x_range=(-6,6), y_range=(-6,6))
|
470 |
+
|
471 |
+
|
472 |
+
# Return the positions plot, the text for the best fitness and positions, and the loaded data
|
473 |
+
return [contour_plot, dispersion_plot, dispersion_heatmap_plot], best_fitness_text, best_positions_text, best_fitness_npy, best_positions_npy, dispersion_text
|
474 |
+
|
475 |
+
|
476 |
+
|
477 |
+
# Define the Gradio interface
|
478 |
+
iface = gr.Interface(
|
479 |
+
fn=optimize, # Pass the optimize function object
|
480 |
+
inputs=[
|
481 |
+
gr.components.Slider(10, 50, 50, step=1, label="Number of Wolves [Default = 50 Wolves]"),
|
482 |
+
gr.components.Slider(2, 2, 2, step=1, label="Two-Dimensional Search Space"),
|
483 |
+
gr.components.Slider(100, 200, 200, step=1, label="Maximum Iterations [Default = 200 Epochs]"),
|
484 |
+
],
|
485 |
+
outputs=[
|
486 |
+
gr.components.Image(type="pil", label="Contour Map of Wolves Oscillating Over Search Space"),
|
487 |
+
gr.components.Image(type="pil", label="Dispersion Plot"),
|
488 |
+
gr.components.Image(type="pil", label="Dispersion Heatmap Plot"),
|
489 |
+
gr.components.Textbox(label="Dispersion Values"),
|
490 |
+
gr.components.Textbox(label="Best Positions"),
|
491 |
+
gr.components.Textbox(label="Best Fitness")
|
492 |
+
|
493 |
+
],
|
494 |
+
title="Grey Wolf Optimizer",
|
495 |
+
description="Optimize the objective function using the Grey Wolf Optimizer.",
|
496 |
+
article="## Grey Wolf Optimizer\nThe Grey Wolf Optimizer (GWO) is a population-based metaheuristic optimization algorithm inspired by the social behavior of grey wolves in nature."
|
497 |
+
)
|
498 |
+
|
499 |
+
# Launch the Gradio interface
|
500 |
+
iface.launch()
|