Sephfox commited on
Commit
81be535
1 Parent(s): 137049e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +288 -0
app.py ADDED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import numpy as np
3
+ import random
4
+ import matplotlib.pyplot as plt
5
+ from scipy.spatial import distance
6
+ from sklearn.cluster import KMeans
7
+ import networkx as nx
8
+ from collections import deque
9
+
10
+ # Constants
11
+ GRID_SIZE = 200
12
+ FOOD_SOURCES = [(20, 20), (80, 80), (150, 150), (40, 160), (180, 30)]
13
+ OBSTACLES = [(50, 50), (100, 100), (150, 50), (70, 130), (120, 80)]
14
+ PHEROMONE_DECAY_RATE = 0.02
15
+ PHEROMONE_DIFFUSION_RATE = 0.05
16
+ MAX_ANTS = 100
17
+ MUTATION_RATE = 0.01
18
+
19
+ # Pheromone Grid
20
+ pheromone_grid = np.zeros((GRID_SIZE, GRID_SIZE, 3)) # 3 channels: food, danger, exploration
21
+
22
+ # Graph representation of the environment
23
+ env_graph = nx.grid_2d_graph(GRID_SIZE, GRID_SIZE)
24
+
25
+ # Remove edges for obstacles
26
+ for obstacle in OBSTACLES:
27
+ env_graph.remove_node(obstacle)
28
+
29
+ # Ant Class
30
+ class Ant:
31
+ def __init__(self, position, genome):
32
+ self.position = position
33
+ self.genome = genome
34
+ self.carrying_food = False
35
+ self.energy = 100
36
+ self.memory = deque(maxlen=20)
37
+ self.path_home = []
38
+ self.role = "explorer"
39
+ self.communication_range = 10
40
+ self.q_table = np.zeros((GRID_SIZE, GRID_SIZE, 4))
41
+
42
+ def perceive_environment(self, pheromone_grid, ants):
43
+ self.food_pheromone = pheromone_grid[self.position[0], self.position[1], 0]
44
+ self.danger_pheromone = pheromone_grid[self.position[0], self.position[1], 1]
45
+ self.exploration_pheromone = pheromone_grid[self.position[0], self.position[1], 2]
46
+
47
+ # Perceive nearby ants
48
+ self.nearby_ants = [ant for ant in ants if distance.euclidean(self.position, ant.position) <= self.communication_range]
49
+
50
+ def act(self, pheromone_grid):
51
+ possible_actions = self.get_possible_actions()
52
+
53
+ if random.random() < self.genome['exploration_rate']:
54
+ action = random.choice(possible_actions)
55
+ else:
56
+ action = np.argmax(self.q_table[self.position[0], self.position[1], possible_actions])
57
+
58
+ reward = self.calculate_reward()
59
+ self.update_q_table(action, reward)
60
+
61
+ return action
62
+
63
+ def calculate_reward(self):
64
+ if self.carrying_food:
65
+ return 10
66
+ elif self.position in FOOD_SOURCES:
67
+ return 20
68
+ elif self.position in OBSTACLES:
69
+ return -10
70
+ else:
71
+ return -1 + self.food_pheromone - self.danger_pheromone + 0.5 * self.exploration_pheromone
72
+
73
+ def update_q_table(self, action, reward):
74
+ self.q_table[self.position[0], self.position[1], action] = (
75
+ (1 - self.genome['learning_rate']) * self.q_table[self.position[0], self.position[1], action] +
76
+ self.genome['learning_rate'] * (reward + self.genome['discount_factor'] * np.max(self.q_table[self.position[0], self.position[1]]))
77
+ )
78
+
79
+ def get_possible_actions(self):
80
+ return list(env_graph.neighbors(self.position))
81
+
82
+ def update(self, pheromone_grid, ants):
83
+ self.perceive_environment(pheromone_grid, ants)
84
+ action = self.act(pheromone_grid)
85
+ self.position = action
86
+
87
+ self.energy -= 1
88
+ if self.energy <= 0:
89
+ return False # Ant dies
90
+
91
+ if self.carrying_food:
92
+ pheromone_grid[self.position[0], self.position[1], 0] += 5
93
+ if self.position == (0, 0): # Drop food at nest
94
+ self.carrying_food = False
95
+ self.energy = min(100, self.energy + 50)
96
+ return True # Food collected successfully
97
+
98
+ if self.position in FOOD_SOURCES and not self.carrying_food:
99
+ self.carrying_food = True
100
+ pheromone_grid[self.position[0], self.position[1], 0] += 10
101
+
102
+ if self.position in OBSTACLES:
103
+ pheromone_grid[self.position[0], self.position[1], 1] += 5
104
+
105
+ pheromone_grid[self.position[0], self.position[1], 2] += 1 # Exploration pheromone
106
+
107
+ self.memory.append(self.position)
108
+
109
+ # Update role based on situation
110
+ if self.carrying_food:
111
+ self.role = "carrier"
112
+ elif self.food_pheromone > 5:
113
+ self.role = "follower"
114
+ else:
115
+ self.role = "explorer"
116
+
117
+ # Path planning
118
+ if self.carrying_food and not self.path_home:
119
+ self.path_home = nx.shortest_path(env_graph, self.position, (0, 0))
120
+
121
+ return True # Ant survives
122
+
123
+ # Pheromone Diffusion using Convolution
124
+ def diffuse_pheromones(pheromone_grid):
125
+ kernel = np.array([[0.05, 0.1, 0.05],
126
+ [0.1, 0.4, 0.1],
127
+ [0.05, 0.1, 0.05]])
128
+ for i in range(3): # For each pheromone type
129
+ pheromone_grid[:,:,i] = np.convolve2d(pheromone_grid[:,:,i], kernel, mode='same', boundary='wrap')
130
+
131
+ # Genetic Algorithm
132
+ def crossover(parent1, parent2):
133
+ child = {}
134
+ for key in parent1.keys():
135
+ if random.random() < 0.5:
136
+ child[key] = parent1[key]
137
+ else:
138
+ child[key] = parent2[key]
139
+ return child
140
+
141
+ def mutate(genome):
142
+ for key in genome.keys():
143
+ if random.random() < MUTATION_RATE:
144
+ genome[key] += random.uniform(-0.1, 0.1)
145
+ genome[key] = max(0, min(1, genome[key]))
146
+ return genome
147
+
148
+ # Simulation Loop
149
+ def simulate(ants):
150
+ global pheromone_grid
151
+ food_collected = 0
152
+ for ant in ants:
153
+ if ant.update(pheromone_grid, ants):
154
+ if ant.position == (0, 0) and not ant.carrying_food:
155
+ food_collected += 1
156
+
157
+ pheromone_grid *= (1 - PHEROMONE_DECAY_RATE)
158
+ diffuse_pheromones(pheromone_grid)
159
+
160
+ # Genetic Algorithm
161
+ if len(ants) > MAX_ANTS:
162
+ ants.sort(key=lambda x: x.energy, reverse=True)
163
+ survivors = ants[:MAX_ANTS//2]
164
+ new_ants = []
165
+ while len(new_ants) < MAX_ANTS//2:
166
+ parent1, parent2 = random.sample(survivors, 2)
167
+ child_genome = crossover(parent1.genome, parent2.genome)
168
+ child_genome = mutate(child_genome)
169
+ new_ant = Ant((random.randint(0, GRID_SIZE-1), random.randint(0, GRID_SIZE-1)), child_genome)
170
+ new_ants.append(new_ant)
171
+ ants = survivors + new_ants
172
+
173
+ return ants, food_collected
174
+
175
+ # Clustering for strategic analysis
176
+ def analyze_ant_clusters(ants):
177
+ positions = np.array([ant.position for ant in ants])
178
+ kmeans = KMeans(n_clusters=3)
179
+ kmeans.fit(positions)
180
+ return kmeans.cluster_centers_
181
+
182
+ # Visualization Functions
183
+ def plot_environment(pheromone_grid, ants, cluster_centers):
184
+ fig, ax = plt.subplots(figsize=(10, 10))
185
+ ax.imshow(np.sum(pheromone_grid, axis=2), cmap='viridis', alpha=0.7)
186
+
187
+ for ant in ants:
188
+ color = 'blue' if ant.role == 'explorer' else 'red' if ant.role == 'carrier' else 'green'
189
+ ax.plot(ant.position[1], ant.position[0], 'o', color=color, markersize=4)
190
+
191
+ for food_x, food_y in FOOD_SOURCES:
192
+ ax.plot(food_y, food_x, 'go', markersize=10)
193
+
194
+ for obstacle_x, obstacle_y in OBSTACLES:
195
+ ax.plot(obstacle_y, obstacle_x, 'ro', markersize=10)
196
+
197
+ for center in cluster_centers:
198
+ ax.plot(center[1], center[0], 'mo', markersize=15, alpha=0.7)
199
+
200
+ ax.set_xlim([0, GRID_SIZE])
201
+ ax.set_ylim([GRID_SIZE, 0])
202
+ return fig
203
+
204
+ # Streamlit App
205
+ st.title("Advanced Ant Hivemind Simulation")
206
+
207
+ # Sidebar controls
208
+ st.sidebar.header("Simulation Parameters")
209
+ num_ants = st.sidebar.slider("Number of Ants", 10, MAX_ANTS, 50)
210
+ exploration_rate = st.sidebar.slider("Exploration Rate", 0.0, 1.0, 0.2)
211
+ learning_rate = st.sidebar.slider("Learning Rate", 0.0, 1.0, 0.1)
212
+ discount_factor = st.sidebar.slider("Discount Factor", 0.0, 1.0, 0.9)
213
+
214
+ # Initialize ants
215
+ ants = [Ant((random.randint(0, GRID_SIZE-1), random.randint(0, GRID_SIZE-1)),
216
+ {'exploration_rate': exploration_rate,
217
+ 'learning_rate': learning_rate,
218
+ 'discount_factor': discount_factor})
219
+ for _ in range(num_ants)]
220
+
221
+ # Simulation control
222
+ start_simulation = st.sidebar.button("Start Simulation")
223
+ stop_simulation = st.sidebar.button("Stop Simulation")
224
+ reset_simulation = st.sidebar.button("Reset Simulation")
225
+
226
+ # Main simulation loop
227
+ if start_simulation:
228
+ total_food_collected = 0
229
+ iterations = 0
230
+ cluster_centers = np.array([[0, 0], [0, 0], [0, 0]])
231
+
232
+ progress_bar = st.progress(0)
233
+ stats_placeholder = st.empty()
234
+ plot_placeholder = st.empty()
235
+
236
+ while not stop_simulation:
237
+ ants, food_collected = simulate(ants)
238
+ total_food_collected += food_collected
239
+ iterations += 1
240
+
241
+ if iterations % 10 == 0:
242
+ cluster_centers = analyze_ant_clusters(ants)
243
+
244
+ if iterations % 5 == 0:
245
+ progress_bar.progress(min(iterations / 1000, 1.0))
246
+ stats_placeholder.write(f"Iterations: {iterations}, Total Food Collected: {total_food_collected}")
247
+ fig = plot_environment(pheromone_grid, ants, cluster_centers)
248
+ plot_placeholder.pyplot(fig)
249
+ plt.close(fig)
250
+
251
+ if reset_simulation:
252
+ pheromone_grid = np.zeros((GRID_SIZE, GRID_SIZE, 3))
253
+ ants = [Ant((random.randint(0, GRID_SIZE-1), random.randint(0, GRID_SIZE-1)),
254
+ {'exploration_rate': exploration_rate,
255
+ 'learning_rate': learning_rate,
256
+ 'discount_factor': discount_factor})
257
+ for _ in range(num_ants)]
258
+
259
+ # Display final statistics
260
+ st.write("## Final Statistics")
261
+ st.write(f"Total Food Collected: {total_food_collected}")
262
+ st.write(f"Average Food per Iteration: {total_food_collected / iterations if iterations > 0 else 0}")
263
+
264
+ # Display heatmap of pheromone concentration
265
+ st.write("## Pheromone Concentration Heatmap")
266
+ fig, ax = plt.subplots(figsize=(10, 10))
267
+ heatmap = ax.imshow(np.sum(pheromone_grid, axis=2), cmap='hot', interpolation='nearest')
268
+ plt.colorbar(heatmap)
269
+ st.pyplot(fig)
270
+
271
+ # Display ant role distribution
272
+ roles = [ant.role for ant in ants]
273
+ role_counts = {role: roles.count(role) for role in set(roles)}
274
+ st.write("## Ant Role Distribution")
275
+ st.bar_chart(role_counts)
276
+
277
+ # Display network graph of ant communication
278
+ st.write("## Ant Communication Network")
279
+ G = nx.Graph()
280
+ for ant in ants:
281
+ G.add_node(ant.position)
282
+ for nearby_ant in ant.nearby_ants:
283
+ G.add_edge(ant.position, nearby_ant.position)
284
+
285
+ fig, ax = plt.subplots(figsize=(10, 10))
286
+ pos = nx.spring_layout(G)
287
+ nx.draw(G, pos, with_labels=False, node_size=30, node_color='skyblue', edge_color='gray', ax=ax)
288
+ st.pyplot(fig)