File size: 16,151 Bytes
81be535 d434cb0 7e52935 81be535 d434cb0 b0028e8 ee32a30 92386a2 f7ea6fc e905375 d434cb0 81be535 d434cb0 81be535 d434cb0 81be535 d434cb0 81be535 777127f 81be535 d434cb0 81be535 d434cb0 81be535 d434cb0 4118093 81be535 4118093 81be535 777127f d434cb0 777127f d434cb0 777127f 81be535 4118093 81be535 d434cb0 81be535 7e52935 81be535 d434cb0 81be535 d434cb0 81be535 d434cb0 81be535 d434cb0 81be535 d434cb0 81be535 d434cb0 81be535 d434cb0 81be535 7e52935 81be535 d434cb0 81be535 d434cb0 81be535 d434cb0 81be535 d434cb0 81be535 7e52935 81be535 7e52935 d434cb0 |
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 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
import streamlit as st
import numpy as np
import random
import matplotlib.pyplot as plt
from scipy.spatial import distance
from sklearn.cluster import KMeans
import networkx as nx
from collections import deque, Counter
from scipy.signal import convolve2d
# Constants
GRID_SIZE = 200
FOOD_SOURCES = [(20, 20), (80, 80), (150, 150), (40, 160), (180, 30)]
OBSTACLES = [(50, 50), (100, 100), (150, 50), (70, 130), (120, 80)]
PHEROMONE_DECAY_RATE = 0.02
PHEROMONE_DIFFUSION_RATE = 0.05
MAX_ANTS = 100
MUTATION_RATE = 0.01
# Pheromone Grid
pheromone_grid = np.zeros((GRID_SIZE, GRID_SIZE, 3)) # 3 channels: food, danger, exploration
# Graph representation of the environment
env_graph = nx.grid_2d_graph(GRID_SIZE, GRID_SIZE)
# Remove edges for obstacles
for obstacle in OBSTACLES:
env_graph.remove_node(obstacle)
class HiveMind:
def __init__(self):
self.collective_memory = {}
self.global_strategy = {}
self.task_allocation = {}
self.pheromone_importance = {'food': 0.5, 'danger': 0.3, 'exploration': 0.2}
def update_collective_memory(self, ant_memories):
for ant_memory in ant_memories:
for position, info in ant_memory:
if position not in self.collective_memory:
self.collective_memory[position] = info
else:
old_info = self.collective_memory[position]
new_info = tuple((old + new) / 2 for old, new in zip(old_info, info))
self.collective_memory[position] = new_info
def update_global_strategy(self, ant_performances):
best_ants = sorted(ant_performances, key=lambda x: x[1], reverse=True)[:5]
self.global_strategy = {
'exploration_rate': np.mean([ant.genome['exploration_rate'] for ant, _ in best_ants]),
'learning_rate': np.mean([ant.genome['learning_rate'] for ant, _ in best_ants]),
'discount_factor': np.mean([ant.genome['discount_factor'] for ant, _ in best_ants])
}
def allocate_tasks(self, ants):
ant_positions = [ant.position for ant in ants]
clusters = KMeans(n_clusters=min(5, len(ants))).fit(ant_positions)
for i, ant in enumerate(ants):
cluster = clusters.labels_[i]
if cluster not in self.task_allocation:
self.task_allocation[cluster] = []
self.task_allocation[cluster].append(ant)
def get_swarm_decision(self, decisions):
return Counter(decisions).most_common(1)[0][0]
class Ant:
def __init__(self, position, genome, hivemind):
self.position = position
self.genome = genome
self.hivemind = hivemind
self.carrying_food = False
self.energy = 100
self.memory = deque(maxlen=20)
self.path_home = []
self.role = "explorer"
self.communication_range = 10
self.q_table = {}
self.performance = 0
self.cluster = None
def perceive_environment(self, pheromone_grid, ants):
self.food_pheromone = pheromone_grid[self.position[0], self.position[1], 0]
self.danger_pheromone = pheromone_grid[self.position[0], self.position[1], 1]
self.exploration_pheromone = pheromone_grid[self.position[0], self.position[1], 2]
self.nearby_ants = [ant for ant in ants if distance.euclidean(self.position, ant.position) <= self.communication_range]
def act(self, pheromone_grid):
possible_actions = self.get_possible_actions()
if random.random() < self.genome['exploration_rate']:
action = random.choice(possible_actions)
else:
nearby_ants = [ant for ant in self.hivemind.task_allocation.get(self.cluster, [])
if distance.euclidean(self.position, ant.position) <= self.communication_range]
if nearby_ants:
swarm_decisions = [ant.decide(pheromone_grid) for ant in nearby_ants]
action = self.hivemind.get_swarm_decision(swarm_decisions)
else:
q_values = [self.get_q_value(action) for action in possible_actions]
action = possible_actions[np.argmax(q_values)]
reward = self.calculate_reward()
self.update_q_table(action, reward)
self.performance += reward
return action
def decide(self, pheromone_grid):
possible_actions = self.get_possible_actions()
q_values = [self.get_q_value(action) for action in possible_actions]
return possible_actions[np.argmax(q_values)]
def get_q_value(self, action):
return self.q_table.get((self.position, action), 0)
def update_q_table(self, action, reward):
current_q = self.get_q_value(action)
max_future_q = max([self.get_q_value(future_action) for future_action in self.get_possible_actions()])
new_q = (1 - self.genome['learning_rate']) * current_q + \
self.genome['learning_rate'] * (reward + self.genome['discount_factor'] * max_future_q)
self.q_table[(self.position, action)] = new_q
def calculate_reward(self):
base_reward = -1 # Cost of living
if self.carrying_food:
base_reward += 10
if self.position in FOOD_SOURCES:
base_reward += 20
if self.position in OBSTACLES:
base_reward -= 10
pheromone_reward = (
self.hivemind.pheromone_importance['food'] * self.food_pheromone +
self.hivemind.pheromone_importance['danger'] * -self.danger_pheromone +
self.hivemind.pheromone_importance['exploration'] * self.exploration_pheromone
)
return base_reward + pheromone_reward
def get_possible_actions(self):
x, y = self.position
possible_actions = []
for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]: # right, down, left, up
new_x, new_y = x + dx, y + dy
if 0 <= new_x < GRID_SIZE and 0 <= new_y < GRID_SIZE and (new_x, new_y) not in OBSTACLES:
possible_actions.append((new_x, new_y))
return possible_actions
def update(self, pheromone_grid, ants):
self.perceive_environment(pheromone_grid, ants)
action = self.act(pheromone_grid)
self.position = action
self.energy -= 1
if self.energy <= 0:
return False # Ant dies
if self.carrying_food:
pheromone_grid[self.position[0], self.position[1], 0] += 5
if self.position == (0, 0): # Drop food at nest
self.carrying_food = False
self.energy = min(100, self.energy + 50)
return True # Food collected successfully
if self.position in FOOD_SOURCES and not self.carrying_food:
self.carrying_food = True
pheromone_grid[self.position[0], self.position[1], 0] += 10
if self.position in OBSTACLES:
pheromone_grid[self.position[0], self.position[1], 1] += 5
pheromone_grid[self.position[0], self.position[1], 2] += 1 # Exploration pheromone
self.memory.append((self.position, (self.food_pheromone, self.danger_pheromone, self.exploration_pheromone)))
# Update role based on cluster task
self.role = self.hivemind.task_allocation.get(self.cluster, ["explorer"])[0]
# Path planning
if self.carrying_food and not self.path_home:
self.path_home = nx.shortest_path(env_graph, self.position, (0, 0))
return True # Ant survives
# Pheromone Diffusion using Convolution
def diffuse_pheromones(pheromone_grid):
kernel = np.array([[0.05, 0.1, 0.05],
[0.1, 0.4, 0.1],
[0.05, 0.1, 0.05]])
for i in range(3): # For each pheromone type
pheromone_grid[:,:,i] = convolve2d(pheromone_grid[:,:,i], kernel, mode='same', boundary='wrap')
# Genetic Algorithm
def crossover(parent1, parent2):
child = {}
for key in parent1.keys():
if random.random() < 0.5:
child[key] = parent1[key]
else:
child[key] = parent2[key]
return child
def mutate(genome):
for key in genome.keys():
if random.random() < MUTATION_RATE:
genome[key] += random.uniform(-0.1, 0.1)
genome[key] = max(0, min(1, genome[key]))
return genome
# Simulation Loop
def simulate(ants, hivemind):
global pheromone_grid
food_collected = 0
hivemind.allocate_tasks(ants)
for ant in ants:
if ant.update(pheromone_grid, ants):
if ant.position == (0, 0) and not ant.carrying_food:
food_collected += 1
pheromone_grid *= (1 - PHEROMONE_DECAY_RATE)
diffuse_pheromones(pheromone_grid)
hivemind.update_collective_memory([ant.memory for ant in ants])
hivemind.update_global_strategy([(ant, ant.performance) for ant in ants])
# Genetic Algorithm and Swarm Adaptation
if len(ants) > MAX_ANTS:
ants.sort(key=lambda x: x.performance, reverse=True)
survivors = ants[:MAX_ANTS//2]
new_ants = []
while len(new_ants) < MAX_ANTS//2:
parent1, parent2 = random.sample(survivors, 2)
child_genome = crossover(parent1.genome, parent2.genome)
child_genome = mutate(child_genome)
child_genome = {**child_genome, **hivemind.global_strategy} # Incorporate global strategy
new_ant = Ant((random.randint(0, GRID_SIZE-1), random.randint(0, GRID_SIZE-1)), child_genome, hivemind)
new_ants.append(new_ant)
ants = survivors + new_ants
return ants, food_collected
# Visualization Functions
def plot_environment(pheromone_grid, ants, cluster_centers):
fig, ax = plt.subplots(figsize=(10, 10))
ax.imshow(np.sum(pheromone_grid, axis=2), cmap='viridis', alpha=0.7)
for ant in ants:
color = 'blue' if ant.role == 'explorer' else 'red' if ant.role == 'carrier' else 'green'
ax.plot(ant.position[1], ant.position[0], 'o', color=color, markersize=4)
for food_x, food_y in FOOD_SOURCES:
ax.plot(food_y, food_x, 'go', markersize=10)
for obstacle_x, obstacle_y in OBSTACLES:
ax.plot(obstacle_y, obstacle_x, 'ro', markersize=10)
for center in cluster_centers:
ax.plot(center[1], center[0], 'mo', markersize=15, alpha=0.7)
ax.set_xlim([0, GRID_SIZE])
ax.set_ylim([GRID_SIZE, 0])
return fig
# Streamlit App
st.title("Advanced Ant Hivemind Simulation")
# Sidebar controls
st.sidebar.header("Simulation Parameters")
num_ants = st.sidebar.slider("Number of Ants", 10, MAX_ANTS, 50)
exploration_rate = st.sidebar.slider("Exploration Rate", 0.0, 1.0, 0.2)
learning_rate = st.sidebar.slider("Learning Rate", 0.0, 1.0, 0.1)
discount_factor = st.sidebar.slider("Discount Factor", 0.0, 1.0, 0.9)
# Initialize hivemind and ants
hivemind = HiveMind()
ants = [Ant((random.randint(0, GRID_SIZE-1), random.randint(0, GRID_SIZE-1)),
{'exploration_rate': exploration_rate,
'learning_rate': learning_rate,
'discount_factor': discount_factor},
hivemind)
for _ in range(num_ants)]
# Simulation control
start_simulation = st.sidebar.button("Start Simulation")
stop_simulation = st.sidebar.button("Stop Simulation")
reset_simulation = st.sidebar.button("Reset Simulation")
# Initialize variables
total_food_collected = 0
iterations = 0
# Main simulation loop
if start_simulation:
cluster_centers = np.array([[0, 0], [0, 0], [0, 0]])
progress_bar = st.progress(0)
stats_placeholder = st.empty()
plot_placeholder = st.empty()
while not stop_simulation:
ants, food_collected = simulate(ants, hivemind)
total_food_collected += food_collected
iterations += 1
if iterations % 10 == 0:
cluster_centers = hivemind.allocate_tasks(ants)
if iterations % 5 == 0:
progress_bar.progress(min(iterations / 1000, 1.0))
stats_placeholder.write(f"Iterations: {iterations}, Total Food Collected: {total_food_collected}")
fig = plot_environment(pheromone_grid, ants, cluster_centers)
plot_placeholder.pyplot(fig)
plt.close(fig)
if reset_simulation:
pheromone_grid = np.zeros((GRID_SIZE, GRID_SIZE, 3))
hivemind = HiveMind()
ants = [Ant((random.randint(0, GRID_SIZE-1), random.randint(0, GRID_SIZE-1)),
{'exploration_rate': exploration_rate,
'learning_rate': learning_rate,
'discount_factor': discount_factor},
hivemind)
for _ in range(num_ants)]
total_food_collected = 0
iterations = 0
# Display final statistics only if simulation has run
if iterations > 0:
st.write("## Final Statistics")
st.write(f"Total Food Collected: {total_food_collected}")
st.write(f"Average Food per Iteration: {total_food_collected / iterations}")
# Display heatmap of pheromone concentration
st.write("## Pheromone Concentration Heatmap")
fig, ax = plt.subplots(figsize=(10, 10))
heatmap = ax.imshow(np.sum(pheromone_grid, axis=2), cmap='hot', interpolation='nearest')
plt.colorbar(heatmap)
st.pyplot(fig)
# Display ant role distribution
roles = [ant.role for ant in ants]
role_counts = {role: roles.count(role) for role in set(roles)}
st.write("## Ant Role Distribution")
st.bar_chart(role_counts)
# Display network graph of ant communication
st.write("## Ant Communication Network")
G = nx.Graph()
for ant in ants:
G.add_node(ant.position)
for nearby_ant in ant.nearby_ants:
G.add_edge(ant.position, nearby_ant.position)
fig, ax = plt.subplots(figsize=(10, 10))
pos = nx.spring_layout(G)
nx.draw(G, pos, with_labels=False, node_size=30, node_color='skyblue', edge_color='gray', ax=ax)
st.pyplot(fig)
# Display hivemind collective memory heatmap
st.write("## Hivemind Collective Memory")
memory_grid = np.zeros((GRID_SIZE, GRID_SIZE))
for pos, info in hivemind.collective_memory.items():
memory_grid[pos[0], pos[1]] = np.mean(info)
fig, ax = plt.subplots(figsize=(10, 10))
heatmap = ax.imshow(memory_grid, cmap='viridis', interpolation='nearest')
plt.colorbar(heatmap)
st.pyplot(fig)
# Display global strategy evolution
st.write("## Global Strategy Evolution")
strategy_df = pd.DataFrame(hivemind.global_strategy, index=[0])
st.line_chart(strategy_df)
# Display performance distribution of ants
st.write("## Ant Performance Distribution")
performances = [ant.performance for ant in ants]
fig, ax = plt.subplots()
ax.hist(performances, bins=20)
ax.set_xlabel('Performance')
ax.set_ylabel('Number of Ants')
st.pyplot(fig)
# Display task allocation
st.write("## Task Allocation")
task_df = pd.DataFrame.from_dict(hivemind.task_allocation, orient='index')
task_df = task_df.applymap(lambda x: len(x) if x else 0)
st.bar_chart(task_df)
# Add some final notes about the simulation
st.write("""
## About this Simulation
This advanced ant hivemind simulation demonstrates several key concepts in swarm intelligence and collective behavior:
1. **Collective Decision Making**: Ants make decisions based on both individual and swarm intelligence.
2. **Adaptive Strategies**: The hivemind evolves its strategy based on the performance of the best ants.
3. **Distributed Task Allocation**: Ants are dynamically assigned to different tasks based on their location and the colony's needs.
4. **Emergent Behavior**: Complex colony-level behaviors emerge from simple individual ant rules.
5. **Information Sharing**: Ants share information through pheromones and direct communication.
6. **Collective Memory**: The hivemind maintains a collective memory of the environment.
This simulation showcases how simple agents, when working together with the right rules, can exhibit complex and intelligent behavior at the group level.
""") |