зеркало из
https://github.com/docxology/cognitive.git
synced 2025-10-29 12:16:04 +02:00
In Stream
Этот коммит содержится в:
родитель
621b613624
Коммит
ca645167d2
2
.obsidian/graph.json
поставляемый
2
.obsidian/graph.json
поставляемый
@ -17,6 +17,6 @@
|
||||
"repelStrength": 10,
|
||||
"linkStrength": 1,
|
||||
"linkDistance": 250,
|
||||
"scale": 2.2318821973563394,
|
||||
"scale": 0.10124266675309304,
|
||||
"close": false
|
||||
}
|
||||
73
.obsidian/workspace.json
поставляемый
73
.obsidian/workspace.json
поставляемый
@ -6,6 +6,7 @@
|
||||
{
|
||||
"id": "dea337cf76935a08",
|
||||
"type": "tabs",
|
||||
"dimension": 37.73006134969325,
|
||||
"children": [
|
||||
{
|
||||
"id": "0ba8a1b9b9dd949a",
|
||||
@ -26,19 +27,16 @@
|
||||
{
|
||||
"id": "99b33ec97f002ea4",
|
||||
"type": "tabs",
|
||||
"dimension": 62.26993865030674,
|
||||
"children": [
|
||||
{
|
||||
"id": "283b4112120e60a0",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "Things/BioFirm/BioFirm_README.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "BioFirm_README"
|
||||
"type": "graph",
|
||||
"state": {},
|
||||
"icon": "lucide-git-fork",
|
||||
"title": "Graph view"
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -114,7 +112,6 @@
|
||||
"state": {
|
||||
"type": "backlink",
|
||||
"state": {
|
||||
"file": "Things/Continuous_Generic/Continuous_Generic_README.md",
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical",
|
||||
@ -124,7 +121,7 @@
|
||||
"unlinkedCollapsed": true
|
||||
},
|
||||
"icon": "links-coming-in",
|
||||
"title": "Backlinks for Continuous_Generic_README"
|
||||
"title": "Backlinks"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -133,12 +130,11 @@
|
||||
"state": {
|
||||
"type": "outgoing-link",
|
||||
"state": {
|
||||
"file": "Things/Continuous_Generic/Continuous_Generic_README.md",
|
||||
"linksCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
},
|
||||
"icon": "links-going-out",
|
||||
"title": "Outgoing links from Continuous_Generic_README"
|
||||
"title": "Outgoing links"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -162,13 +158,12 @@
|
||||
"state": {
|
||||
"type": "outline",
|
||||
"state": {
|
||||
"file": "Things/Continuous_Generic/Continuous_Generic_README.md",
|
||||
"followCursor": false,
|
||||
"showSearch": false,
|
||||
"searchQuery": ""
|
||||
},
|
||||
"icon": "lucide-list",
|
||||
"title": "Outline of Continuous_Generic_README"
|
||||
"title": "Outline"
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -188,32 +183,34 @@
|
||||
"command-palette:Open command palette": false
|
||||
}
|
||||
},
|
||||
"active": "0ba8a1b9b9dd949a",
|
||||
"active": "283b4112120e60a0",
|
||||
"lastOpenFiles": [
|
||||
"ant_colony/agents/nestmate.py",
|
||||
"ant_colony/agents",
|
||||
"ant_colony",
|
||||
"Things/Ant_Colony/ant_colony/__pycache__/main.cpython-310.pyc",
|
||||
"Things/Ant_Colony/ant_colony/utils/__pycache__/data_collection.cpython-310.pyc",
|
||||
"Things/Ant_Colony/ant_colony/utils/__pycache__/__init__.cpython-310.pyc",
|
||||
"Things/Ant_Colony/ant_colony/utils/__pycache__",
|
||||
"Things/Ant_Colony/ant_colony/environment/__pycache__/world.cpython-310.pyc",
|
||||
"Things/Ant_Colony/ant_colony/utils/__init__.py",
|
||||
"Things/Ant_Colony/ant_colony/utils/data_collection.py",
|
||||
"Things/Ant_Colony/ant_colony/utils",
|
||||
"Things/Path_Network/venv/lib/python3.10/site-packages/pip-25.0.dist-info/top_level.txt",
|
||||
"Things/Path_Network/venv/lib/python3.10/site-packages/pip-25.0.dist-info/entry_points.txt",
|
||||
"Things/Path_Network/venv/lib/python3.10/site-packages/pip-25.0.dist-info/WHEEL",
|
||||
"Things/Path_Network/venv/lib/python3.10/site-packages/pip-25.0.dist-info/REQUESTED",
|
||||
"Things/Path_Network/venv/lib/python3.10/site-packages/pip-25.0.dist-info/RECORD",
|
||||
"Things/Path_Network/venv/lib/python3.10/site-packages/pip-25.0.dist-info/METADATA",
|
||||
"Things/Path_Network/venv/lib/python3.10/site-packages/pip-25.0.dist-info/LICENSE.txt",
|
||||
"Things/Path_Network/venv/lib/python3.10/site-packages/pip-25.0.dist-info/AUTHORS.txt",
|
||||
"Things/Path_Network/venv/lib/python3.10/site-packages/pip-25.0.dist-info/INSTALLER",
|
||||
"Things/Path_Network/venv/lib/python3.10/site-packages/pip-25.0.dist-info",
|
||||
"Things/Path_Network/venv/bin/Activate.ps1",
|
||||
"Things/Path_Network/output/20250207_134114/agent_height_variations.png",
|
||||
"Things/Path_Network/output/20250207_134114/water_level_distribution.png",
|
||||
"Things/Path_Network/output/20250207_134114/final_state.png",
|
||||
"Things/Path_Network/output/20250207_134114/initial_state.png",
|
||||
"Things/Path_Network/output/20250207_134014/agent_height_variations.png",
|
||||
"Things/Path_Network/output/20250207_134014/water_level_distribution.png",
|
||||
"Things/Path_Network/output/20250207_134014/final_state.png",
|
||||
"Things/Path_Network/output/20250207_134014/initial_state.png",
|
||||
"Things/Path_Network/README.md",
|
||||
"Things/Path_Network/Path_Network_README.md",
|
||||
"Things/BioFirm/BioFirm_README.md",
|
||||
"Things/Continuous_Generic/Continuous_Generic_README.md",
|
||||
"Output/tests/visualization/detailed_summary.png",
|
||||
"Output/tests/visualization/summary.png",
|
||||
"Output/tests/visualization/action_phase_space.png",
|
||||
"Output/tests/visualization/action_evolution.png",
|
||||
"Output/tests/visualization/free_energy_landscape.png",
|
||||
"Output/tests/visualization/belief_animation.gif",
|
||||
"Things/BioFirm/BioFirm_README.md",
|
||||
"knowledge_base/cognitive/continuous_time_active_inference.md",
|
||||
"Output/tests/visualization/generalized_coordinates.png",
|
||||
"Output/tests/visualization/energy_ratio.png",
|
||||
"Output/tests/visualization/energy_components.png",
|
||||
"Output/tests/visualization/phase_space_energy.png",
|
||||
"Things/Continuous_Generic/Continuous_Generic_README.md",
|
||||
"Things/Generic_POMDP/Generic_POMDP_README.md",
|
||||
"src/models/active_inference/docs/biofirm_schema.md",
|
||||
"knowledge_base/agents/GenericPOMDP/matrices/A_matrix.md",
|
||||
@ -234,8 +231,6 @@
|
||||
"knowledge_base/mathematics/expected_free_energy.md",
|
||||
"knowledge_base/mathematics/active_inference_pomdp.md",
|
||||
"knowledge_base/mathematics/compute_efe.md",
|
||||
"knowledge_base/mathematics/belief_updating.md",
|
||||
"knowledge_base/cognitive/perceptual_inference.md",
|
||||
"knowledge_base/cognitive/metacognition.md"
|
||||
"knowledge_base/mathematics/belief_updating.md"
|
||||
]
|
||||
}
|
||||
@ -34,6 +34,9 @@ class Nestmate:
|
||||
"""Initialize the agent."""
|
||||
self.config = config
|
||||
|
||||
# Initialize beliefs first
|
||||
self.beliefs = Belief()
|
||||
|
||||
# Physical state
|
||||
self.position = None
|
||||
self.orientation = 0.0
|
||||
@ -47,6 +50,13 @@ class Nestmate:
|
||||
self.current_task = TaskType.EXPLORATION
|
||||
self.task_time = 0.0
|
||||
|
||||
# Memory state
|
||||
self.memory = {
|
||||
'temporal': [], # List of temporal memories (past states/actions)
|
||||
'spatial': {}, # Dict of spatial memories (locations)
|
||||
'social': {} # Dict of social memories (interactions)
|
||||
}
|
||||
|
||||
# Sensory state
|
||||
self.observations = {
|
||||
'pheromones': {},
|
||||
@ -56,7 +66,6 @@ class Nestmate:
|
||||
}
|
||||
|
||||
# Internal model
|
||||
self.beliefs = Belief()
|
||||
self.preferences = {task: 1.0 for task in TaskType}
|
||||
|
||||
# Learning parameters
|
||||
@ -77,6 +86,31 @@ class Nestmate:
|
||||
# Select and execute actions
|
||||
self._select_actions()
|
||||
|
||||
# Update memory with current state
|
||||
self._update_memory()
|
||||
|
||||
def _update_memory(self) -> None:
|
||||
"""Update agent's memory with current state."""
|
||||
# Add current state to temporal memory
|
||||
current_state = {
|
||||
'state': self.current_task,
|
||||
'position': self.position,
|
||||
'energy': self.energy,
|
||||
'time': self.task_time
|
||||
}
|
||||
self.memory['temporal'].append(current_state)
|
||||
|
||||
# Limit memory size to prevent unbounded growth
|
||||
max_memory = 100
|
||||
if len(self.memory['temporal']) > max_memory:
|
||||
self.memory['temporal'] = self.memory['temporal'][-max_memory:]
|
||||
|
||||
# Update spatial memory if we found something interesting
|
||||
if self.beliefs.food_location:
|
||||
self.memory['spatial']['food'] = self.beliefs.food_location
|
||||
|
||||
# Could add more memory updates here (social interactions, etc.)
|
||||
|
||||
def _update_physical_state(self, dt: float) -> None:
|
||||
"""Update physical state of the agent."""
|
||||
# Update position based on velocity and orientation
|
||||
|
||||
@ -10,8 +10,8 @@ import numpy as np
|
||||
from typing import Dict, List, Tuple, Optional
|
||||
from dataclasses import dataclass
|
||||
import networkx as nx
|
||||
from agents.nestmate import Nestmate, TaskType
|
||||
from environment.world import World, Position, Resource
|
||||
from ant_colony.agents.nestmate import Nestmate, TaskType
|
||||
from ant_colony.environment.world import World, Position, Resource
|
||||
|
||||
@dataclass
|
||||
class ColonyStats:
|
||||
@ -46,6 +46,10 @@ class Colony:
|
||||
'building_materials': 0.0
|
||||
}
|
||||
|
||||
# Initialize task needs and allocation
|
||||
self.task_needs = {task: 0.0 for task in TaskType}
|
||||
self.task_allocation = {task: set() for task in TaskType}
|
||||
|
||||
# Initialize agents
|
||||
self.agents: List[Nestmate] = []
|
||||
self._initialize_agents()
|
||||
@ -91,6 +95,8 @@ class Colony:
|
||||
|
||||
agent = Nestmate(agent_config)
|
||||
agent.position = pos
|
||||
|
||||
# Initialize beliefs after creating agent
|
||||
agent.beliefs.nest_location = self.nest_position
|
||||
|
||||
self.agents.append(agent)
|
||||
@ -181,11 +187,19 @@ class Colony:
|
||||
'energy_efficiency': self._compute_energy_efficiency()
|
||||
}
|
||||
|
||||
# Compute coordination metrics
|
||||
coordination = {
|
||||
'task_specialization': self._calculate_specialization(),
|
||||
'social_network_density': nx.density(self.interaction_network),
|
||||
'task_balance': self._compute_task_balance(task_dist)
|
||||
}
|
||||
|
||||
return ColonyStats(
|
||||
population=len(self.agents),
|
||||
task_distribution=task_dist,
|
||||
resource_levels=self.resources.copy(),
|
||||
efficiency_metrics=efficiency
|
||||
efficiency_metrics=efficiency,
|
||||
coordination_metrics=coordination
|
||||
)
|
||||
|
||||
def _compute_food_efficiency(self) -> float:
|
||||
@ -459,4 +473,17 @@ class Colony:
|
||||
break
|
||||
if agent not in current_defenders:
|
||||
agent.current_task = TaskType.DEFENSE
|
||||
current_defenders.add(agent)
|
||||
current_defenders.add(agent)
|
||||
|
||||
def _compute_task_balance(self, task_dist: Dict[TaskType, int]) -> float:
|
||||
"""Compute how well-balanced the task distribution is."""
|
||||
if not self.agents:
|
||||
return 0.0
|
||||
|
||||
# Ideal distribution would be uniform across tasks
|
||||
ideal_per_task = len(self.agents) / len(TaskType)
|
||||
deviations = [abs(count - ideal_per_task) for count in task_dist.values()]
|
||||
max_deviation = len(self.agents) # Worst case: all agents on one task
|
||||
|
||||
# Return normalized score (1.0 = perfect balance, 0.0 = worst balance)
|
||||
return 1.0 - sum(deviations) / (2 * max_deviation)
|
||||
@ -78,6 +78,7 @@ class World:
|
||||
for _ in range(self.config['food_sources']['count']):
|
||||
pos = self._random_position()
|
||||
amount = np.random.uniform(*self.config['food_sources']['value_range'])
|
||||
size = np.random.uniform(*self.config['food_sources']['size_range'])
|
||||
|
||||
resource = Resource(
|
||||
position=pos,
|
||||
@ -137,6 +138,14 @@ class World:
|
||||
resource.max_amount
|
||||
)
|
||||
|
||||
def get_state(self) -> dict:
|
||||
"""Get the current state of the world."""
|
||||
return {
|
||||
'pheromones': self.pheromones,
|
||||
'resources': [resource for resources in self.resources.values() for resource in resources],
|
||||
'terrain': self.terrain
|
||||
}
|
||||
|
||||
def get_local_state(self, position: Position, radius: float) -> dict:
|
||||
"""Get the local state around a position within given radius."""
|
||||
x, y = position.x, position.y
|
||||
|
||||
@ -6,6 +6,8 @@ import yaml
|
||||
import numpy as np
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
import matplotlib
|
||||
matplotlib.use('Agg') # Use non-GUI backend
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from ant_colony.environment import World
|
||||
@ -27,8 +29,18 @@ class Simulation:
|
||||
# Initialize components
|
||||
self.environment = World(self.config['environment'])
|
||||
self.colony = Colony(self.config['colony'], self.environment)
|
||||
self.visualizer = ColonyVisualizer(self.config['visualization'])
|
||||
self.data_collector = DataCollector(self.config['data_collection'])
|
||||
|
||||
# Initialize visualization if enabled
|
||||
if self.config.get('visualization', {}).get('enabled', True):
|
||||
self.visualizer = ColonyVisualizer(self.config)
|
||||
else:
|
||||
self.visualizer = None
|
||||
|
||||
# Initialize data collection if enabled
|
||||
if self.config.get('data_collection', {}).get('enabled', True):
|
||||
self.data_collector = DataCollector(self.config['data_collection'])
|
||||
else:
|
||||
self.data_collector = None
|
||||
|
||||
# Simulation state
|
||||
self.current_step = 0
|
||||
@ -55,7 +67,7 @@ class Simulation:
|
||||
self.colony.update(dt)
|
||||
|
||||
# Update visualization if enabled
|
||||
if self.config['visualization']['enabled']:
|
||||
if self.visualizer is not None:
|
||||
world_state = {
|
||||
'agents': self.colony.agents,
|
||||
'resources': self.environment.resources,
|
||||
@ -64,8 +76,8 @@ class Simulation:
|
||||
}
|
||||
self.visualizer.update(world_state)
|
||||
|
||||
# Collect data
|
||||
if self.config['data_collection']['enabled']:
|
||||
# Collect data if enabled
|
||||
if self.data_collector is not None:
|
||||
self.data_collector.collect(self.current_time, world_state)
|
||||
|
||||
# Save data periodically
|
||||
@ -89,7 +101,7 @@ class Simulation:
|
||||
print(f"Step {self.current_step}/{max_steps}")
|
||||
|
||||
# Update visualization
|
||||
if not headless and self.config['visualization']['enabled']:
|
||||
if not headless and self.visualizer is not None:
|
||||
plt.pause(0.001) # Allow GUI to update
|
||||
|
||||
except KeyboardInterrupt:
|
||||
@ -97,11 +109,11 @@ class Simulation:
|
||||
|
||||
finally:
|
||||
# Save final data
|
||||
if self.config['data_collection']['enabled']:
|
||||
if self.data_collector is not None:
|
||||
self.data_collector.save_data()
|
||||
|
||||
# Show final visualization
|
||||
if not headless and self.config['visualization']['enabled']:
|
||||
if not headless and self.visualizer is not None:
|
||||
plt.show()
|
||||
|
||||
def pause(self) -> None:
|
||||
@ -123,5 +135,5 @@ class Simulation:
|
||||
self.colony = Colony(self.config['colony'], self.environment)
|
||||
|
||||
# Clear data
|
||||
if self.config['data_collection']['enabled']:
|
||||
if self.data_collector is not None:
|
||||
self.data_collector = DataCollector(self.config['data_collection'])
|
||||
@ -134,13 +134,13 @@ class DataCollector:
|
||||
'run_id': self.run_id,
|
||||
'duration': len(self.data['time']),
|
||||
'colony_stats': {
|
||||
'mean_population': float(colony_stats['population'].mean()),
|
||||
'peak_population': int(colony_stats['population'].max()),
|
||||
'total_food_collected': float(colony_stats['total_food_collected'].sum())
|
||||
'mean_population': float(np.mean([stats['population'] for stats in self.data['colony_stats']])),
|
||||
'peak_population': int(max(stats['population'] for stats in self.data['colony_stats'])),
|
||||
'total_food_collected': float(sum(stats['total_food_collected'] for stats in self.data['colony_stats']))
|
||||
},
|
||||
'task_distribution': {
|
||||
task: float(task_dist[task].mean())
|
||||
for task in task_dist.columns
|
||||
task: float(np.mean([dist.get(task, 0) for dist in self.data['task_distribution']]))
|
||||
for task in set().union(*self.data['task_distribution'])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,9 +14,33 @@ class SimulationRenderer:
|
||||
def __init__(self, config: dict):
|
||||
"""Initialize the renderer with configuration settings."""
|
||||
self.config = config
|
||||
self.viz_config = config['visualization']
|
||||
self.viz_config = config.get('visualization', {})
|
||||
self.env_size = config['environment']['size']
|
||||
|
||||
# Default colors if not specified in config
|
||||
self.colors = {
|
||||
'nest': 'brown',
|
||||
'food': 'green',
|
||||
'obstacles': 'gray',
|
||||
'agents': {
|
||||
'foraging': 'red',
|
||||
'maintenance': 'blue',
|
||||
'nursing': 'pink',
|
||||
'defense': 'darkred',
|
||||
'exploration': 'orange'
|
||||
},
|
||||
'pheromones': {
|
||||
'food': 'green',
|
||||
'home': 'red',
|
||||
'alarm': 'orange',
|
||||
'trail': 'blue'
|
||||
}
|
||||
}
|
||||
|
||||
# Override defaults with config values if present
|
||||
if 'colors' in self.viz_config:
|
||||
self.colors.update(self.viz_config['colors'])
|
||||
|
||||
# Setup the figure and axis
|
||||
self.fig, self.ax = plt.subplots(figsize=(10, 10))
|
||||
self.ax.set_xlim(0, self.env_size[0])
|
||||
@ -31,7 +55,7 @@ class SimulationRenderer:
|
||||
|
||||
# Setup the nest
|
||||
nest_loc = config['environment']['nest_location']
|
||||
nest = Circle(nest_loc, 5, color=self.viz_config['colors']['nest'])
|
||||
nest = Circle(nest_loc, 5, color=self.colors['nest'])
|
||||
self.ax.add_patch(nest)
|
||||
|
||||
def update(self, world_state: dict) -> None:
|
||||
@ -46,7 +70,7 @@ class SimulationRenderer:
|
||||
# Update pheromones
|
||||
for p_type, grid in world_state['pheromones'].items():
|
||||
if p_type not in self.pheromone_plots:
|
||||
color = self.viz_config['colors']['pheromones'][p_type]
|
||||
color = self.colors['pheromones'][p_type]
|
||||
self.pheromone_plots[p_type] = self.ax.imshow(
|
||||
grid,
|
||||
extent=[0, self.env_size[0], 0, self.env_size[1]],
|
||||
@ -60,7 +84,7 @@ class SimulationRenderer:
|
||||
|
||||
# Draw agents
|
||||
for agent in world_state['agents']:
|
||||
color = self.viz_config['colors']['agents'][agent.current_task.value]
|
||||
color = self.colors['agents'][agent.current_task.value]
|
||||
agent_patch = self._create_agent_patch(agent, color)
|
||||
self.ax.add_patch(agent_patch)
|
||||
self.agent_patches.append(agent_patch)
|
||||
@ -69,8 +93,8 @@ class SimulationRenderer:
|
||||
for food in world_state['resources']:
|
||||
food_patch = Circle(
|
||||
(food.position.x, food.position.y),
|
||||
food.size,
|
||||
color=self.viz_config['colors']['food']
|
||||
food.size if hasattr(food, 'size') else 1.0,
|
||||
color=self.colors['food']
|
||||
)
|
||||
self.ax.add_patch(food_patch)
|
||||
self.food_patches.append(food_patch)
|
||||
@ -79,8 +103,8 @@ class SimulationRenderer:
|
||||
for obstacle in world_state['obstacles']:
|
||||
obstacle_patch = Circle(
|
||||
(obstacle.position.x, obstacle.position.y),
|
||||
obstacle.size,
|
||||
color=self.viz_config['colors']['obstacles']
|
||||
obstacle.size if hasattr(obstacle, 'size') else 1.0,
|
||||
color=self.colors['obstacles']
|
||||
)
|
||||
self.ax.add_patch(obstacle_patch)
|
||||
self.obstacle_patches.append(obstacle_patch)
|
||||
|
||||
Двоичные данные
Things/Ant_Colony/output/simulation_20250207_132721.h5
Обычный файл
Двоичные данные
Things/Ant_Colony/output/simulation_20250207_132721.h5
Обычный файл
Двоичный файл не отображается.
Двоичные данные
Things/Ant_Colony/output/simulation_20250207_132802.h5
Обычный файл
Двоичные данные
Things/Ant_Colony/output/simulation_20250207_132802.h5
Обычный файл
Двоичный файл не отображается.
21
Things/Path_Network/LICENSE
Обычный файл
21
Things/Path_Network/LICENSE
Обычный файл
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Path Network Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
137
Things/Path_Network/Path_Network_README.md
Обычный файл
137
Things/Path_Network/Path_Network_README.md
Обычный файл
@ -0,0 +1,137 @@
|
||||
# Path Network: Active Inference Agents in a Dynamic Topology
|
||||
|
||||
## Project Overview
|
||||
We want a simulation where an arbitrary topology (randomly initially generated) of nodes, reflecting their communicative effective causal mutual influence, is generated and simulated. Each node is a Continuous time, Active Inference agent.
|
||||
|
||||
Different nodes can have different relations with the same underlying inference methods, for example different time delta of integration, different levels of Taylor Series expansion for generalized coordinate anticipatory inference.
|
||||
|
||||
At a big picture level, it is like there are nested Sin waves that are the "level of water in the world". All of the nodes are like ships or towers, that are doing this real-time inference on how much to ascend or descend in order to stay within a tolerable limited range of the overall sea level (which floats all boats).
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
path_network/
|
||||
├── core/
|
||||
│ ├── __init__.py
|
||||
│ ├── agent.py # Active Inference agent implementation
|
||||
│ ├── network.py # Network topology and communication
|
||||
│ ├── dynamics.py # Sin wave and environmental dynamics
|
||||
│ └── inference.py # Generalized coordinates and inference methods
|
||||
├── utils/
|
||||
│ ├── __init__.py
|
||||
│ ├── visualization.py # Network and dynamics visualization
|
||||
│ └── math_utils.py # Mathematical utilities
|
||||
├── config/
|
||||
│ ├── __init__.py
|
||||
│ └── settings.py # Simulation parameters
|
||||
└── simulation/
|
||||
├── __init__.py
|
||||
└── runner.py # Main simulation orchestration
|
||||
```
|
||||
|
||||
## Core Components
|
||||
|
||||
### 1. Active Inference Agent (agent.py)
|
||||
- Continuous-time state estimation
|
||||
- Free energy minimization
|
||||
- Generalized coordinates for anticipatory inference
|
||||
- Adaptive response mechanisms
|
||||
- Individual parameter settings for:
|
||||
- Integration time delta
|
||||
- Taylor series expansion levels
|
||||
- Tolerance ranges
|
||||
- Response dynamics
|
||||
|
||||
### 2. Network Topology (network.py)
|
||||
- Random topology generation
|
||||
- Inter-agent communication protocols
|
||||
- Influence weight matrices
|
||||
- Dynamic topology updates
|
||||
- Neighborhood relationships
|
||||
|
||||
### 3. Environmental Dynamics (dynamics.py)
|
||||
- Nested sinusoidal wave generation
|
||||
- Global state management
|
||||
- Environmental perturbations
|
||||
- Time evolution systems
|
||||
|
||||
### 4. Inference Methods (inference.py)
|
||||
- Generalized coordinates implementation
|
||||
- Free energy computation
|
||||
- Variational inference algorithms
|
||||
- Prediction error minimization
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
1. **Phase 1: Core Infrastructure**
|
||||
- Set up project structure
|
||||
- Implement basic mathematical utilities
|
||||
- Create configuration management
|
||||
- Develop testing framework
|
||||
|
||||
2. **Phase 2: Agent Implementation**
|
||||
- Implement core Active Inference mathematics
|
||||
- Create base agent class
|
||||
- Add generalized coordinate systems
|
||||
- Implement free energy minimization
|
||||
|
||||
3. **Phase 3: Network Development**
|
||||
- Create topology generation
|
||||
- Implement inter-agent communication
|
||||
- Develop influence propagation
|
||||
- Add dynamic network updates
|
||||
|
||||
4. **Phase 4: Environmental Systems**
|
||||
- Implement sinusoidal wave systems
|
||||
- Create global state management
|
||||
- Add perturbation mechanisms
|
||||
- Develop state tracking
|
||||
|
||||
5. **Phase 5: Visualization and Analysis**
|
||||
- Create network visualization
|
||||
- Implement state space plotting
|
||||
- Add analysis tools
|
||||
- Create performance metrics
|
||||
|
||||
6. **Phase 6: Integration and Testing**
|
||||
- Integrate all components
|
||||
- Comprehensive testing
|
||||
- Performance optimization
|
||||
- Documentation
|
||||
|
||||
## Key Features
|
||||
|
||||
1. **Dynamic Topology**
|
||||
- Random initial generation
|
||||
- Adaptive connectivity
|
||||
- Influence-based relationships
|
||||
- Real-time updates
|
||||
|
||||
2. **Active Inference Implementation**
|
||||
- Continuous time processing
|
||||
- Generalized coordinate inference
|
||||
- Variable integration time steps
|
||||
- Adaptive response mechanisms
|
||||
|
||||
3. **Environmental Simulation**
|
||||
- Multi-frequency sin waves
|
||||
- Global state management
|
||||
- Perturbation systems
|
||||
- State tracking
|
||||
|
||||
4. **Visualization and Analysis**
|
||||
- Network topology visualization
|
||||
- State space plotting
|
||||
- Performance metrics
|
||||
- Real-time monitoring
|
||||
|
||||
## Dependencies
|
||||
- NumPy: Numerical computations
|
||||
- NetworkX: Graph topology management
|
||||
- SciPy: Scientific computations
|
||||
- Matplotlib: Visualization
|
||||
- PyTorch: Deep learning and optimization
|
||||
- Pandas: Data management
|
||||
|
||||
## Getting Started
|
||||
[Implementation to follow]
|
||||
114
Things/Path_Network/README.md
Обычный файл
114
Things/Path_Network/README.md
Обычный файл
@ -0,0 +1,114 @@
|
||||
# Path Network Simulation
|
||||
|
||||
A simulation of Active Inference agents in a dynamic network topology, where agents adapt their heights in response to changing water levels and network influences.
|
||||
|
||||
## Features
|
||||
|
||||
- **Active Inference Agents**: Each node implements continuous-time active inference
|
||||
- **Dynamic Network Topology**: Network connections evolve based on agent performance
|
||||
- **Environmental Dynamics**: Complex water level patterns through nested sinusoidal waves
|
||||
- **Real-time Visualization**: Interactive visualization of network state and agent behavior
|
||||
- **Comprehensive Analysis**: Detailed metrics and visualizations of simulation results
|
||||
|
||||
## Requirements
|
||||
|
||||
### System Dependencies
|
||||
|
||||
- Python 3.8+
|
||||
- Qt5 or Tk (for visualization)
|
||||
- Required system libraries (installed automatically by setup script)
|
||||
|
||||
### Python Dependencies
|
||||
|
||||
All Python dependencies are listed in `requirements.txt` and will be installed automatically by the setup script.
|
||||
|
||||
## Quick Start
|
||||
|
||||
The easiest way to run the simulation is using the provided setup script:
|
||||
|
||||
```bash
|
||||
./run_simulation.sh
|
||||
```
|
||||
|
||||
This script will:
|
||||
1. Create a Python virtual environment
|
||||
2. Install required system dependencies
|
||||
3. Install Python dependencies
|
||||
4. Run the simulation
|
||||
5. Save results to the `output` directory
|
||||
|
||||
## Manual Setup
|
||||
|
||||
If you prefer to set up manually:
|
||||
|
||||
1. Create and activate a virtual environment:
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
3. Run the simulation:
|
||||
```bash
|
||||
python example.py
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
The simulation creates a timestamped output directory containing:
|
||||
|
||||
- `simulation.log`: Detailed log of the simulation run
|
||||
- `initial_state.png`: Network state visualization after initial period
|
||||
- `final_state.png`: Network state visualization after perturbation
|
||||
- `water_level_distribution.png`: Distribution of water levels
|
||||
- `agent_height_variations.png`: Time series of agent heights
|
||||
- `water_levels.npy`: Raw water level data
|
||||
- `agent_heights.npy`: Raw agent height data
|
||||
|
||||
## Visualization
|
||||
|
||||
The simulation provides real-time visualization of:
|
||||
- Network topology with node colors representing heights
|
||||
- Current agent heights compared to water level
|
||||
- Historical evolution of heights and water levels
|
||||
|
||||
## Configuration
|
||||
|
||||
Key parameters can be adjusted in `example.py`:
|
||||
|
||||
- Network parameters (number of nodes, connectivity, etc.)
|
||||
- Wave components (frequencies, amplitudes, phases)
|
||||
- Simulation duration and visualization intervals
|
||||
- Perturbation parameters
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Visualization Issues
|
||||
|
||||
If you encounter visualization problems:
|
||||
|
||||
1. The script will automatically try different backends (Qt5 → Tk → Agg)
|
||||
2. Check if Qt5 or Tk is properly installed
|
||||
3. Look for error messages in the simulation log
|
||||
|
||||
### System Dependencies
|
||||
|
||||
If system dependencies fail to install:
|
||||
|
||||
1. Check your system's package manager
|
||||
2. Install required packages manually:
|
||||
- For Ubuntu/Debian: `sudo apt-get install python3-tk python3-qt5 libxcb-cursor0`
|
||||
- For Fedora: `sudo dnf install python3-tkinter python3-qt5 xcb-util-cursor`
|
||||
- For Arch: `sudo pacman -S python-tk qt5-base xcb-util-cursor`
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit issues and pull requests.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the LICENSE file for details.
|
||||
91
Things/Path_Network/config.yaml
Обычный файл
91
Things/Path_Network/config.yaml
Обычный файл
@ -0,0 +1,91 @@
|
||||
# Path Network Simulation Configuration
|
||||
|
||||
# Network Configuration
|
||||
network:
|
||||
num_nodes: 15
|
||||
initial_connectivity: 0.3
|
||||
min_weight: 0.1
|
||||
max_weight: 1.0
|
||||
dynamic_topology: true
|
||||
topology_update_interval: 50
|
||||
|
||||
# Environmental Dynamics
|
||||
dynamics:
|
||||
wave_components:
|
||||
- name: "slow_wave"
|
||||
amplitude: 1.0
|
||||
frequency: 0.1
|
||||
phase: 0.0
|
||||
- name: "medium_wave"
|
||||
amplitude: 0.5
|
||||
frequency: 0.5
|
||||
phase: 0.0
|
||||
- name: "fast_wave"
|
||||
amplitude: 0.2
|
||||
frequency: 2.0
|
||||
phase: 0.0
|
||||
noise_std: 0.05
|
||||
time_scale: 1.0
|
||||
|
||||
# Simulation Parameters
|
||||
simulation:
|
||||
total_steps: 1000
|
||||
initial_period: 200
|
||||
save_interval: 10
|
||||
visualization_interval: 20
|
||||
|
||||
# Agent Parameters
|
||||
agent:
|
||||
dt: 0.01
|
||||
taylor_order: 2
|
||||
tolerance: 0.1
|
||||
learning_rate: 0.01
|
||||
|
||||
# Perturbation Settings
|
||||
perturbation:
|
||||
magnitude: 2.0
|
||||
duration: 100
|
||||
decay: 1.0
|
||||
|
||||
# Visualization Settings
|
||||
visualization:
|
||||
# General settings
|
||||
style: "seaborn-whitegrid"
|
||||
font_scale: 1.2
|
||||
dpi: 300
|
||||
fps: 30 # For animations
|
||||
|
||||
# Color schemes
|
||||
network_cmap: "coolwarm"
|
||||
agent_cmap: "viridis"
|
||||
|
||||
# Plot sizes
|
||||
network_figsize: [15, 10]
|
||||
timeseries_figsize: [12, 6]
|
||||
animation_figsize: [10, 10]
|
||||
|
||||
# Output formats
|
||||
save_formats: ["png", "pdf"]
|
||||
create_animations: true
|
||||
|
||||
# Animation settings
|
||||
animation_duration: 10 # seconds
|
||||
|
||||
# Plot types to generate
|
||||
plots:
|
||||
network_topology: true
|
||||
height_distribution: true
|
||||
height_variations: true
|
||||
phase_space: true
|
||||
prediction_errors: true
|
||||
correlation_matrix: true
|
||||
free_energy: true
|
||||
spectral_analysis: true
|
||||
|
||||
# 3D visualization
|
||||
enable_3d: true
|
||||
3d_rotation_speed: 2 # degrees per frame
|
||||
|
||||
# Interactive features
|
||||
enable_interactive: true
|
||||
update_interval: 100 # milliseconds
|
||||
228
Things/Path_Network/example.py
Обычный файл
228
Things/Path_Network/example.py
Обычный файл
@ -0,0 +1,228 @@
|
||||
"""
|
||||
Example script demonstrating the Path Network simulation.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import numpy as np
|
||||
import matplotlib
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
import yaml
|
||||
from path_network.core.network import NetworkConfig
|
||||
from path_network.core.dynamics import DynamicsConfig, WaveComponent
|
||||
from path_network.simulation.runner import SimulationRunner, SimulationConfig
|
||||
from path_network.utils.visualization import NetworkVisualizer
|
||||
from path_network.utils.advanced_visualization import AdvancedVisualizer
|
||||
|
||||
def load_config(config_path: str = "config.yaml") -> dict:
|
||||
"""Load configuration from YAML file."""
|
||||
with open(config_path, 'r') as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
def setup_logging(output_dir: Path) -> logging.Logger:
|
||||
"""Set up logging configuration."""
|
||||
logger = logging.getLogger('path_network')
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
# Create handlers
|
||||
console_handler = logging.StreamHandler()
|
||||
file_handler = logging.FileHandler(output_dir / 'simulation.log')
|
||||
|
||||
# Create formatters and add it to handlers
|
||||
log_format = logging.Formatter(
|
||||
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
console_handler.setFormatter(log_format)
|
||||
file_handler.setFormatter(log_format)
|
||||
|
||||
# Add handlers to the logger
|
||||
logger.addHandler(console_handler)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
return logger
|
||||
|
||||
def setup_matplotlib_backend(logger: logging.Logger) -> bool:
|
||||
"""
|
||||
Set up appropriate matplotlib backend.
|
||||
|
||||
Returns:
|
||||
bool: True if interactive backend is available
|
||||
"""
|
||||
interactive = True
|
||||
|
||||
# First try Qt5Agg
|
||||
try:
|
||||
matplotlib.use('Qt5Agg')
|
||||
logger.info("Using Qt5Agg backend")
|
||||
return interactive
|
||||
except Exception:
|
||||
logger.warning("Could not use Qt5Agg backend")
|
||||
|
||||
# Then try TkAgg
|
||||
try:
|
||||
matplotlib.use('TkAgg')
|
||||
logger.info("Using TkAgg backend")
|
||||
return interactive
|
||||
except Exception:
|
||||
logger.warning("Could not use TkAgg backend")
|
||||
|
||||
# Finally fallback to Agg
|
||||
try:
|
||||
matplotlib.use('Agg')
|
||||
logger.info("Using non-interactive Agg backend")
|
||||
interactive = False
|
||||
return interactive
|
||||
except Exception as e:
|
||||
logger.error(f"Could not set up any matplotlib backend: {e}")
|
||||
raise
|
||||
|
||||
def create_output_directory() -> Path:
|
||||
"""Create and return output directory for simulation results."""
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
output_dir = Path('output') / timestamp
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
return output_dir
|
||||
|
||||
def run_simulation(
|
||||
config: dict,
|
||||
logger: logging.Logger,
|
||||
output_dir: Path,
|
||||
interactive: bool
|
||||
):
|
||||
"""Run the main simulation with comprehensive logging and visualization."""
|
||||
logger.info("Initializing simulation configurations...")
|
||||
|
||||
# Create network configuration
|
||||
network_config = NetworkConfig(
|
||||
num_nodes=config['network']['num_nodes'],
|
||||
initial_connectivity=config['network']['initial_connectivity'],
|
||||
min_weight=config['network']['min_weight'],
|
||||
max_weight=config['network']['max_weight'],
|
||||
dynamic_topology=config['network']['dynamic_topology'],
|
||||
topology_update_interval=config['network']['topology_update_interval']
|
||||
)
|
||||
|
||||
# Create dynamics configuration
|
||||
dynamics_config = DynamicsConfig(
|
||||
base_components=[
|
||||
WaveComponent(
|
||||
amplitude=comp['amplitude'],
|
||||
frequency=comp['frequency'],
|
||||
phase=comp['phase']
|
||||
)
|
||||
for comp in config['dynamics']['wave_components']
|
||||
],
|
||||
noise_std=config['dynamics']['noise_std'],
|
||||
time_scale=config['dynamics']['time_scale']
|
||||
)
|
||||
|
||||
# Create simulation configuration
|
||||
sim_config = SimulationConfig(
|
||||
network_config=network_config,
|
||||
dynamics_config=dynamics_config,
|
||||
num_steps=config['simulation']['total_steps'],
|
||||
save_interval=config['simulation']['save_interval'],
|
||||
visualization_interval=(
|
||||
config['simulation']['visualization_interval']
|
||||
if interactive
|
||||
else config['simulation']['total_steps'] // 10
|
||||
)
|
||||
)
|
||||
|
||||
logger.info("Creating visualizers...")
|
||||
basic_visualizer = NetworkVisualizer()
|
||||
advanced_visualizer = AdvancedVisualizer()
|
||||
|
||||
logger.info("Initializing simulation runner...")
|
||||
runner = SimulationRunner(sim_config, basic_visualizer)
|
||||
|
||||
# Initial simulation period
|
||||
logger.info("Running initial simulation period...")
|
||||
initial_states = runner.run(config['simulation']['initial_period'])
|
||||
|
||||
# Save initial period results
|
||||
basic_visualizer.save(output_dir / 'initial_state.png')
|
||||
logger.info("Saved initial state visualization")
|
||||
|
||||
# Add perturbation
|
||||
logger.info("Adding perturbation to the system...")
|
||||
runner.add_perturbation(
|
||||
magnitude=config['perturbation']['magnitude'],
|
||||
duration=config['perturbation']['duration'],
|
||||
decay=config['perturbation']['decay']
|
||||
)
|
||||
|
||||
# Continue simulation
|
||||
logger.info("Running post-perturbation simulation...")
|
||||
final_states = runner.run(
|
||||
config['simulation']['total_steps'] -
|
||||
config['simulation']['initial_period']
|
||||
)
|
||||
|
||||
# Save final basic visualization
|
||||
basic_visualizer.save(output_dir / 'final_state.png')
|
||||
logger.info("Saved final state visualization")
|
||||
|
||||
# Create advanced visualizations
|
||||
logger.info("Creating advanced visualizations...")
|
||||
|
||||
# Get full history
|
||||
history = runner.get_history()
|
||||
|
||||
# Create animations
|
||||
if config['visualization']['create_animations']:
|
||||
logger.info("Creating animations...")
|
||||
advanced_visualizer.create_network_animation(history, output_dir)
|
||||
advanced_visualizer.create_phase_space_animation(history, output_dir)
|
||||
|
||||
# Create static visualizations
|
||||
if config['visualization']['plots']['spectral_analysis']:
|
||||
logger.info("Creating spectral analysis...")
|
||||
advanced_visualizer.create_spectral_analysis(history, output_dir)
|
||||
|
||||
if config['visualization']['plots']['correlation_matrix']:
|
||||
logger.info("Creating correlation analysis...")
|
||||
advanced_visualizer.create_correlation_analysis(history, output_dir)
|
||||
|
||||
if config['visualization']['enable_interactive']:
|
||||
logger.info("Creating interactive dashboard...")
|
||||
advanced_visualizer.create_interactive_dashboard(history, output_dir)
|
||||
|
||||
basic_visualizer.close()
|
||||
logger.info("Simulation complete!")
|
||||
|
||||
return initial_states, final_states
|
||||
|
||||
def main():
|
||||
"""Main entry point for the simulation."""
|
||||
# Load configuration
|
||||
config = load_config()
|
||||
|
||||
# Create output directory
|
||||
output_dir = create_output_directory()
|
||||
|
||||
# Setup logging
|
||||
logger = setup_logging(output_dir)
|
||||
|
||||
try:
|
||||
# Setup matplotlib backend
|
||||
interactive = setup_matplotlib_backend(logger)
|
||||
|
||||
# Run simulation
|
||||
initial_states, final_states = run_simulation(
|
||||
config,
|
||||
logger,
|
||||
output_dir,
|
||||
interactive
|
||||
)
|
||||
|
||||
logger.info(f"Results saved to: {output_dir}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Simulation failed: {str(e)}", exc_info=True)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
112
Things/Path_Network/path_network/core/agent.py
Обычный файл
112
Things/Path_Network/path_network/core/agent.py
Обычный файл
@ -0,0 +1,112 @@
|
||||
"""
|
||||
Active Inference Agent implementation for the Path Network simulation.
|
||||
This module contains the core agent class that performs continuous-time active inference.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
@dataclass
|
||||
class AgentConfig:
|
||||
"""Configuration parameters for an Active Inference agent."""
|
||||
dt: float = 0.01 # Integration time step
|
||||
taylor_order: int = 2 # Order of Taylor expansion for generalized coordinates
|
||||
tolerance: float = 0.1 # Tolerance range for water level
|
||||
learning_rate: float = 0.01 # Learning rate for parameter updates
|
||||
initial_height: Optional[float] = None # Initial height of the agent
|
||||
|
||||
class ActiveInferenceAgent:
|
||||
"""
|
||||
An Active Inference agent that infers and responds to water level changes.
|
||||
|
||||
The agent uses generalized coordinates and continuous-time inference to
|
||||
maintain its height within a tolerable range of the global water level.
|
||||
"""
|
||||
|
||||
def __init__(self, config: AgentConfig):
|
||||
self.config = config
|
||||
self.height = (
|
||||
config.initial_height
|
||||
if config.initial_height is not None
|
||||
else np.random.normal(0, 0.1)
|
||||
)
|
||||
|
||||
# Generalized coordinates for position (height)
|
||||
self.gen_coords = torch.zeros(config.taylor_order)
|
||||
self.gen_coords[0] = self.height
|
||||
|
||||
# Free energy components
|
||||
self.mu = torch.zeros(config.taylor_order) # Expected states
|
||||
self.pi = torch.ones(config.taylor_order) # Precision (inverse variance)
|
||||
|
||||
# History for analysis
|
||||
self.height_history: List[float] = [self.height]
|
||||
self.prediction_error_history: List[float] = []
|
||||
|
||||
def update_beliefs(self, sensory_input: float) -> None:
|
||||
"""
|
||||
Update beliefs about the environment based on sensory input.
|
||||
|
||||
Args:
|
||||
sensory_input: The current water level measurement
|
||||
"""
|
||||
# Compute prediction error
|
||||
prediction_error = sensory_input - self.mu[0]
|
||||
self.prediction_error_history.append(prediction_error.item())
|
||||
|
||||
# Update generalized coordinates
|
||||
for i in range(self.config.taylor_order - 1):
|
||||
self.gen_coords[i] += (
|
||||
self.gen_coords[i + 1] * self.config.dt +
|
||||
self.config.learning_rate * prediction_error * self.pi[i]
|
||||
)
|
||||
|
||||
# Update expectations
|
||||
self.mu = self.gen_coords.clone()
|
||||
|
||||
def act(self, water_level: float) -> float:
|
||||
"""
|
||||
Generate an action (height adjustment) based on current beliefs.
|
||||
|
||||
Args:
|
||||
water_level: Current global water level
|
||||
|
||||
Returns:
|
||||
float: The new height of the agent
|
||||
"""
|
||||
# Update beliefs based on sensory input
|
||||
self.update_beliefs(water_level)
|
||||
|
||||
# Compute desired height adjustment
|
||||
error = water_level - self.height
|
||||
adjustment = np.clip(
|
||||
error * self.config.learning_rate,
|
||||
-self.config.tolerance,
|
||||
self.config.tolerance
|
||||
)
|
||||
|
||||
# Update height
|
||||
self.height += adjustment
|
||||
self.height_history.append(self.height)
|
||||
|
||||
return self.height
|
||||
|
||||
def get_state(self) -> Tuple[float, List[float]]:
|
||||
"""
|
||||
Get the current state of the agent.
|
||||
|
||||
Returns:
|
||||
Tuple containing current height and generalized coordinates
|
||||
"""
|
||||
return self.height, self.gen_coords.tolist()
|
||||
|
||||
def get_history(self) -> Tuple[List[float], List[float]]:
|
||||
"""
|
||||
Get the agent's history of heights and prediction errors.
|
||||
|
||||
Returns:
|
||||
Tuple containing height history and prediction error history
|
||||
"""
|
||||
return self.height_history, self.prediction_error_history
|
||||
126
Things/Path_Network/path_network/core/dynamics.py
Обычный файл
126
Things/Path_Network/path_network/core/dynamics.py
Обычный файл
@ -0,0 +1,126 @@
|
||||
"""
|
||||
Environmental dynamics for the Path Network simulation.
|
||||
Generates nested sinusoidal waves that represent the global water level.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
@dataclass
|
||||
class WaveComponent:
|
||||
"""Parameters for a single sinusoidal wave component."""
|
||||
amplitude: float
|
||||
frequency: float
|
||||
phase: float = 0.0
|
||||
|
||||
@dataclass
|
||||
class DynamicsConfig:
|
||||
"""Configuration for the environmental dynamics."""
|
||||
base_components: List[WaveComponent] = None
|
||||
noise_std: float = 0.05
|
||||
time_scale: float = 1.0
|
||||
|
||||
def __post_init__(self):
|
||||
if self.base_components is None:
|
||||
# Default wave components
|
||||
self.base_components = [
|
||||
WaveComponent(amplitude=1.0, frequency=0.1), # Slow wave
|
||||
WaveComponent(amplitude=0.5, frequency=0.5), # Medium wave
|
||||
WaveComponent(amplitude=0.2, frequency=2.0) # Fast wave
|
||||
]
|
||||
|
||||
class EnvironmentalDynamics:
|
||||
"""
|
||||
Generates and manages the environmental dynamics (water level) through
|
||||
nested sinusoidal waves with optional noise and perturbations.
|
||||
"""
|
||||
|
||||
def __init__(self, config: DynamicsConfig):
|
||||
self.config = config
|
||||
self.time = 0.0
|
||||
self.history: List[float] = []
|
||||
self.perturbation: Optional[Tuple[float, float, float]] = None
|
||||
|
||||
def step(self) -> float:
|
||||
"""
|
||||
Compute the next water level value.
|
||||
|
||||
Returns:
|
||||
float: The current global water level
|
||||
"""
|
||||
# Base level from superposition of waves
|
||||
level = sum(
|
||||
component.amplitude * np.sin(
|
||||
2 * np.pi * component.frequency * self.time * self.config.time_scale
|
||||
+ component.phase
|
||||
)
|
||||
for component in self.config.base_components
|
||||
)
|
||||
|
||||
# Add noise
|
||||
if self.config.noise_std > 0:
|
||||
level += np.random.normal(0, self.config.noise_std)
|
||||
|
||||
# Add any active perturbation
|
||||
if self.perturbation is not None:
|
||||
magnitude, duration, decay = self.perturbation
|
||||
if self.time < duration:
|
||||
level += magnitude * (1 - self.time / duration)
|
||||
else:
|
||||
# Remove perturbation after it expires
|
||||
self.perturbation = None
|
||||
|
||||
# Update time and history
|
||||
self.time += 1
|
||||
self.history.append(level)
|
||||
|
||||
return level
|
||||
|
||||
def add_perturbation(
|
||||
self,
|
||||
magnitude: float,
|
||||
duration: float,
|
||||
decay: float = 1.0
|
||||
) -> None:
|
||||
"""
|
||||
Add a temporary perturbation to the water level.
|
||||
|
||||
Args:
|
||||
magnitude: Size of the perturbation
|
||||
duration: How long the perturbation lasts
|
||||
decay: How quickly the perturbation decays (1.0 = linear)
|
||||
"""
|
||||
self.perturbation = (magnitude, duration, decay)
|
||||
|
||||
def add_wave_component(
|
||||
self,
|
||||
amplitude: float,
|
||||
frequency: float,
|
||||
phase: float = 0.0
|
||||
) -> None:
|
||||
"""
|
||||
Add a new wave component to the dynamics.
|
||||
|
||||
Args:
|
||||
amplitude: Wave amplitude
|
||||
frequency: Wave frequency
|
||||
phase: Wave phase shift
|
||||
"""
|
||||
self.config.base_components.append(
|
||||
WaveComponent(amplitude, frequency, phase)
|
||||
)
|
||||
|
||||
def get_history(self) -> List[float]:
|
||||
"""Get the history of water levels."""
|
||||
return self.history.copy()
|
||||
|
||||
def get_wave_components(self) -> List[WaveComponent]:
|
||||
"""Get the current wave components."""
|
||||
return self.config.base_components.copy()
|
||||
|
||||
def reset(self) -> None:
|
||||
"""Reset the dynamics to initial state."""
|
||||
self.time = 0.0
|
||||
self.history.clear()
|
||||
self.perturbation = None
|
||||
173
Things/Path_Network/path_network/core/network.py
Обычный файл
173
Things/Path_Network/path_network/core/network.py
Обычный файл
@ -0,0 +1,173 @@
|
||||
"""
|
||||
Network topology management for the Path Network simulation.
|
||||
Handles the creation and management of the network of Active Inference agents.
|
||||
"""
|
||||
|
||||
import networkx as nx
|
||||
import numpy as np
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
from dataclasses import dataclass
|
||||
from .agent import ActiveInferenceAgent, AgentConfig
|
||||
|
||||
@dataclass
|
||||
class NetworkConfig:
|
||||
"""Configuration parameters for the network topology."""
|
||||
num_nodes: int = 10
|
||||
initial_connectivity: float = 0.3 # Probability of edge creation
|
||||
min_weight: float = 0.1
|
||||
max_weight: float = 1.0
|
||||
dynamic_topology: bool = True
|
||||
topology_update_interval: int = 100 # Steps between topology updates
|
||||
|
||||
class PathNetwork:
|
||||
"""
|
||||
Manages a network of Active Inference agents and their interactions.
|
||||
|
||||
The network topology is represented as a weighted directed graph where
|
||||
edges represent influence relationships between agents.
|
||||
"""
|
||||
|
||||
def __init__(self, network_config: NetworkConfig):
|
||||
self.config = network_config
|
||||
self.graph = nx.DiGraph()
|
||||
self.agents: Dict[int, ActiveInferenceAgent] = {}
|
||||
self.step_counter = 0
|
||||
|
||||
# Initialize network
|
||||
self._initialize_network()
|
||||
|
||||
def _initialize_network(self) -> None:
|
||||
"""Initialize the network topology and create agents."""
|
||||
# Create nodes with agents
|
||||
for i in range(self.config.num_nodes):
|
||||
agent_config = AgentConfig(
|
||||
initial_height=np.random.normal(0, 0.1)
|
||||
)
|
||||
self.agents[i] = ActiveInferenceAgent(agent_config)
|
||||
self.graph.add_node(i)
|
||||
|
||||
# Create random edges
|
||||
for i in range(self.config.num_nodes):
|
||||
for j in range(self.config.num_nodes):
|
||||
if i != j and np.random.random() < self.config.initial_connectivity:
|
||||
weight = np.random.uniform(
|
||||
self.config.min_weight,
|
||||
self.config.max_weight
|
||||
)
|
||||
self.graph.add_edge(i, j, weight=weight)
|
||||
|
||||
def update_topology(self) -> None:
|
||||
"""
|
||||
Update network topology based on agent interactions and performance.
|
||||
This is called periodically to evolve the network structure.
|
||||
"""
|
||||
if not self.config.dynamic_topology:
|
||||
return
|
||||
|
||||
# Update edge weights based on prediction error correlation
|
||||
for i, j in self.graph.edges():
|
||||
agent_i = self.agents[i]
|
||||
agent_j = self.agents[j]
|
||||
|
||||
# Compute correlation between agents' prediction errors
|
||||
corr = np.corrcoef(
|
||||
agent_i.prediction_error_history[-100:],
|
||||
agent_j.prediction_error_history[-100:]
|
||||
)[0, 1]
|
||||
|
||||
# Update edge weight
|
||||
new_weight = np.clip(
|
||||
abs(corr),
|
||||
self.config.min_weight,
|
||||
self.config.max_weight
|
||||
)
|
||||
self.graph[i][j]['weight'] = new_weight
|
||||
|
||||
# Potentially add or remove edges based on agent performance
|
||||
self._update_connections()
|
||||
|
||||
def _update_connections(self) -> None:
|
||||
"""Update network connections based on agent performance."""
|
||||
# Add edges between well-performing agents
|
||||
for i in range(self.config.num_nodes):
|
||||
for j in range(self.config.num_nodes):
|
||||
if i != j and not self.graph.has_edge(i, j):
|
||||
# Add edge if agents have similar performance
|
||||
if self._should_connect(i, j):
|
||||
weight = np.random.uniform(
|
||||
self.config.min_weight,
|
||||
self.config.max_weight
|
||||
)
|
||||
self.graph.add_edge(i, j, weight=weight)
|
||||
|
||||
# Remove edges with very low weights
|
||||
edges_to_remove = [
|
||||
(i, j) for i, j, w in self.graph.edges(data='weight')
|
||||
if w < self.config.min_weight
|
||||
]
|
||||
self.graph.remove_edges_from(edges_to_remove)
|
||||
|
||||
def _should_connect(self, i: int, j: int) -> bool:
|
||||
"""Determine if two agents should be connected based on their performance."""
|
||||
agent_i = self.agents[i]
|
||||
agent_j = self.agents[j]
|
||||
|
||||
# Compare recent performance
|
||||
errors_i = np.mean(agent_i.prediction_error_history[-50:])
|
||||
errors_j = np.mean(agent_j.prediction_error_history[-50:])
|
||||
|
||||
# Connect if agents have similar error levels
|
||||
return abs(errors_i - errors_j) < 0.1
|
||||
|
||||
def step(self, global_water_level: float) -> Dict[int, float]:
|
||||
"""
|
||||
Perform one step of network simulation.
|
||||
|
||||
Args:
|
||||
global_water_level: The current global water level
|
||||
|
||||
Returns:
|
||||
Dict mapping node IDs to their new heights
|
||||
"""
|
||||
self.step_counter += 1
|
||||
|
||||
# Update agent states
|
||||
new_heights = {}
|
||||
for node_id, agent in self.agents.items():
|
||||
# Compute weighted average of neighbors' heights
|
||||
neighbor_influence = 0.0
|
||||
total_weight = 0.0
|
||||
|
||||
for neighbor_id in self.graph.predecessors(node_id):
|
||||
weight = self.graph[neighbor_id][node_id]['weight']
|
||||
neighbor_height = self.agents[neighbor_id].height
|
||||
neighbor_influence += weight * neighbor_height
|
||||
total_weight += weight
|
||||
|
||||
if total_weight > 0:
|
||||
effective_level = (
|
||||
0.7 * global_water_level +
|
||||
0.3 * (neighbor_influence / total_weight)
|
||||
)
|
||||
else:
|
||||
effective_level = global_water_level
|
||||
|
||||
# Update agent
|
||||
new_height = agent.act(effective_level)
|
||||
new_heights[node_id] = new_height
|
||||
|
||||
# Periodically update topology
|
||||
if (self.step_counter % self.config.topology_update_interval) == 0:
|
||||
self.update_topology()
|
||||
|
||||
return new_heights
|
||||
|
||||
def get_network_state(self) -> Tuple[nx.DiGraph, Dict[int, float]]:
|
||||
"""
|
||||
Get the current state of the network.
|
||||
|
||||
Returns:
|
||||
Tuple containing the network graph and current agent heights
|
||||
"""
|
||||
heights = {i: agent.height for i, agent in self.agents.items()}
|
||||
return self.graph, heights
|
||||
120
Things/Path_Network/path_network/simulation/runner.py
Обычный файл
120
Things/Path_Network/path_network/simulation/runner.py
Обычный файл
@ -0,0 +1,120 @@
|
||||
"""
|
||||
Main simulation runner for the Path Network.
|
||||
Orchestrates the interaction between the network of agents and environmental dynamics.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
from dataclasses import dataclass
|
||||
from ..core.network import PathNetwork, NetworkConfig
|
||||
from ..core.dynamics import EnvironmentalDynamics, DynamicsConfig
|
||||
from ..utils.visualization import NetworkVisualizer
|
||||
|
||||
@dataclass
|
||||
class SimulationConfig:
|
||||
"""Configuration for the simulation."""
|
||||
network_config: NetworkConfig
|
||||
dynamics_config: DynamicsConfig
|
||||
num_steps: int = 1000
|
||||
save_interval: int = 10
|
||||
visualization_interval: int = 50
|
||||
|
||||
class SimulationRunner:
|
||||
"""
|
||||
Main simulation runner that coordinates the network of agents
|
||||
and environmental dynamics.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: SimulationConfig,
|
||||
visualizer: Optional[NetworkVisualizer] = None
|
||||
):
|
||||
self.config = config
|
||||
self.network = PathNetwork(config.network_config)
|
||||
self.dynamics = EnvironmentalDynamics(config.dynamics_config)
|
||||
self.visualizer = visualizer
|
||||
|
||||
self.current_step = 0
|
||||
self.history: List[Dict] = []
|
||||
|
||||
def step(self) -> Dict:
|
||||
"""
|
||||
Perform one step of the simulation.
|
||||
|
||||
Returns:
|
||||
Dict containing the current state of the simulation
|
||||
"""
|
||||
# Get current water level
|
||||
water_level = self.dynamics.step()
|
||||
|
||||
# Update network
|
||||
agent_heights = self.network.step(water_level)
|
||||
|
||||
# Record state
|
||||
state = {
|
||||
'step': self.current_step,
|
||||
'water_level': water_level,
|
||||
'agent_heights': agent_heights
|
||||
}
|
||||
|
||||
if self.current_step % self.config.save_interval == 0:
|
||||
self.history.append(state)
|
||||
|
||||
# Visualize if needed
|
||||
if (
|
||||
self.visualizer is not None and
|
||||
self.current_step % self.config.visualization_interval == 0
|
||||
):
|
||||
self.visualizer.update(self.network, water_level)
|
||||
|
||||
self.current_step += 1
|
||||
return state
|
||||
|
||||
def run(self, num_steps: Optional[int] = None) -> List[Dict]:
|
||||
"""
|
||||
Run the simulation for a specified number of steps.
|
||||
|
||||
Args:
|
||||
num_steps: Number of steps to run (default: config.num_steps)
|
||||
|
||||
Returns:
|
||||
List of recorded states
|
||||
"""
|
||||
steps_to_run = num_steps or self.config.num_steps
|
||||
|
||||
for _ in range(steps_to_run):
|
||||
self.step()
|
||||
|
||||
return self.history
|
||||
|
||||
def add_perturbation(
|
||||
self,
|
||||
magnitude: float,
|
||||
duration: float,
|
||||
decay: float = 1.0
|
||||
) -> None:
|
||||
"""Add a perturbation to the environmental dynamics."""
|
||||
self.dynamics.add_perturbation(magnitude, duration, decay)
|
||||
|
||||
def get_network_state(self) -> Tuple[Dict[int, float], float]:
|
||||
"""
|
||||
Get the current state of the network and environment.
|
||||
|
||||
Returns:
|
||||
Tuple of agent heights and current water level
|
||||
"""
|
||||
_, heights = self.network.get_network_state()
|
||||
water_level = self.dynamics.history[-1] if self.dynamics.history else 0.0
|
||||
return heights, water_level
|
||||
|
||||
def get_history(self) -> List[Dict]:
|
||||
"""Get the simulation history."""
|
||||
return self.history.copy()
|
||||
|
||||
def reset(self) -> None:
|
||||
"""Reset the simulation to initial state."""
|
||||
self.current_step = 0
|
||||
self.history.clear()
|
||||
self.dynamics.reset()
|
||||
# Note: Network is not reset as it maintains its learned structure
|
||||
390
Things/Path_Network/path_network/utils/advanced_visualization.py
Обычный файл
390
Things/Path_Network/path_network/utils/advanced_visualization.py
Обычный файл
@ -0,0 +1,390 @@
|
||||
"""
|
||||
Advanced visualization utilities for the Path Network simulation.
|
||||
Provides comprehensive visualization options including animations and 3D plots.
|
||||
"""
|
||||
|
||||
import os
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import networkx as nx
|
||||
import seaborn as sns
|
||||
import plotly.graph_objects as go
|
||||
from plotly.subplots import make_subplots
|
||||
import plotly.express as px
|
||||
from matplotlib.animation import FuncAnimation, PillowWriter
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
from scipy import signal
|
||||
from scipy.stats import gaussian_kde
|
||||
from typing import Dict, List, Optional, Tuple, Any
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from tqdm import tqdm
|
||||
import imageio
|
||||
from sklearn.decomposition import PCA
|
||||
from ..core.network import PathNetwork
|
||||
|
||||
class AdvancedVisualizer:
|
||||
"""Advanced visualization tools for the Path Network simulation."""
|
||||
|
||||
def __init__(self, config_path: str = "config.yaml"):
|
||||
# Load configuration
|
||||
with open(config_path, 'r') as f:
|
||||
self.config = yaml.safe_load(f)['visualization']
|
||||
|
||||
# Set style
|
||||
plt.style.use(self.config['style'])
|
||||
sns.set_context("notebook", font_scale=self.config['font_scale'])
|
||||
|
||||
# Initialize storage for animation frames
|
||||
self.network_frames: List[plt.Figure] = []
|
||||
self.phase_space_frames: List[plt.Figure] = []
|
||||
|
||||
def create_network_animation(
|
||||
self,
|
||||
history: List[Dict],
|
||||
output_path: Path
|
||||
) -> None:
|
||||
"""Create an animated visualization of the network evolution."""
|
||||
fig = plt.figure(figsize=self.config['animation_figsize'])
|
||||
|
||||
def update(frame):
|
||||
plt.clf()
|
||||
state = history[frame]
|
||||
self._draw_network_state(state, fig.gca())
|
||||
return fig.gca()
|
||||
|
||||
anim = FuncAnimation(
|
||||
fig,
|
||||
update,
|
||||
frames=len(history),
|
||||
interval=1000/self.config['fps']
|
||||
)
|
||||
|
||||
# Save as GIF
|
||||
writer = PillowWriter(fps=self.config['fps'])
|
||||
anim.save(output_path / 'network_evolution.gif', writer=writer)
|
||||
plt.close()
|
||||
|
||||
def create_phase_space_animation(
|
||||
self,
|
||||
history: List[Dict],
|
||||
output_path: Path
|
||||
) -> None:
|
||||
"""Create an animated 3D phase space visualization."""
|
||||
if not self.config['enable_3d']:
|
||||
return
|
||||
|
||||
fig = plt.figure(figsize=self.config['animation_figsize'])
|
||||
ax = fig.add_subplot(111, projection='3d')
|
||||
|
||||
# Compute PCA for dimensionality reduction
|
||||
heights_matrix = []
|
||||
for state in history:
|
||||
heights = list(state['agent_heights'].values())
|
||||
heights_matrix.append(heights)
|
||||
|
||||
pca = PCA(n_components=3)
|
||||
transformed = pca.fit_transform(heights_matrix)
|
||||
|
||||
def update(frame):
|
||||
ax.clear()
|
||||
ax.scatter(
|
||||
transformed[:frame+1, 0],
|
||||
transformed[:frame+1, 1],
|
||||
transformed[:frame+1, 2],
|
||||
c=range(frame+1),
|
||||
cmap='viridis'
|
||||
)
|
||||
ax.view_init(
|
||||
elev=30,
|
||||
azim=frame * self.config['3d_rotation_speed']
|
||||
)
|
||||
return ax
|
||||
|
||||
anim = FuncAnimation(
|
||||
fig,
|
||||
update,
|
||||
frames=len(history),
|
||||
interval=1000/self.config['fps']
|
||||
)
|
||||
|
||||
anim.save(output_path / 'phase_space.gif', writer=PillowWriter(fps=self.config['fps']))
|
||||
plt.close()
|
||||
|
||||
def create_spectral_analysis(
|
||||
self,
|
||||
history: List[Dict],
|
||||
output_path: Path
|
||||
) -> None:
|
||||
"""Create spectral analysis visualizations."""
|
||||
water_levels = [state['water_level'] for state in history]
|
||||
|
||||
# Compute spectrograms for water level
|
||||
f, t, Sxx = signal.spectrogram(water_levels, fs=1.0)
|
||||
|
||||
plt.figure(figsize=self.config['timeseries_figsize'])
|
||||
plt.pcolormesh(t, f, Sxx, shading='gouraud')
|
||||
plt.ylabel('Frequency')
|
||||
plt.xlabel('Time')
|
||||
plt.title('Water Level Spectrogram')
|
||||
plt.colorbar(label='Intensity')
|
||||
plt.savefig(output_path / 'water_level_spectrogram.png', dpi=self.config['dpi'])
|
||||
plt.close()
|
||||
|
||||
# Compute and plot power spectrum
|
||||
plt.figure(figsize=self.config['timeseries_figsize'])
|
||||
f, Pxx = signal.welch(water_levels)
|
||||
plt.semilogy(f, Pxx)
|
||||
plt.xlabel('Frequency')
|
||||
plt.ylabel('Power Spectral Density')
|
||||
plt.title('Water Level Power Spectrum')
|
||||
plt.savefig(output_path / 'power_spectrum.png', dpi=self.config['dpi'])
|
||||
plt.close()
|
||||
|
||||
def create_correlation_analysis(
|
||||
self,
|
||||
history: List[Dict],
|
||||
output_path: Path
|
||||
) -> None:
|
||||
"""Create correlation analysis visualizations."""
|
||||
# Extract agent height histories
|
||||
agent_histories = {}
|
||||
for state in history:
|
||||
for agent_id, height in state['agent_heights'].items():
|
||||
if agent_id not in agent_histories:
|
||||
agent_histories[agent_id] = []
|
||||
agent_histories[agent_id].append(height)
|
||||
|
||||
# Compute correlation matrix
|
||||
num_agents = len(agent_histories)
|
||||
corr_matrix = np.zeros((num_agents, num_agents))
|
||||
|
||||
for i in range(num_agents):
|
||||
for j in range(num_agents):
|
||||
corr = np.corrcoef(
|
||||
agent_histories[i],
|
||||
agent_histories[j]
|
||||
)[0, 1]
|
||||
corr_matrix[i, j] = corr
|
||||
|
||||
# Plot correlation matrix
|
||||
plt.figure(figsize=self.config['network_figsize'])
|
||||
sns.heatmap(
|
||||
corr_matrix,
|
||||
cmap='RdBu_r',
|
||||
center=0,
|
||||
vmin=-1,
|
||||
vmax=1,
|
||||
annot=True,
|
||||
fmt='.2f'
|
||||
)
|
||||
plt.title('Agent Height Correlation Matrix')
|
||||
plt.savefig(output_path / 'correlation_matrix.png', dpi=self.config['dpi'])
|
||||
plt.close()
|
||||
|
||||
def create_interactive_dashboard(
|
||||
self,
|
||||
history: List[Dict],
|
||||
output_path: Path
|
||||
) -> None:
|
||||
"""Create an interactive HTML dashboard using plotly."""
|
||||
if not self.config['enable_interactive']:
|
||||
return
|
||||
|
||||
# Create subplot figure
|
||||
fig = make_subplots(
|
||||
rows=2,
|
||||
cols=2,
|
||||
specs=[[{'type': 'scatter3d'}, {'type': 'heatmap'}],
|
||||
[{'type': 'scatter'}, {'type': 'histogram'}]],
|
||||
subplot_titles=(
|
||||
'3D Phase Space',
|
||||
'Agent Correlation',
|
||||
'Height Evolution',
|
||||
'Height Distribution'
|
||||
)
|
||||
)
|
||||
|
||||
# Add traces
|
||||
self._add_phase_space_trace(fig, history, row=1, col=1)
|
||||
self._add_correlation_trace(fig, history, row=1, col=2)
|
||||
self._add_height_evolution_trace(fig, history, row=2, col=1)
|
||||
self._add_height_distribution_trace(fig, history, row=2, col=2)
|
||||
|
||||
# Update layout
|
||||
fig.update_layout(height=1000, showlegend=True)
|
||||
|
||||
# Save
|
||||
fig.write_html(output_path / 'interactive_dashboard.html')
|
||||
|
||||
def _add_phase_space_trace(
|
||||
self,
|
||||
fig: go.Figure,
|
||||
history: List[Dict],
|
||||
row: int,
|
||||
col: int
|
||||
) -> None:
|
||||
"""Add 3D phase space trace to plotly figure."""
|
||||
heights_matrix = []
|
||||
for state in history:
|
||||
heights = list(state['agent_heights'].values())
|
||||
heights_matrix.append(heights)
|
||||
|
||||
pca = PCA(n_components=3)
|
||||
transformed = pca.fit_transform(heights_matrix)
|
||||
|
||||
fig.add_trace(
|
||||
go.Scatter3d(
|
||||
x=transformed[:, 0],
|
||||
y=transformed[:, 1],
|
||||
z=transformed[:, 2],
|
||||
mode='lines+markers',
|
||||
marker=dict(
|
||||
size=2,
|
||||
color=range(len(transformed)),
|
||||
colorscale='Viridis',
|
||||
opacity=0.8
|
||||
),
|
||||
name='Phase Space'
|
||||
),
|
||||
row=row,
|
||||
col=col
|
||||
)
|
||||
|
||||
def _add_correlation_trace(
|
||||
self,
|
||||
fig: go.Figure,
|
||||
history: List[Dict],
|
||||
row: int,
|
||||
col: int
|
||||
) -> None:
|
||||
"""Add correlation matrix trace to plotly figure."""
|
||||
agent_histories = {}
|
||||
for state in history:
|
||||
for agent_id, height in state['agent_heights'].items():
|
||||
if agent_id not in agent_histories:
|
||||
agent_histories[agent_id] = []
|
||||
agent_histories[agent_id].append(height)
|
||||
|
||||
num_agents = len(agent_histories)
|
||||
corr_matrix = np.zeros((num_agents, num_agents))
|
||||
|
||||
for i in range(num_agents):
|
||||
for j in range(num_agents):
|
||||
corr = np.corrcoef(
|
||||
agent_histories[i],
|
||||
agent_histories[j]
|
||||
)[0, 1]
|
||||
corr_matrix[i, j] = corr
|
||||
|
||||
fig.add_trace(
|
||||
go.Heatmap(
|
||||
z=corr_matrix,
|
||||
colorscale='RdBu',
|
||||
zmid=0,
|
||||
name='Correlation'
|
||||
),
|
||||
row=row,
|
||||
col=col
|
||||
)
|
||||
|
||||
def _add_height_evolution_trace(
|
||||
self,
|
||||
fig: go.Figure,
|
||||
history: List[Dict],
|
||||
row: int,
|
||||
col: int
|
||||
) -> None:
|
||||
"""Add height evolution traces to plotly figure."""
|
||||
water_levels = [state['water_level'] for state in history]
|
||||
time_points = list(range(len(history)))
|
||||
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x=time_points,
|
||||
y=water_levels,
|
||||
mode='lines',
|
||||
name='Water Level',
|
||||
line=dict(color='red', dash='dash')
|
||||
),
|
||||
row=row,
|
||||
col=col
|
||||
)
|
||||
|
||||
for agent_id in history[0]['agent_heights'].keys():
|
||||
heights = [
|
||||
state['agent_heights'][agent_id]
|
||||
for state in history
|
||||
]
|
||||
fig.add_trace(
|
||||
go.Scatter(
|
||||
x=time_points,
|
||||
y=heights,
|
||||
mode='lines',
|
||||
name=f'Agent {agent_id}',
|
||||
opacity=0.6
|
||||
),
|
||||
row=row,
|
||||
col=col
|
||||
)
|
||||
|
||||
def _add_height_distribution_trace(
|
||||
self,
|
||||
fig: go.Figure,
|
||||
history: List[Dict],
|
||||
row: int,
|
||||
col: int
|
||||
) -> None:
|
||||
"""Add height distribution trace to plotly figure."""
|
||||
all_heights = []
|
||||
for state in history:
|
||||
all_heights.extend(state['agent_heights'].values())
|
||||
|
||||
fig.add_trace(
|
||||
go.Histogram(
|
||||
x=all_heights,
|
||||
nbinsx=30,
|
||||
name='Height Distribution'
|
||||
),
|
||||
row=row,
|
||||
col=col
|
||||
)
|
||||
|
||||
def _draw_network_state(
|
||||
self,
|
||||
state: Dict,
|
||||
ax: plt.Axes
|
||||
) -> None:
|
||||
"""Draw network state for animation frame."""
|
||||
graph = state['network']
|
||||
heights = state['agent_heights']
|
||||
|
||||
pos = nx.spring_layout(graph, seed=42)
|
||||
|
||||
nx.draw_networkx_nodes(
|
||||
graph,
|
||||
pos,
|
||||
node_color=[heights[node] for node in graph.nodes()],
|
||||
node_size=500,
|
||||
cmap=self.config['network_cmap'],
|
||||
ax=ax
|
||||
)
|
||||
|
||||
nx.draw_networkx_edges(
|
||||
graph,
|
||||
pos,
|
||||
edge_color='gray',
|
||||
width=[
|
||||
graph[u][v]['weight'] * 2
|
||||
for u, v in graph.edges()
|
||||
],
|
||||
alpha=0.6,
|
||||
ax=ax
|
||||
)
|
||||
|
||||
nx.draw_networkx_labels(
|
||||
graph,
|
||||
pos,
|
||||
{node: str(node) for node in graph.nodes()},
|
||||
ax=ax
|
||||
)
|
||||
150
Things/Path_Network/path_network/utils/math_utils.py
Обычный файл
150
Things/Path_Network/path_network/utils/math_utils.py
Обычный файл
@ -0,0 +1,150 @@
|
||||
"""
|
||||
Mathematical utilities for the Path Network simulation.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
from typing import List, Tuple, Union
|
||||
import torch
|
||||
|
||||
def compute_free_energy(
|
||||
mu: torch.Tensor,
|
||||
sigma: torch.Tensor,
|
||||
sensory_input: torch.Tensor
|
||||
) -> torch.Tensor:
|
||||
"""
|
||||
Compute the variational free energy.
|
||||
|
||||
Args:
|
||||
mu: Expected state
|
||||
sigma: Variance of state estimation
|
||||
sensory_input: Observed sensory input
|
||||
|
||||
Returns:
|
||||
Free energy value
|
||||
"""
|
||||
precision = 1.0 / sigma
|
||||
prediction_error = sensory_input - mu
|
||||
return 0.5 * (prediction_error**2 * precision + torch.log(sigma))
|
||||
|
||||
def generalized_coordinates_update(
|
||||
coords: torch.Tensor,
|
||||
dt: float,
|
||||
order: int
|
||||
) -> torch.Tensor:
|
||||
"""
|
||||
Update generalized coordinates using Taylor series expansion.
|
||||
|
||||
Args:
|
||||
coords: Current generalized coordinates
|
||||
dt: Time step
|
||||
order: Order of Taylor expansion
|
||||
|
||||
Returns:
|
||||
Updated generalized coordinates
|
||||
"""
|
||||
new_coords = coords.clone()
|
||||
|
||||
for i in range(order - 1):
|
||||
new_coords[i] += coords[i + 1] * dt
|
||||
|
||||
return new_coords
|
||||
|
||||
def compute_correlation_matrix(
|
||||
time_series: List[np.ndarray]
|
||||
) -> np.ndarray:
|
||||
"""
|
||||
Compute correlation matrix between multiple time series.
|
||||
|
||||
Args:
|
||||
time_series: List of time series data
|
||||
|
||||
Returns:
|
||||
Correlation matrix
|
||||
"""
|
||||
n = len(time_series)
|
||||
corr_matrix = np.zeros((n, n))
|
||||
|
||||
for i in range(n):
|
||||
for j in range(n):
|
||||
corr_matrix[i, j] = np.corrcoef(time_series[i], time_series[j])[0, 1]
|
||||
|
||||
return corr_matrix
|
||||
|
||||
def compute_prediction_error_metrics(
|
||||
predictions: np.ndarray,
|
||||
observations: np.ndarray
|
||||
) -> Tuple[float, float, float]:
|
||||
"""
|
||||
Compute various prediction error metrics.
|
||||
|
||||
Args:
|
||||
predictions: Predicted values
|
||||
observations: Observed values
|
||||
|
||||
Returns:
|
||||
Tuple of (MSE, MAE, RMSE)
|
||||
"""
|
||||
mse = np.mean((predictions - observations) ** 2)
|
||||
mae = np.mean(np.abs(predictions - observations))
|
||||
rmse = np.sqrt(mse)
|
||||
return mse, mae, rmse
|
||||
|
||||
def sigmoid_scale(
|
||||
x: Union[float, np.ndarray],
|
||||
scale: float = 1.0,
|
||||
offset: float = 0.0
|
||||
) -> Union[float, np.ndarray]:
|
||||
"""
|
||||
Apply sigmoid scaling to a value or array.
|
||||
|
||||
Args:
|
||||
x: Input value(s)
|
||||
scale: Scaling factor
|
||||
offset: Offset value
|
||||
|
||||
Returns:
|
||||
Scaled value(s)
|
||||
"""
|
||||
return 1 / (1 + np.exp(-(x - offset) / scale))
|
||||
|
||||
def compute_entropy(
|
||||
probabilities: np.ndarray,
|
||||
epsilon: float = 1e-10
|
||||
) -> float:
|
||||
"""
|
||||
Compute the entropy of a probability distribution.
|
||||
|
||||
Args:
|
||||
probabilities: Probability distribution
|
||||
epsilon: Small value to avoid log(0)
|
||||
|
||||
Returns:
|
||||
Entropy value
|
||||
"""
|
||||
# Ensure probabilities sum to 1 and are positive
|
||||
p = np.clip(probabilities, epsilon, 1.0)
|
||||
p = p / np.sum(p)
|
||||
|
||||
return -np.sum(p * np.log(p))
|
||||
|
||||
def exponential_moving_average(
|
||||
data: np.ndarray,
|
||||
alpha: float = 0.1
|
||||
) -> np.ndarray:
|
||||
"""
|
||||
Compute exponential moving average of a time series.
|
||||
|
||||
Args:
|
||||
data: Input time series
|
||||
alpha: Smoothing factor (0 < alpha < 1)
|
||||
|
||||
Returns:
|
||||
Smoothed time series
|
||||
"""
|
||||
result = np.zeros_like(data)
|
||||
result[0] = data[0]
|
||||
|
||||
for t in range(1, len(data)):
|
||||
result[t] = alpha * data[t] + (1 - alpha) * result[t-1]
|
||||
|
||||
return result
|
||||
233
Things/Path_Network/path_network/utils/visualization.py
Обычный файл
233
Things/Path_Network/path_network/utils/visualization.py
Обычный файл
@ -0,0 +1,233 @@
|
||||
"""
|
||||
Visualization utilities for the Path Network simulation.
|
||||
Provides real-time visualization of the network topology and agent states.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import networkx as nx
|
||||
import seaborn as sns
|
||||
from matplotlib.animation import FuncAnimation
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
from ..core.network import PathNetwork
|
||||
|
||||
class NetworkVisualizer:
|
||||
"""
|
||||
Visualizes the network topology and agent states in real-time.
|
||||
"""
|
||||
|
||||
def __init__(self, figsize: Tuple[int, int] = (15, 10)):
|
||||
# Set up style
|
||||
try:
|
||||
sns.set_style("whitegrid")
|
||||
sns.set_context("notebook", font_scale=1.2)
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not set seaborn style: {e}")
|
||||
plt.style.use('default')
|
||||
|
||||
self.fig = plt.figure(figsize=figsize)
|
||||
|
||||
# Create subplots
|
||||
self.network_ax = self.fig.add_subplot(221)
|
||||
self.heights_ax = self.fig.add_subplot(222)
|
||||
self.history_ax = self.fig.add_subplot(212)
|
||||
|
||||
# Initialize data storage
|
||||
self.water_level_history: List[float] = []
|
||||
self.height_histories: Dict[int, List[float]] = {}
|
||||
self.time_points: List[int] = []
|
||||
|
||||
# Style settings
|
||||
self.fig.tight_layout(pad=3.0)
|
||||
|
||||
def update(self, network: PathNetwork, water_level: float) -> None:
|
||||
"""
|
||||
Update the visualization with current network state.
|
||||
|
||||
Args:
|
||||
network: The current network state
|
||||
water_level: Current global water level
|
||||
"""
|
||||
self._clear_axes()
|
||||
|
||||
# Get current network state
|
||||
graph, heights = network.get_network_state()
|
||||
|
||||
# Update histories
|
||||
self.water_level_history.append(water_level)
|
||||
self.time_points.append(len(self.water_level_history))
|
||||
|
||||
for node_id, height in heights.items():
|
||||
if node_id not in self.height_histories:
|
||||
self.height_histories[node_id] = []
|
||||
self.height_histories[node_id].append(height)
|
||||
|
||||
# Draw network topology
|
||||
self._draw_network(graph, heights)
|
||||
|
||||
# Draw current heights
|
||||
self._draw_heights(heights, water_level)
|
||||
|
||||
# Draw history
|
||||
self._draw_history()
|
||||
|
||||
# Update display
|
||||
try:
|
||||
plt.draw()
|
||||
plt.pause(0.01)
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not update display in real-time: {e}")
|
||||
|
||||
def _clear_axes(self) -> None:
|
||||
"""Clear all axes for redrawing."""
|
||||
for ax in [self.network_ax, self.heights_ax, self.history_ax]:
|
||||
ax.clear()
|
||||
|
||||
def _draw_network(self, graph: nx.DiGraph, heights: Dict[int, float]) -> None:
|
||||
"""Draw the network topology with node colors based on heights."""
|
||||
self.network_ax.set_title('Network Topology')
|
||||
|
||||
# Calculate node colors based on heights
|
||||
vmin = min(heights.values())
|
||||
vmax = max(heights.values())
|
||||
node_colors = [heights[node] for node in graph.nodes()]
|
||||
|
||||
# Calculate edge weights for width
|
||||
edge_weights = [
|
||||
graph[u][v]['weight'] * 2 for u, v in graph.edges()
|
||||
]
|
||||
|
||||
# Draw the network
|
||||
pos = nx.spring_layout(graph, seed=42) # Fixed seed for consistency
|
||||
nx.draw_networkx_nodes(
|
||||
graph,
|
||||
pos,
|
||||
node_color=node_colors,
|
||||
node_size=500,
|
||||
cmap='coolwarm',
|
||||
vmin=vmin,
|
||||
vmax=vmax,
|
||||
ax=self.network_ax
|
||||
)
|
||||
nx.draw_networkx_edges(
|
||||
graph,
|
||||
pos,
|
||||
edge_color='gray',
|
||||
width=edge_weights,
|
||||
alpha=0.6,
|
||||
ax=self.network_ax
|
||||
)
|
||||
nx.draw_networkx_labels(
|
||||
graph,
|
||||
pos,
|
||||
{node: str(node) for node in graph.nodes()},
|
||||
ax=self.network_ax
|
||||
)
|
||||
|
||||
# Add colorbar
|
||||
sm = plt.cm.ScalarMappable(
|
||||
cmap='coolwarm',
|
||||
norm=plt.Normalize(vmin=vmin, vmax=vmax)
|
||||
)
|
||||
plt.colorbar(sm, ax=self.network_ax, label='Height')
|
||||
|
||||
def _draw_heights(
|
||||
self,
|
||||
heights: Dict[int, float],
|
||||
water_level: float
|
||||
) -> None:
|
||||
"""Draw current agent heights and water level."""
|
||||
self.heights_ax.set_title('Current Heights')
|
||||
|
||||
# Plot agent heights
|
||||
nodes = list(heights.keys())
|
||||
height_values = [heights[node] for node in nodes]
|
||||
|
||||
# Create bar plot with custom colors based on height
|
||||
colors = plt.cm.coolwarm(
|
||||
plt.Normalize()(height_values)
|
||||
)
|
||||
self.heights_ax.bar(
|
||||
nodes,
|
||||
height_values,
|
||||
alpha=0.6,
|
||||
color=colors
|
||||
)
|
||||
|
||||
# Plot water level
|
||||
self.heights_ax.axhline(
|
||||
y=water_level,
|
||||
color='r',
|
||||
linestyle='--',
|
||||
label='Water Level'
|
||||
)
|
||||
|
||||
self.heights_ax.set_xlabel('Agent ID')
|
||||
self.heights_ax.set_ylabel('Height')
|
||||
self.heights_ax.legend()
|
||||
|
||||
# Set y-limits with some padding
|
||||
ymin = min(min(height_values), water_level)
|
||||
ymax = max(max(height_values), water_level)
|
||||
padding = (ymax - ymin) * 0.1
|
||||
self.heights_ax.set_ylim(ymin - padding, ymax + padding)
|
||||
|
||||
def _draw_history(self) -> None:
|
||||
"""Draw the history of water level and agent heights."""
|
||||
self.history_ax.set_title('Height History')
|
||||
|
||||
# Create color palette for agents
|
||||
num_agents = len(self.height_histories)
|
||||
colors = plt.cm.viridis(np.linspace(0, 1, num_agents))
|
||||
|
||||
# Plot agent height histories
|
||||
for (node_id, history), color in zip(
|
||||
self.height_histories.items(), colors
|
||||
):
|
||||
self.history_ax.plot(
|
||||
self.time_points[-len(history):],
|
||||
history,
|
||||
alpha=0.6,
|
||||
label=f'Agent {node_id}',
|
||||
color=color
|
||||
)
|
||||
|
||||
# Plot water level history
|
||||
self.history_ax.plot(
|
||||
self.time_points,
|
||||
self.water_level_history,
|
||||
'r--',
|
||||
label='Water Level',
|
||||
linewidth=2,
|
||||
alpha=0.8
|
||||
)
|
||||
|
||||
self.history_ax.set_xlabel('Time Step')
|
||||
self.history_ax.set_ylabel('Height')
|
||||
|
||||
# Adjust legend
|
||||
self.history_ax.legend(
|
||||
bbox_to_anchor=(1.05, 1),
|
||||
loc='upper left',
|
||||
borderaxespad=0.,
|
||||
ncol=2
|
||||
)
|
||||
|
||||
def save(self, filename: str) -> None:
|
||||
"""Save the current figure to a file."""
|
||||
try:
|
||||
# Adjust layout before saving
|
||||
self.fig.tight_layout()
|
||||
self.fig.savefig(
|
||||
filename,
|
||||
bbox_inches='tight',
|
||||
dpi=300,
|
||||
facecolor='white',
|
||||
edgecolor='none'
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not save figure to {filename}: {e}")
|
||||
|
||||
def close(self) -> None:
|
||||
"""Close the figure."""
|
||||
plt.close(self.fig)
|
||||
19
Things/Path_Network/requirements.txt
Обычный файл
19
Things/Path_Network/requirements.txt
Обычный файл
@ -0,0 +1,19 @@
|
||||
numpy>=1.21.0
|
||||
networkx>=2.6.0
|
||||
scipy>=1.7.0
|
||||
matplotlib>=3.4.0
|
||||
torch>=1.9.0
|
||||
pandas>=1.3.0
|
||||
seaborn>=0.11.0
|
||||
pytest>=6.2.0
|
||||
black>=21.5b2
|
||||
mypy>=0.910
|
||||
pylint>=2.8.0
|
||||
pyyaml>=5.4.1
|
||||
plotly>=5.3.0
|
||||
imageio>=2.9.0
|
||||
tqdm>=4.62.0
|
||||
scikit-learn>=0.24.0
|
||||
ipywidgets>=7.6.0
|
||||
moviepy>=1.0.3
|
||||
mayavi>=4.7.0
|
||||
166
Things/Path_Network/run_simulation.sh
Исполняемый файл
166
Things/Path_Network/run_simulation.sh
Исполняемый файл
@ -0,0 +1,166 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
# Function to check if a command exists
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Function to setup Python virtual environment
|
||||
setup_venv() {
|
||||
echo "Setting up Python virtual environment..."
|
||||
|
||||
# Check if python3-venv is installed
|
||||
if command_exists apt-get; then
|
||||
if ! dpkg -l | grep -q python3-venv; then
|
||||
echo "Installing python3-venv..."
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y python3-venv
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create and activate virtual environment
|
||||
if [ ! -d "venv" ]; then
|
||||
python3 -m venv venv
|
||||
fi
|
||||
source venv/bin/activate
|
||||
|
||||
# Upgrade pip
|
||||
python3 -m pip install --upgrade pip
|
||||
}
|
||||
|
||||
# Function to install system dependencies
|
||||
install_system_deps() {
|
||||
echo "Checking system dependencies..."
|
||||
|
||||
if command_exists apt-get; then
|
||||
echo "Debian/Ubuntu system detected"
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
python3-tk \
|
||||
python3-qt5 \
|
||||
libxcb-cursor0 \
|
||||
python3-dev \
|
||||
build-essential \
|
||||
ffmpeg \
|
||||
python3-vtk7 \
|
||||
libvtk7-dev \
|
||||
mayavi2 \
|
||||
python3-mayavi \
|
||||
imagemagick
|
||||
elif command_exists dnf; then
|
||||
echo "Fedora system detected"
|
||||
sudo dnf install -y \
|
||||
python3-tkinter \
|
||||
python3-qt5 \
|
||||
xcb-util-cursor \
|
||||
python3-devel \
|
||||
gcc \
|
||||
ffmpeg \
|
||||
vtk \
|
||||
vtk-devel \
|
||||
mayavi \
|
||||
ImageMagick
|
||||
elif command_exists pacman; then
|
||||
echo "Arch system detected"
|
||||
sudo pacman -S --noconfirm \
|
||||
python-tk \
|
||||
qt5-base \
|
||||
xcb-util-cursor \
|
||||
python-dev \
|
||||
base-devel \
|
||||
ffmpeg \
|
||||
vtk \
|
||||
mayavi \
|
||||
imagemagick
|
||||
else
|
||||
echo "Warning: Unknown package manager. Please install dependencies manually if needed."
|
||||
fi
|
||||
|
||||
# Configure ImageMagick to allow PDF operations if needed
|
||||
if command_exists convert; then
|
||||
sudo sed -i 's/rights="none" pattern="PDF"/rights="read|write" pattern="PDF"/' /etc/ImageMagick-6/policy.xml 2>/dev/null || true
|
||||
sudo sed -i 's/rights="none" pattern="PDF"/rights="read|write" pattern="PDF"/' /etc/ImageMagick-7/policy.xml 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to install Python dependencies
|
||||
install_python_deps() {
|
||||
echo "Installing Python dependencies..."
|
||||
|
||||
# First install numpy and other core dependencies
|
||||
pip install numpy wheel setuptools
|
||||
|
||||
# Install VTK separately if needed
|
||||
if ! python3 -c "import vtk" 2>/dev/null; then
|
||||
pip install vtk
|
||||
fi
|
||||
|
||||
# Then install other dependencies
|
||||
pip install -r requirements.txt
|
||||
}
|
||||
|
||||
# Function to check installation
|
||||
check_installation() {
|
||||
echo "Checking installation..."
|
||||
|
||||
# Try importing required packages
|
||||
python3 -c "
|
||||
import numpy
|
||||
import torch
|
||||
import matplotlib
|
||||
import networkx
|
||||
import seaborn
|
||||
import plotly
|
||||
import imageio
|
||||
import vtk
|
||||
import mayavi.mlab
|
||||
print('All required packages are installed correctly!')
|
||||
"
|
||||
}
|
||||
|
||||
# Function to check output directory
|
||||
check_output_dir() {
|
||||
echo "Checking output directory..."
|
||||
if [ ! -d "output" ]; then
|
||||
mkdir output
|
||||
fi
|
||||
|
||||
# Test write permissions
|
||||
if ! touch output/.test 2>/dev/null; then
|
||||
echo "Error: Cannot write to output directory"
|
||||
exit 1
|
||||
fi
|
||||
rm output/.test
|
||||
}
|
||||
|
||||
# Function to run the simulation
|
||||
run_simulation() {
|
||||
echo "Running simulation..."
|
||||
python example.py
|
||||
}
|
||||
|
||||
# Main execution
|
||||
echo "=== Path Network Simulation Setup ==="
|
||||
|
||||
# Setup virtual environment
|
||||
setup_venv
|
||||
|
||||
# Install dependencies
|
||||
install_system_deps
|
||||
install_python_deps
|
||||
|
||||
# Check installation
|
||||
check_installation
|
||||
|
||||
# Check output directory
|
||||
check_output_dir
|
||||
|
||||
# Run simulation
|
||||
echo "=== Starting Simulation ==="
|
||||
run_simulation
|
||||
|
||||
echo "=== Simulation Complete ==="
|
||||
echo "Check the 'output' directory for results and visualizations."
|
||||
68
ant_colony/agents/nestmate.py
Обычный файл
68
ant_colony/agents/nestmate.py
Обычный файл
@ -0,0 +1,68 @@
|
||||
"""
|
||||
Nestmate agent implementation using active inference.
|
||||
"""
|
||||
|
||||
from enum import Enum
|
||||
import numpy as np
|
||||
from typing import Dict, Optional, List
|
||||
from dataclasses import dataclass, field
|
||||
from ant_colony.environment.world import Position, Resource
|
||||
|
||||
class TaskType(Enum):
|
||||
"""Types of tasks an ant can perform."""
|
||||
FORAGING = 'foraging'
|
||||
MAINTENANCE = 'maintenance'
|
||||
NURSING = 'nursing'
|
||||
DEFENSE = 'defense'
|
||||
EXPLORATION = 'exploration'
|
||||
|
||||
@dataclass
|
||||
class Belief:
|
||||
"""Represents an agent's beliefs about the world state."""
|
||||
food_location: Optional[Position] = None
|
||||
nest_location: Optional[Position] = None
|
||||
danger_level: float = 0.0
|
||||
energy_level: float = 1.0
|
||||
task_urgency: Dict[TaskType, float] = field(default_factory=lambda: {task: 0.0 for task in TaskType})
|
||||
|
||||
class Nestmate:
|
||||
"""
|
||||
Implementation of an ant agent using active inference principles.
|
||||
"""
|
||||
|
||||
def __init__(self, config: dict):
|
||||
"""Initialize the agent."""
|
||||
self.config = config
|
||||
|
||||
# Initialize beliefs first
|
||||
self.beliefs = Belief()
|
||||
|
||||
# Physical state
|
||||
self.position = None
|
||||
self.orientation = 0.0
|
||||
self.speed = 0.0
|
||||
self.energy = config['physical']['energy']['initial']
|
||||
|
||||
# Carrying state
|
||||
self.carrying: Optional[Resource] = None
|
||||
|
||||
# Task state
|
||||
self.current_task = TaskType.EXPLORATION
|
||||
self.task_time = 0.0
|
||||
|
||||
# Sensory state
|
||||
self.observations = {
|
||||
'pheromones': {},
|
||||
'resources': [],
|
||||
'nestmates': [],
|
||||
'terrain': None
|
||||
}
|
||||
|
||||
# Internal model
|
||||
self.preferences = {task: 1.0 for task in TaskType}
|
||||
|
||||
# Learning parameters
|
||||
self.learning_rate = config['behavior'].get('learning_rate', 0.1)
|
||||
self.exploration_rate = config['behavior'].get('exploration_rate', 0.2)
|
||||
|
||||
# ... existing code ...
|
||||
18
ant_colony/simulation.py
Обычный файл
18
ant_colony/simulation.py
Обычный файл
@ -0,0 +1,18 @@
|
||||
"""
|
||||
Main simulation coordinator for ant colony simulation.
|
||||
"""
|
||||
|
||||
import yaml
|
||||
import numpy as np
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
import matplotlib
|
||||
matplotlib.use('Agg') # Use non-GUI backend
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from ant_colony.environment import World
|
||||
from ant_colony.colony import Colony
|
||||
from ant_colony.visualization import ColonyVisualizer
|
||||
from ant_colony.utils.data_collection import DataCollector
|
||||
|
||||
# ... existing code ...
|
||||
@ -16,16 +16,16 @@ pomegranate>=0.14.0
|
||||
matplotlib>=3.4.0
|
||||
seaborn>=0.11.0
|
||||
networkx>=2.6.0
|
||||
plotly>=5.1.0
|
||||
plotly>=5.3.0
|
||||
|
||||
# Data Processing
|
||||
pyyaml>=5.4.0
|
||||
pyyaml>=5.4.1
|
||||
jinja2>=3.0.0
|
||||
markdown>=3.3.0
|
||||
|
||||
# Testing and Development
|
||||
pytest>=6.2.0
|
||||
black>=21.6b0
|
||||
black>=21.5b2
|
||||
flake8>=3.9.0
|
||||
mypy>=0.910
|
||||
|
||||
@ -34,7 +34,7 @@ sphinx>=4.0.0
|
||||
sphinx-rtd-theme>=0.5.0
|
||||
|
||||
# Utilities
|
||||
tqdm>=4.61.0
|
||||
tqdm>=4.62.0
|
||||
click>=8.0.0
|
||||
python-dotenv>=0.19.0
|
||||
|
||||
@ -44,4 +44,8 @@ hyperopt>=0.2.5
|
||||
|
||||
# Monitoring and Logging
|
||||
wandb>=0.12.0
|
||||
mlflow>=1.19.0
|
||||
mlflow>=1.19.0
|
||||
|
||||
# Additional dependencies
|
||||
pylint>=2.8.0
|
||||
imageio>=2.9.0
|
||||
Загрузка…
x
Ссылка в новой задаче
Block a user