TroglodyteDerivations commited on
Commit
b8440f4
·
verified ·
1 Parent(s): f9fcc04

Upload 7 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ output.mp4 filter=lfs diff=lfs merge=lfs -text
37
+ Screenshot[[:space:]]2025-11-03[[:space:]]at[[:space:]]2.01.25 PM.png filter=lfs diff=lfs merge=lfs -text
38
+ Screenshot[[:space:]]2025-11-03[[:space:]]at[[:space:]]2.02.02 PM.png filter=lfs diff=lfs merge=lfs -text
39
+ Screenshot[[:space:]]2025-11-03[[:space:]]at[[:space:]]2.02.38 PM.png filter=lfs diff=lfs merge=lfs -text
40
+ Screenshot[[:space:]]2025-11-03[[:space:]]at[[:space:]]2.03.29 PM.png filter=lfs diff=lfs merge=lfs -text
Screenshot 2025-11-03 at 2.01.25 PM.png ADDED

Git LFS Details

  • SHA256: 8f697b522e81b1eee240b38258b7b05757c54bda595e6f0cc2c0734f8b29b9cf
  • Pointer size: 132 Bytes
  • Size of remote file: 1.03 MB
Screenshot 2025-11-03 at 2.02.02 PM.png ADDED

Git LFS Details

  • SHA256: 019770865bfdd08908f0b003fe525a4c889f60d12474b0a93b990d06aac9273e
  • Pointer size: 132 Bytes
  • Size of remote file: 1.28 MB
Screenshot 2025-11-03 at 2.02.38 PM.png ADDED

Git LFS Details

  • SHA256: 4a8025c2df642cb7fd51fb7648195eea3c218d028e16222b9bcf82bc33a42c91
  • Pointer size: 132 Bytes
  • Size of remote file: 1.02 MB
Screenshot 2025-11-03 at 2.03.29 PM.png ADDED

Git LFS Details

  • SHA256: a7294968a90fb1c9e43b9fc2b894b961893fcb379cf4c93770dfd0c985bac4a0
  • Pointer size: 131 Bytes
  • Size of remote file: 877 kB
app.py ADDED
@@ -0,0 +1,629 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import numpy as np
3
+ import matplotlib.pyplot as plt
4
+ from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
5
+ from matplotlib.figure import Figure
6
+ from mpl_toolkits.mplot3d import Axes3D
7
+ import random
8
+ from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout,
9
+ QWidget, QComboBox, QPushButton, QLabel, QSpinBox,
10
+ QDoubleSpinBox, QGroupBox, QGridLayout, QTextEdit,
11
+ QSplitter, QProgressBar)
12
+ from PyQt5.QtCore import QTimer, Qt
13
+ from PyQt5.QtGui import QFont
14
+
15
+ class Particle:
16
+ def __init__(self, dim, bounds):
17
+ self.dim = dim
18
+ self.position = np.array([random.uniform(bounds[i][0], bounds[i][1]) for i in range(dim)])
19
+ self.velocity = np.array([random.uniform(-1, 1) for _ in range(dim)])
20
+ self.best_position = self.position.copy()
21
+ self.best_value = float('inf')
22
+ self.bounds = bounds
23
+
24
+ def update_velocity(self, global_best_position, w, c1, c2):
25
+ for i in range(self.dim):
26
+ r1, r2 = random.random(), random.random()
27
+ cognitive = c1 * r1 * (self.best_position[i] - self.position[i])
28
+ social = c2 * r2 * (global_best_position[i] - self.position[i])
29
+ self.velocity[i] = w * self.velocity[i] + cognitive + social
30
+
31
+ def update_position(self):
32
+ self.position += self.velocity
33
+ # Apply bounds
34
+ for i in range(self.dim):
35
+ if self.position[i] < self.bounds[i][0]:
36
+ self.position[i] = self.bounds[i][0]
37
+ self.velocity[i] *= -0.5
38
+ elif self.position[i] > self.bounds[i][1]:
39
+ self.position[i] = self.bounds[i][1]
40
+ self.velocity[i] *= -0.5
41
+
42
+ class PSO:
43
+ def __init__(self, objective_func, dim, bounds, num_particles=30, w=0.7, c1=1.4, c2=1.4):
44
+ self.objective_func = objective_func
45
+ self.dim = dim
46
+ self.bounds = bounds
47
+ self.num_particles = num_particles
48
+ self.w = w
49
+ self.c1 = c1
50
+ self.c2 = c2
51
+
52
+ self.particles = [Particle(dim, bounds) for _ in range(num_particles)]
53
+ self.global_best_position = np.array([random.uniform(bounds[i][0], bounds[i][1]) for i in range(dim)])
54
+ self.global_best_value = float('inf')
55
+ self.history = []
56
+
57
+ def optimize(self, max_iterations):
58
+ for iteration in range(max_iterations):
59
+ for particle in self.particles:
60
+ # Evaluate fitness
61
+ value = self.objective_func(particle.position)
62
+
63
+ # Update personal best
64
+ if value < particle.best_value:
65
+ particle.best_value = value
66
+ particle.best_position = particle.position.copy()
67
+
68
+ # Update global best
69
+ if value < self.global_best_value:
70
+ self.global_best_value = value
71
+ self.global_best_position = particle.position.copy()
72
+
73
+ # Update velocities and positions
74
+ for particle in self.particles:
75
+ particle.update_velocity(self.global_best_position, self.w, self.c1, self.c2)
76
+ particle.update_position()
77
+
78
+ # Save history for visualization
79
+ self.history.append({
80
+ 'positions': [p.position.copy() for p in self.particles],
81
+ 'global_best': self.global_best_position.copy(),
82
+ 'global_best_value': self.global_best_value,
83
+ 'iteration': iteration
84
+ })
85
+
86
+ return self.global_best_position, self.global_best_value
87
+
88
+ class EquationDefinitions:
89
+ @staticmethod
90
+ def get_equations():
91
+ equations = {
92
+ # 2D Equations
93
+ "Sphere Function": {
94
+ "func": lambda x: sum(xi**2 for xi in x),
95
+ "dim": 2,
96
+ "bounds": [(-5.12, 5.12), (-5.12, 5.12)],
97
+ "description": "f(x,y) = x² + y²\nMinimum at (0,0)"
98
+ },
99
+ "Rosenbrock Function": {
100
+ "func": lambda x: 100*(x[1]-x[0]**2)**2 + (1-x[0])**2,
101
+ "dim": 2,
102
+ "bounds": [(-2, 2), (-1, 3)],
103
+ "description": "f(x,y) = 100(y-x²)² + (1-x)²\nMinimum at (1,1)"
104
+ },
105
+ "Rastrigin Function": {
106
+ "func": lambda x: 20 + sum(xi**2 - 10*np.cos(2*np.pi*xi) for xi in x),
107
+ "dim": 2,
108
+ "bounds": [(-5.12, 5.12), (-5.12, 5.12)],
109
+ "description": "f(x,y) = 20 + x²+y² -10(cos(2πx)+cos(2πy))\nMinimum at (0,0)"
110
+ },
111
+ "Ackley Function": {
112
+ "func": lambda x: -20*np.exp(-0.2*np.sqrt(0.5*sum(xi**2 for xi in x))) -
113
+ np.exp(0.5*sum(np.cos(2*np.pi*xi) for xi in x)) + 20 + np.e,
114
+ "dim": 2,
115
+ "bounds": [(-5, 5), (-5, 5)],
116
+ "description": "Complex function with many local minima\nMinimum at (0,0)"
117
+ },
118
+ "Matyas Function": {
119
+ "func": lambda x: 0.26*(x[0]**2 + x[1]**2) - 0.48*x[0]*x[1],
120
+ "dim": 2,
121
+ "bounds": [(-10, 10), (-10, 10)],
122
+ "description": "f(x,y) = 0.26(x²+y²) - 0.48xy\nMinimum at (0,0)"
123
+ },
124
+ "Himmelblau's Function": {
125
+ "func": lambda x: (x[0]**2 + x[1] - 11)**2 + (x[0] + x[1]**2 - 7)**2,
126
+ "dim": 2,
127
+ "bounds": [(-5, 5), (-5, 5)],
128
+ "description": "f(x,y) = (x²+y-11)² + (x+y²-7)²\n4 minima at (3,2), (-2.8,3.1), (-3.8,-3.3), (3.6,-1.8)"
129
+ },
130
+ "Three-Hump Camel": {
131
+ "func": lambda x: 2*x[0]**2 - 1.05*x[0]**4 + x[0]**6/6 + x[0]*x[1] + x[1]**2,
132
+ "dim": 2,
133
+ "bounds": [(-5, 5), (-5, 5)],
134
+ "description": "f(x,y) = 2x² -1.05x⁴ + x⁶/6 + xy + y²\nMinimum at (0,0)"
135
+ },
136
+ "Easom Function": {
137
+ "func": lambda x: -np.cos(x[0])*np.cos(x[1])*np.exp(-((x[0]-np.pi)**2 + (x[1]-np.pi)**2)),
138
+ "dim": 2,
139
+ "bounds": [(-10, 10), (-10, 10)],
140
+ "description": "f(x,y) = -cos(x)cos(y)exp(-((x-π)²+(y-π)²))\nMinimum at (π,π)"
141
+ },
142
+ "Cross-in-Tray": {
143
+ "func": lambda x: -0.0001*(abs(np.sin(x[0])*np.sin(x[1])*np.exp(abs(100-np.sqrt(x[0]**2+x[1]**2)/np.pi))) + 1)**0.1,
144
+ "dim": 2,
145
+ "bounds": [(-10, 10), (-10, 10)],
146
+ "description": "Multiple global minima in cross pattern"
147
+ },
148
+ "Holder Table": {
149
+ "func": lambda x: -abs(np.sin(x[0])*np.cos(x[1])*np.exp(abs(1-np.sqrt(x[0]**2+x[1]**2)/np.pi))),
150
+ "dim": 2,
151
+ "bounds": [(-10, 10), (-10, 10)],
152
+ "description": "Multiple minima in table-like pattern"
153
+ },
154
+
155
+ # 3D Equations
156
+ "Sphere 3D": {
157
+ "func": lambda x: sum(xi**2 for xi in x),
158
+ "dim": 3,
159
+ "bounds": [(-5.12, 5.12), (-5.12, 5.12), (-5.12, 5.12)],
160
+ "description": "f(x,y,z) = x² + y² + z²\nMinimum at (0,0,0)"
161
+ },
162
+ "Rosenbrock 3D": {
163
+ "func": lambda x: sum(100*(x[i+1]-x[i]**2)**2 + (1-x[i])**2 for i in range(len(x)-1)),
164
+ "dim": 3,
165
+ "bounds": [(-2, 2), (-2, 2), (-2, 2)],
166
+ "description": "3D extension of Rosenbrock\nMinimum at (1,1,1)"
167
+ },
168
+ "Rastrigin 3D": {
169
+ "func": lambda x: 30 + sum(xi**2 - 10*np.cos(2*np.pi*xi) for xi in x),
170
+ "dim": 3,
171
+ "bounds": [(-5.12, 5.12), (-5.12, 5.12), (-5.12, 5.12)],
172
+ "description": "3D Rastrigin function\nMinimum at (0,0,0)"
173
+ },
174
+ "Ackley 3D": {
175
+ "func": lambda x: -20*np.exp(-0.2*np.sqrt(1/3*sum(xi**2 for xi in x))) -
176
+ np.exp(1/3*sum(np.cos(2*np.pi*xi) for xi in x)) + 20 + np.e,
177
+ "dim": 3,
178
+ "bounds": [(-5, 5), (-5, 5), (-5, 5)],
179
+ "description": "3D Ackley function\nMinimum at (0,0,0)"
180
+ },
181
+ "Sum of Different Powers": {
182
+ "func": lambda x: sum(abs(xi)**(i+2) for i, xi in enumerate(x)),
183
+ "dim": 3,
184
+ "bounds": [(-1, 1), (-1, 1), (-1, 1)],
185
+ "description": "f(x,y,z) = |x|² + |y|³ + |z|⁴\nMinimum at (0,0,0)"
186
+ },
187
+ "Rotated Hyper-Ellipsoid": {
188
+ "func": lambda x: sum(sum(x[j]**2 for j in range(i+1)) for i in range(len(x))),
189
+ "dim": 3,
190
+ "bounds": [(-5.12, 5.12), (-5.12, 5.12), (-5.12, 5.12)],
191
+ "description": "f(x,y,z) = x² + (x²+y²) + (x²+y²+z²)\nMinimum at (0,0,0)"
192
+ },
193
+ "Zakharov 3D": {
194
+ "func": lambda x: sum(xi**2 for xi in x) + (0.5*sum(i*xi for i, xi in enumerate(x, 1)))**2 + (0.5*sum(i*xi for i, xi in enumerate(x, 1)))**4,
195
+ "dim": 3,
196
+ "bounds": [(-5, 10), (-5, 10), (-5, 10)],
197
+ "description": "Zakharov function in 3D\nMinimum at (0,0,0)"
198
+ },
199
+ "Dixon-Price": {
200
+ "func": lambda x: (x[0]-1)**2 + sum(i*(2*x[i]**2 - x[i-1])**2 for i in range(1, len(x))),
201
+ "dim": 3,
202
+ "bounds": [(-10, 10), (-10, 10), (-10, 10)],
203
+ "description": "Dixon-Price function\nMinimum depends on dimension"
204
+ },
205
+ "Levy 3D": {
206
+ "func": lambda x: (
207
+ np.sin(np.pi * (1 + (x[0] - 1) / 4))**2 +
208
+ sum(
209
+ ((1 + (x[i] - 1) / 4 - 1)**2 *
210
+ (1 + 10 * np.sin(np.pi * (1 + (x[i] - 1) / 4) + 1)**2))
211
+ for i in range(len(x) - 1)
212
+ ) +
213
+ ((1 + (x[-1] - 1) / 4 - 1)**2 *
214
+ (1 + np.sin(2 * np.pi * (1 + (x[-1] - 1) / 4))**2))
215
+ ),
216
+ "dim": 3,
217
+ "bounds": [(-10, 10), (-10, 10), (-10, 10)],
218
+ "description": "Levy function in 3D\nMinimum at (1,1,1)"
219
+ },
220
+ "Michalewicz 3D": {
221
+ "func": lambda x: -sum(np.sin(x[i]) * np.sin((i+1)*x[i]**2/np.pi)**20 for i in range(len(x))),
222
+ "dim": 3,
223
+ "bounds": [(0, np.pi), (0, np.pi), (0, np.pi)],
224
+ "description": "Michalewicz function\nMany local minima, hard global optimization"
225
+ }
226
+ }
227
+ return equations
228
+
229
+ class PlotCanvas(FigureCanvas):
230
+ def __init__(self, parent=None, width=5, height=4, dpi=100, is_3d=False):
231
+ self.fig = Figure(figsize=(width, height), dpi=dpi)
232
+ super().__init__(self.fig)
233
+ self.setParent(parent)
234
+ self.is_3d = is_3d
235
+
236
+ if is_3d:
237
+ self.ax = self.fig.add_subplot(111, projection='3d')
238
+ else:
239
+ self.ax = self.fig.add_subplot(111)
240
+
241
+ self.ax.grid(True, alpha=0.3)
242
+
243
+ def plot_optimization(self, equation_info, particles_history, current_iteration):
244
+ self.ax.clear()
245
+
246
+ if current_iteration >= len(particles_history):
247
+ return
248
+
249
+ current_data = particles_history[current_iteration]
250
+ positions = current_data['positions']
251
+
252
+ if equation_info['dim'] == 2:
253
+ self._plot_2d(equation_info, positions, current_data)
254
+ else:
255
+ if self.is_3d:
256
+ self._plot_3d(equation_info, positions, current_data)
257
+ else:
258
+ self._plot_3d_projection(equation_info, positions, current_data)
259
+
260
+ self.ax.set_title(f'Iteration {current_iteration + 1}\nBest Value: {current_data["global_best_value"]:.6f}')
261
+ self.draw()
262
+
263
+ def _plot_2d(self, equation_info, positions, current_data):
264
+ # Create contour plot of the function
265
+ bounds = equation_info['bounds']
266
+ x = np.linspace(bounds[0][0], bounds[0][1], 100)
267
+ y = np.linspace(bounds[1][0], bounds[1][1], 100)
268
+ X, Y = np.meshgrid(x, y)
269
+ Z = np.array([[equation_info['func']([xi, yi]) for xi in x] for yi in y])
270
+
271
+ # Plot contour
272
+ contour = self.ax.contour(X, Y, Z, levels=20, alpha=0.6)
273
+ self.ax.clabel(contour, inline=True, fontsize=8)
274
+
275
+ # Plot particles
276
+ particle_x = [p[0] for p in positions]
277
+ particle_y = [p[1] for p in positions]
278
+ self.ax.scatter(particle_x, particle_y, c='red', s=30, alpha=0.7, label='Particles')
279
+
280
+ # Plot global best
281
+ self.ax.scatter(current_data['global_best'][0], current_data['global_best'][1],
282
+ c='green', s=100, marker='*', label='Global Best')
283
+
284
+ self.ax.set_xlabel('X')
285
+ self.ax.set_ylabel('Y')
286
+ self.ax.legend()
287
+
288
+ def _plot_3d(self, equation_info, positions, current_data):
289
+ bounds = equation_info['bounds']
290
+ x = np.linspace(bounds[0][0], bounds[0][1], 30)
291
+ y = np.linspace(bounds[1][0], bounds[1][1], 30)
292
+ X, Y = np.meshgrid(x, y)
293
+
294
+ # For 3D functions, we'll fix the third dimension for visualization
295
+ if len(positions[0]) == 3:
296
+ fixed_z = current_data['global_best'][2] # Use best z value
297
+ Z = np.array([[equation_info['func']([xi, yi, fixed_z]) for xi in x] for yi in y])
298
+
299
+ # Plot surface
300
+ self.ax.plot_surface(X, Y, Z, cmap='viridis', alpha=0.6)
301
+
302
+ # Plot particles
303
+ particle_x = [p[0] for p in positions]
304
+ particle_y = [p[1] for p in positions]
305
+ particle_z = [equation_info['func']([p[0], p[1], fixed_z]) for p in positions]
306
+ self.ax.scatter(particle_x, particle_y, particle_z, c='red', s=30, alpha=0.7, label='Particles')
307
+
308
+ # Plot global best
309
+ best_x, best_y = current_data['global_best'][0], current_data['global_best'][1]
310
+ best_z = equation_info['func']([best_x, best_y, fixed_z])
311
+ self.ax.scatter([best_x], [best_y], [best_z], c='green', s=100, marker='*', label='Global Best')
312
+
313
+ self.ax.set_xlabel('X')
314
+ self.ax.set_ylabel('Y')
315
+ self.ax.set_zlabel('f(X,Y)')
316
+
317
+ self.ax.legend()
318
+
319
+ def _plot_3d_projection(self, equation_info, positions, current_data):
320
+ """2D projection of 3D function by fixing one dimension"""
321
+ bounds = equation_info['bounds']
322
+
323
+ # Use the best position to determine which dimensions to fix
324
+ best_pos = current_data['global_best']
325
+
326
+ # Create a 2D projection by fixing one dimension
327
+ x = np.linspace(bounds[0][0], bounds[0][1], 100)
328
+ y = np.linspace(bounds[1][0], bounds[1][1], 100)
329
+ X, Y = np.meshgrid(x, y)
330
+
331
+ # Fix the third dimension at the best value
332
+ fixed_z = best_pos[2] if len(best_pos) > 2 else 0
333
+ Z = np.array([[equation_info['func']([xi, yi, fixed_z]) for xi in x] for yi in y])
334
+
335
+ # Plot contour
336
+ contour = self.ax.contour(X, Y, Z, levels=20, alpha=0.6)
337
+ self.ax.clabel(contour, inline=True, fontsize=8)
338
+
339
+ # Plot particles (only first two dimensions)
340
+ particle_x = [p[0] for p in positions]
341
+ particle_y = [p[1] for p in positions]
342
+ self.ax.scatter(particle_x, particle_y, c='red', s=30, alpha=0.7, label='Particles')
343
+
344
+ # Plot global best
345
+ self.ax.scatter(best_pos[0], best_pos[1], c='green', s=100, marker='*', label='Global Best')
346
+
347
+ self.ax.set_xlabel('X')
348
+ self.ax.set_ylabel('Y')
349
+ self.ax.set_title(f'3D Function Projection (Z fixed at {fixed_z:.3f})')
350
+ self.ax.legend()
351
+
352
+ class PSOApp(QMainWindow):
353
+ def __init__(self):
354
+ super().__init__()
355
+ self.equations = EquationDefinitions.get_equations()
356
+ self.current_pso = None
357
+ self.current_iteration = 0
358
+ self.timer = QTimer()
359
+ self.timer.timeout.connect(self.update_visualization)
360
+
361
+ self.init_ui()
362
+
363
+ def init_ui(self):
364
+ self.setWindowTitle("Particle Swarm Optimization - 20 Equations Solver")
365
+ self.setGeometry(100, 100, 1600, 1000)
366
+
367
+ # Central widget
368
+ central_widget = QWidget()
369
+ self.setCentralWidget(central_widget)
370
+
371
+ # Main layout
372
+ main_layout = QHBoxLayout(central_widget)
373
+
374
+ # Left panel for controls
375
+ left_panel = QWidget()
376
+ left_panel.setMaximumWidth(400)
377
+ left_layout = QVBoxLayout(left_panel)
378
+
379
+ # Equation selection
380
+ equation_group = QGroupBox("Equation Selection")
381
+ equation_layout = QVBoxLayout(equation_group)
382
+
383
+ self.equation_combo = QComboBox()
384
+ self.equation_combo.addItems(self.equations.keys())
385
+ self.equation_combo.currentTextChanged.connect(self.on_equation_changed)
386
+ equation_layout.addWidget(QLabel("Select Equation:"))
387
+ equation_layout.addWidget(self.equation_combo)
388
+
389
+ self.equation_desc = QTextEdit()
390
+ self.equation_desc.setMaximumHeight(100)
391
+ self.equation_desc.setReadOnly(True)
392
+ equation_layout.addWidget(QLabel("Description:"))
393
+ equation_layout.addWidget(self.equation_desc)
394
+
395
+ left_layout.addWidget(equation_group)
396
+
397
+ # PSO Parameters
398
+ params_group = QGroupBox("PSO Parameters")
399
+ params_layout = QGridLayout(params_group)
400
+
401
+ params_layout.addWidget(QLabel("Particles:"), 0, 0)
402
+ self.particles_spin = QSpinBox()
403
+ self.particles_spin.setRange(10, 100)
404
+ self.particles_spin.setValue(30)
405
+ params_layout.addWidget(self.particles_spin, 0, 1)
406
+
407
+ params_layout.addWidget(QLabel("Iterations:"), 1, 0)
408
+ self.iterations_spin = QSpinBox()
409
+ self.iterations_spin.setRange(10, 500)
410
+ self.iterations_spin.setValue(100)
411
+ params_layout.addWidget(self.iterations_spin, 1, 1)
412
+
413
+ params_layout.addWidget(QLabel("Inertia (w):"), 2, 0)
414
+ self.w_spin = QDoubleSpinBox()
415
+ self.w_spin.setRange(0.1, 1.0)
416
+ self.w_spin.setSingleStep(0.1)
417
+ self.w_spin.setValue(0.7)
418
+ params_layout.addWidget(self.w_spin, 2, 1)
419
+
420
+ params_layout.addWidget(QLabel("Cognitive (c1):"), 3, 0)
421
+ self.c1_spin = QDoubleSpinBox()
422
+ self.c1_spin.setRange(0.1, 2.0)
423
+ self.c1_spin.setSingleStep(0.1)
424
+ self.c1_spin.setValue(1.4)
425
+ params_layout.addWidget(self.c1_spin, 3, 1)
426
+
427
+ params_layout.addWidget(QLabel("Social (c2):"), 4, 0)
428
+ self.c2_spin = QDoubleSpinBox()
429
+ self.c2_spin.setRange(0.1, 2.0)
430
+ self.c2_spin.setSingleStep(0.1)
431
+ self.c2_spin.setValue(1.4)
432
+ params_layout.addWidget(self.c2_spin, 4, 1)
433
+
434
+ left_layout.addWidget(params_group)
435
+
436
+ # Control buttons
437
+ control_group = QGroupBox("Controls")
438
+ control_layout = QVBoxLayout(control_group)
439
+
440
+ self.run_button = QPushButton("Run PSO")
441
+ self.run_button.clicked.connect(self.run_pso)
442
+ control_layout.addWidget(self.run_button)
443
+
444
+ self.pause_button = QPushButton("Pause")
445
+ self.pause_button.clicked.connect(self.toggle_pause)
446
+ self.pause_button.setEnabled(False)
447
+ control_layout.addWidget(self.pause_button)
448
+
449
+ self.step_button = QPushButton("Step")
450
+ self.step_button.clicked.connect(self.step_forward)
451
+ self.step_button.setEnabled(False)
452
+ control_layout.addWidget(self.step_button)
453
+
454
+ self.reset_button = QPushButton("Reset")
455
+ self.reset_button.clicked.connect(self.reset)
456
+ control_layout.addWidget(self.reset_button)
457
+
458
+ left_layout.addWidget(control_group)
459
+
460
+ # Progress
461
+ progress_group = QGroupBox("Progress")
462
+ progress_layout = QVBoxLayout(progress_group)
463
+
464
+ self.progress_bar = QProgressBar()
465
+ self.progress_bar.setValue(0)
466
+ progress_layout.addWidget(self.progress_bar)
467
+
468
+ self.status_label = QLabel("Ready to optimize")
469
+ progress_layout.addWidget(self.status_label)
470
+
471
+ self.results_text = QTextEdit()
472
+ self.results_text.setMaximumHeight(150)
473
+ self.results_text.setReadOnly(True)
474
+ progress_layout.addWidget(self.results_text)
475
+
476
+ left_layout.addWidget(progress_group)
477
+ left_layout.addStretch()
478
+
479
+ # Right panel for visualizations
480
+ right_panel = QWidget()
481
+ right_layout = QVBoxLayout(right_panel)
482
+
483
+ # Create splitter for 2D and 3D plots
484
+ splitter = QSplitter(Qt.Vertical)
485
+
486
+ self.plot_2d = PlotCanvas(self, width=8, height=6, dpi=100, is_3d=False)
487
+ self.plot_3d = PlotCanvas(self, width=8, height=6, dpi=100, is_3d=True)
488
+
489
+ splitter.addWidget(self.plot_2d)
490
+ splitter.addWidget(self.plot_3d)
491
+ splitter.setSizes([500, 500])
492
+
493
+ right_layout.addWidget(splitter)
494
+
495
+ # Add panels to main layout
496
+ main_layout.addWidget(left_panel)
497
+ main_layout.addWidget(right_panel)
498
+
499
+ # Initialize with first equation
500
+ self.on_equation_changed(self.equation_combo.currentText())
501
+
502
+ def on_equation_changed(self, equation_name):
503
+ equation_info = self.equations[equation_name]
504
+ self.equation_desc.setText(equation_info['description'])
505
+
506
+ def run_pso(self):
507
+ try:
508
+ equation_name = self.equation_combo.currentText()
509
+ equation_info = self.equations[equation_name]
510
+
511
+ # Get PSO parameters
512
+ num_particles = self.particles_spin.value()
513
+ max_iterations = self.iterations_spin.value()
514
+ w = self.w_spin.value()
515
+ c1 = self.c1_spin.value()
516
+ c2 = self.c2_spin.value()
517
+
518
+ # Run PSO
519
+ self.current_pso = PSO(
520
+ objective_func=equation_info['func'],
521
+ dim=equation_info['dim'],
522
+ bounds=equation_info['bounds'],
523
+ num_particles=num_particles,
524
+ w=w, c1=c1, c2=c2
525
+ )
526
+
527
+ # Run optimization
528
+ best_position, best_value = self.current_pso.optimize(max_iterations)
529
+
530
+ # Display results
531
+ self.results_text.setText(
532
+ f"Optimization Complete!\n"
533
+ f"Best Position: {[f'{x:.6f}' for x in best_position]}\n"
534
+ f"Best Value: {best_value:.10f}\n"
535
+ f"Equation: {equation_name}"
536
+ )
537
+
538
+ # Setup visualization
539
+ self.current_iteration = 0
540
+ self.progress_bar.setMaximum(max_iterations - 1)
541
+ self.update_visualization()
542
+
543
+ # Enable controls
544
+ self.pause_button.setEnabled(True)
545
+ self.step_button.setEnabled(True)
546
+ self.run_button.setEnabled(False)
547
+
548
+ # Start animation timer
549
+ self.timer.start(100) # Update every 100ms
550
+
551
+ except Exception as e:
552
+ self.results_text.setText(f"Error during optimization: {str(e)}")
553
+
554
+ def toggle_pause(self):
555
+ if self.timer.isActive():
556
+ self.timer.stop()
557
+ self.pause_button.setText("Resume")
558
+ else:
559
+ self.timer.start(100)
560
+ self.pause_button.setText("Pause")
561
+
562
+ def step_forward(self):
563
+ if self.current_pso and self.current_iteration < len(self.current_pso.history) - 1:
564
+ self.current_iteration += 1
565
+ self.update_visualization()
566
+
567
+ def reset(self):
568
+ self.timer.stop()
569
+ self.current_pso = None
570
+ self.current_iteration = 0
571
+ self.progress_bar.setValue(0)
572
+ self.status_label.setText("Ready to optimize")
573
+ self.results_text.clear()
574
+ self.pause_button.setEnabled(False)
575
+ self.step_button.setEnabled(False)
576
+ self.run_button.setEnabled(True)
577
+ self.pause_button.setText("Pause")
578
+
579
+ # Clear plots
580
+ self.plot_2d.ax.clear()
581
+ self.plot_3d.ax.clear()
582
+ self.plot_2d.draw()
583
+ self.plot_3d.draw()
584
+
585
+ def update_visualization(self):
586
+ if not self.current_pso or self.current_iteration >= len(self.current_pso.history):
587
+ self.timer.stop()
588
+ self.status_label.setText("Optimization Complete!")
589
+ return
590
+
591
+ equation_name = self.equation_combo.currentText()
592
+ equation_info = self.equations[equation_name]
593
+
594
+ try:
595
+ # Update 2D plot
596
+ self.plot_2d.plot_optimization(equation_info, self.current_pso.history, self.current_iteration)
597
+
598
+ # Update 3D plot
599
+ self.plot_3d.plot_optimization(equation_info, self.current_pso.history, self.current_iteration)
600
+
601
+ # Update progress
602
+ self.progress_bar.setValue(self.current_iteration)
603
+ self.status_label.setText(f"Iteration {self.current_iteration + 1}/{len(self.current_pso.history)}")
604
+
605
+ self.current_iteration += 1
606
+
607
+ if self.current_iteration >= len(self.current_pso.history):
608
+ self.timer.stop()
609
+ self.status_label.setText("Optimization Complete!")
610
+
611
+ except Exception as e:
612
+ self.status_label.setText(f"Visualization error: {str(e)}")
613
+ self.timer.stop()
614
+
615
+ def main():
616
+ app = QApplication(sys.argv)
617
+ app.setStyle('Fusion') # Modern style
618
+
619
+ # Set application font
620
+ font = QFont("Arial", 10)
621
+ app.setFont(font)
622
+
623
+ window = PSOApp()
624
+ window.show()
625
+
626
+ sys.exit(app.exec_())
627
+
628
+ if __name__ == '__main__':
629
+ main()
output.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fd13d1ed7ca29b3fae509f95dea28635528fbec0fce03907e77d66f8680c1716
3
+ size 80989466
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ numpy
2
+ matplotlib
3
+ PyQt5
4
+ PyQt5-sip