An interactive web simulator for swarm behavior built with Elixir and the Phoenix framework. This project allows you to visualize and experiment with swarm intelligence algorithms in real time.
Elixir Swarm Simulator is a modern web application that simulates the collective behavior of autonomous agents (such as bee swarms, bird flocks, or fish schools). Users can:
- Create custom simulations with different parameters
- Visualize in real time the movement and behavior of agents
- Experiment with algorithms for artificial intelligence and emergent behavior
- Elixir 1.15+: Functional language with native concurrency support
- Phoenix 1.8.1: Modern and scalable web framework
- Phoenix Channels / WebSockets: Real-time position broadcasting
- Ecto + SQLite3: Data persistence
- Tailwind CSS 4: Responsive and modern design
- Heroicons: Icon library
Before getting started, make sure you have installed:
- Elixir 1.15 or higher
- Erlang/OTP 26+ (included with Elixir)
- Node.js 18+ (for compiling assets)
- SQLite3 (included in most systems)
- Git
To verify your installation:
elixir --version
erl -version
node --versiongit clone <repository-url>
cd Elixir-Swarm-SimulatorRun the setup command that automatically configures the project:
mix setupThis command performs:
- Downloads and installs all dependencies with
mix deps.get - Sets up the database with
mix ecto.setup - Compiles the assets (CSS, JS) with
mix assets.build
mix phx.serverOr if you prefer using IEx (Elixir interactive shell):
iex -S mix phx.serverVisit http://localhost:4000 once the server is started.
├── lib/
│ ├── simulator/ # Core domain logic
│ │ ├── point_agent.ex # Agent process (position + algorithm)
│ │ ├── simulation_executor.ex # GenServer managing one execution
│ │ ├── simulation_manager.ex # GenServer tracking all executions
│ │ ├── simulations.ex # Ecto CRUD context
│ │ ├── simulations/
│ │ │ └── simulation.ex # Simulation schema (type, algorithm, swarm, map)
│ │ ├── algorithms/
│ │ │ ├── algorithm.ex # Algorithm behaviour
│ │ │ ├── algorithms.ex # Algorithm registry
│ │ │ ├── helpers/ # Cross-algorithm utilities
│ │ │ │ ├── geometry.ex # Geometric utilities (collision, distance, grids)
│ │ │ │ └── knowledge_store.ex # Shared knowledge (decay, merge, anti-echo)
│ │ │ └── impl/ # Algorithm implementations
│ │ │ ├── random_walk.ex # Random walk with collision avoidance
│ │ │ ├── static.ex # No movement
│ │ │ ├── aim_random_walk.ex # Target-directed walk
│ │ │ ├── heatmap_walk.ex # Heat-grid exploration with shared knowledge
│ │ │ ├── ant_colony.ex # Ant Colony Optimization with pheromone grid
│ │ │ ├── particle_swarm.ex # Particle Swarm Optimization (PSO)
│ │ │ └── grey_wolf.ex # Grey Wolf Optimizer (GWO)
│ │ ├── environment/ # Physical world simulation
│ │ │ ├── position_tracker.ex # Stores agent positions
│ │ │ ├── proximity_detector.ex # Detects neighbor proximity
│ │ │ └── communication_relay.ex # Routes data between neighbors
│ │ └── maps/
│ │ ├── map.ex # Map behaviour
│ │ ├── maps.ex # Map registry
│ │ ├── map_params.ex # MapParams struct (width, height, structures, spawn_point)
│ │ └── impl/ # Map implementations
│ │ ├── clean_map.ex # 500×500 empty map
│ │ ├── clean_city.ex # 500×500 city map with 8 blocks
│ │ ├── big_clean_map.ex # 1000×500 empty map
│ │ └── square_obstacle_map.ex # 1000×500 map with centered obstacle
│ └── simulator_web/ # Web layer
│ ├── router.ex # HTTP routes
│ ├── channels/
│ │ ├── user_socket.ex # WebSocket endpoint
│ │ └── simulation_channel.ex # Real-time position broadcasting
│ ├── controllers/
│ │ ├── simulation_controller.ex # CRUD at /simulations
│ │ └── execution_controller.ex # Execution view at /execution/:id
│ └── components/ # Reusable UI components
├── assets/
│ ├── css/ # Tailwind CSS styles
│ └── js/ # JavaScript (Canvas, WebSocket client)
├── priv/
│ └── repo/ # Database migrations
├── test/ # Test suite
├── config/ # Project configuration
└── mix.exs # Dependencies and project config
The simulation system is built on Erlang/OTP processes communicating through GenServers and Phoenix Channels. Below is the complete data flow:
The user creates a simulation record through the web interface at /simulations. Each simulation has:
| Field | Description |
|---|---|
type |
A name/label for the simulation |
algorithm |
Movement algorithm key (e.g. "random_walk") |
swarm |
Number of agents to spawn |
map |
Map key (e.g. "clean", "city", "big_clean") |
These records are persisted in SQLite via Ecto.
When the user navigates to /execution/:id:
Browser Server
│ │
├─ GET /execution/:id ────►│ ExecutionController loads simulation + map params
│◄──── HTML page ──────────│ (renders canvas with correct dimensions)
│ │
├─ WebSocket connect ─────►│ UserSocket accepts connection
├─ join "simulation:<id>" ►│ SimulationChannel.join/3
│ │
On channel join, the following OTP process tree is created:
SimulationManager (singleton GenServer)
│
├── tracks: %{simulation_id => executor_pid}
│
└── SimulationExecutor (GenServer, one per simulation)
│
├── PositionTracker (stores positions broadcast by agents)
├── ProximityDetector (detects neighbor proximity)
├── CommunicationRelay (routes data between neighbors)
├── PointAgent 1 (GenServer + tick loop)
├── PointAgent 2 (GenServer + tick loop)
├── ...
└── PointAgent N (GenServer + tick loop)
- SimulationManager — Prevents duplicate executions per simulation ID. Delegates
start_executionandget_positionscalls to the appropriate executor. - SimulationExecutor — Spawns N
PointAgentprocesses on init. Registered undersimulation.typeas its process name. - PointAgent — Each agent is a GenServer holding
%{id, position, algorithm, map, neighbors, tracker, relay}. Every@update_intervalms it callsalgorithm.compute_step(state)to compute the next position and updated state, then broadcasts position and shared data.
After the execution starts, SimulationChannel enters a tick loop:
SimulationChannel SimulationManager SimulationExecutor PointAgents
│ │ │ │
├── :tick (every @tick_interval) │ │ │
├── {:get_positions, sim} ──────►│ │ │
│ ├── get_positions(pid) ───►│ │
│ │ ├── get_position(pid) ─►│
│ │ │◄── %{x, y} ──────────│
│ │◄── %{positions: [...]} ──│ │
│◄── %{positions: [...]} ────────│ │ │
│ │
├── push("positions", data) ──► Browser (Canvas renders agents) │
│ │
│ Meanwhile, each PointAgent ticks independently: │
│ ┌── :tick ─────────────│
│ │ algorithm │
│ │ .compute_step() │
│ │ updates position │
│ └──────────────────────►│
Algorithms implement the Simulator.Algorithm behaviour:
@callback compute_step(map()) :: {map(), map()}The callback receives the full agent state (%{position: %{x, y}, map: %MapParams{}}) and must return {new_position, updated_state}. Available algorithms are registered in Simulator.Algorithms (@available_algorithms map). Unknown names fall back to RandomWalk.
Maps implement the Simulator.Map behaviour:
@callback get_parameters(map()) :: MapParams.t()Each map returns a %MapParams{width, height, structures} struct that defines spatial bounds. Algorithms use these bounds to constrain agent movement (e.g. RandomWalk clamps positions to 0..map.width and 0..map.height).
Run all tests:
mix testRun tests for a specific file:
mix test test/simulator/point_agent_test.exsRun only previously failed tests:
mix test --failed| Command | Description |
|---|---|
mix setup |
Initial installation and setup |
mix phx.server |
Start the development server |
mix test |
Run the test suite |
mix format |
Automatically format code |
mix precommit |
Run linters and tests (use before committing) |
mix ecto.setup |
Set up the database |
mix ecto.reset |
Reset the database |
Configuration files are located in config/:
- config.exs: Global configuration
- dev.exs: Development configuration
- prod.exs: Production configuration
- test.exs: Test configuration
- runtime.exs: Runtime configuration
See docs/algorithms/ALGORITHMS.md for a guide on implementing new movement algorithms.
See docs/maps/MAPS.md for a guide on implementing new simulation maps.
See docs/ProgramingGuide.md for development guidelines, code conventions, and architecture standards.
Contributions are welcome. Please:
- Fork the project
- Create a branch for your feature (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed. See the LICENSE file for details.
Project developed as part of research in swarm intelligence and multi-agent simulation.
Issues or Questions?
If you find any issues or have questions, please open an issue in the repository.