Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reimplementation of Continuous Space #2584

Merged
merged 90 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from 83 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
2e47f56
initial draft
quaquel Dec 30, 2024
6ef0b13
Update continuous_space.py
quaquel Dec 30, 2024
a8bd211
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 30, 2024
797e681
ruff
quaquel Dec 30, 2024
2782736
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 30, 2024
d0b05ec
Update continuous_space.py
quaquel Dec 30, 2024
611af52
first tests
quaquel Dec 31, 2024
85c0bc2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 31, 2024
2e31c49
docstring for agent
quaquel Dec 31, 2024
322a50e
Update continuous_space_agents.py
quaquel Dec 31, 2024
aee0ff8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 31, 2024
1e15913
Merge branch 'main' into continuous_space
quaquel Jan 1, 2025
85665c5
add scipy as dependency
quaquel Jan 1, 2025
cdbeb2a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 1, 2025
04f66f9
Update continuous_space_agents.py
quaquel Jan 1, 2025
a2d113e
ensure aligntment between agents and distances
quaquel Jan 1, 2025
76f3ccd
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 1, 2025
d8b62b0
Update continuous_space.py
quaquel Jan 1, 2025
c5ad8bb
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 1, 2025
5695c3b
typing fix
quaquel Jan 1, 2025
3a985d8
tests for distance calculations
quaquel Jan 1, 2025
94963cd
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 1, 2025
acd0ef0
ruff related fixes
quaquel Jan 1, 2025
5b676d0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 1, 2025
c8119ed
wip
quaquel Jan 2, 2025
b7c3914
wip
quaquel Jan 2, 2025
a08e29b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 2, 2025
238d105
Update configurations.py
quaquel Jan 2, 2025
07e5da4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 2, 2025
1b5b082
updates
quaquel Jan 2, 2025
c46c890
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 2, 2025
357bc75
ongoing
quaquel Jan 2, 2025
cc4a095
Update continuous_space.py
quaquel Jan 2, 2025
f549eee
revert mpl changes
quaquel Jan 3, 2025
4b3bb91
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 3, 2025
8f04312
fine tuning performance
quaquel Jan 3, 2025
416455a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 3, 2025
daa9b47
fine tuning
quaquel Jan 3, 2025
137162b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 3, 2025
5ce3d55
Delete profile.svg
quaquel Jan 3, 2025
96fc316
ruff related
quaquel Jan 3, 2025
d6326fd
Update continuous_space.py
quaquel Jan 3, 2025
8d57c62
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 3, 2025
afe44c3
updates
quaquel Jan 3, 2025
b7bdd82
make new continous spaces work with existing space drawing
quaquel Jan 3, 2025
0db0a6f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 3, 2025
625069c
ruff related
quaquel Jan 3, 2025
b56a970
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 3, 2025
eb5abd6
Update continuous_space.py
quaquel Jan 3, 2025
3e8e535
Merge branch 'main' into continuous_space
quaquel Jan 4, 2025
53ffa30
Update continuous_space.py
quaquel Jan 3, 2025
99bb9de
profiling
quaquel Jan 3, 2025
a1cb4cb
onging
quaquel Jan 4, 2025
f7bdb8b
cleanup
quaquel Jan 4, 2025
e2ae60e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 4, 2025
45d5744
ruff
quaquel Jan 4, 2025
cf94c46
cleaning
quaquel Jan 4, 2025
c5a53c6
fine tuning
quaquel Jan 5, 2025
a64ac38
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 5, 2025
595cef4
Merge remote-tracking branch 'upstream/main' into continuous_space
quaquel Jan 5, 2025
6303863
tweak
quaquel Jan 5, 2025
2b8ed2b
substantial update
quaquel Jan 5, 2025
4e9a39b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 5, 2025
102492a
switch active agents to list
quaquel Jan 5, 2025
037bc3b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 5, 2025
3a4fa51
an additional test
quaquel Jan 5, 2025
06a8c34
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 5, 2025
73b8777
Update continuous_space_agents.py
quaquel Jan 5, 2025
4f3073b
Merge remote-tracking branch 'upstream/main' into continuous_space
quaquel Jan 6, 2025
a23b982
additional test
quaquel Jan 6, 2025
b625e23
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 6, 2025
ce0c311
additional tests
quaquel Jan 6, 2025
21c01ad
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 6, 2025
c7df9be
Update test_continuous_space.py
quaquel Jan 6, 2025
c0782ab
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 6, 2025
6677e03
Merge branch 'main' into continuous_space
quaquel Jan 6, 2025
6f0a46a
merge related fixes
quaquel Jan 6, 2025
36bf20a
Merge branch 'main' into continuous_space
quaquel Jan 7, 2025
7780b3a
typing and tests
quaquel Jan 8, 2025
c2aa0f2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 8, 2025
528aab5
more tests
quaquel Jan 8, 2025
e98eadf
Delete for_development.py
quaquel Jan 8, 2025
983fbb9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 8, 2025
c4de8de
Update mesa/examples/basic/boid_flockers/model.py
quaquel Jan 8, 2025
23159bf
Update mesa/examples/basic/boid_flockers/model.py
quaquel Jan 8, 2025
0706667
expanded docstring and comments
quaquel Jan 8, 2025
0cbbbb5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 8, 2025
4187786
Update continuous_space.py
quaquel Jan 8, 2025
1b8937f
final tweaks
quaquel Jan 10, 2025
897d62e
Update continuous_space.py
quaquel Jan 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions benchmarks/configurations.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,19 @@
"seeds": 25,
"replications": 3,
"steps": 20,
"parameters": {"population": 200, "width": 100, "height": 100, "vision": 5},
"parameters": {
"population_size": 200,
"width": 100,
"height": 100,
"vision": 5,
},
},
"large": {
"seeds": 10,
"replications": 3,
"steps": 10,
"parameters": {
"population": 400,
"population_size": 400,
"width": 150,
"height": 150,
"vision": 15,
Expand Down
63 changes: 25 additions & 38 deletions mesa/examples/basic/boid_flockers/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

import numpy as np

from mesa import Agent
from mesa.experimental.continuous_space import ContinuousSpaceAgent
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's you long term vision on the different Agent types in Mesa? Will each space need their own Agent class?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a viable alternative at the moment other than having a set of different agent subclasses designed to work with different spaces.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I am understanding correctly, related #2585 (which is an awesome discussion BTW) then if a user has say someone in continouspace and part of network, then their agent would use inheritance to get those particular functions?



class Boid(Agent):
class Boid(ContinuousSpaceAgent):
"""A Boid-style flocker agent.

The agent follows three behaviors to flock:
Expand All @@ -26,10 +26,12 @@ class Boid(Agent):
def __init__(
self,
model,
speed,
direction,
vision,
separation,
space,
position=(0, 0),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't this supposed to be a sequence/array with (like [0, 0])?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

position in newstyle is np.typing.ArrayLike, so anything castable to np.array works.

The cleaner solution is to make position a positional argument rather than a keyword argument because this avoids the need for a default value. The nice thing of a kwarg, however, is that create_agents becomes a bit more readable.

speed=1,
direction=(1, 1),
vision=1,
separation=1,
cohere=0.03,
separate=0.015,
match=0.05,
Expand All @@ -46,7 +48,8 @@ def __init__(
separate: Relative importance of avoiding close neighbors (default: 0.015)
match: Relative importance of matching neighbors' directions (default: 0.05)
"""
super().__init__(model)
super().__init__(space, model)
self.position = position
self.speed = speed
self.direction = direction
self.vision = vision
Expand All @@ -58,47 +61,31 @@ def __init__(

def step(self):
"""Get the Boid's neighbors, compute the new vector, and move accordingly."""
neighbors = self.model.space.get_neighbors(self.pos, self.vision, True)
neighbors, distances = self.get_neighbors_in_radius(radius=self.vision)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very clean!

self.neighbors = [n for n in neighbors if n is not self]

# If no neighbors, maintain current direction
if not self.neighbors:
new_pos = self.pos + self.direction * self.speed
self.model.space.move_agent(self, new_pos)
if not neighbors:
self.position += self.direction * self.speed
return

# Initialize vectors for the three flocking behaviors
cohere = np.zeros(2) # Cohesion vector
match_vector = np.zeros(2) # Alignment vector
separation_vector = np.zeros(2) # Separation vector
delta = self.space.calculate_difference_vector(self.position, agents=neighbors)

# Calculate the contribution of each neighbor to the three behaviors
for neighbor in self.neighbors:
heading = self.model.space.get_heading(self.pos, neighbor.pos)
distance = self.model.space.get_distance(self.pos, neighbor.pos)

# Cohesion - steer towards the average position of neighbors
cohere += heading

# Separation - avoid getting too close
if distance < self.separation:
separation_vector -= heading

# Alignment - match neighbors' flying direction
match_vector += neighbor.direction

# Weight each behavior by its factor and normalize by number of neighbors
n = len(self.neighbors)
cohere = cohere * self.cohere_factor
separation_vector = separation_vector * self.separate_factor
match_vector = match_vector * self.match_factor
cohere_vector = delta.sum(axis=0) * self.cohere_factor
separation_vector = (
-1 * delta[distances < self.separation].sum(axis=0) * self.separate_factor
)
match_vector = (
np.asarray([n.direction for n in neighbors]).sum(axis=0) * self.match_factor
)

# Update direction based on the three behaviors
self.direction += (cohere + separation_vector + match_vector) / n
self.direction += (cohere_vector + separation_vector + match_vector) / len(
neighbors
)

# Normalize direction vector
self.direction /= np.linalg.norm(self.direction)

# Move boid
new_pos = self.pos + self.direction * self.speed
self.model.space.move_agent(self, new_pos)
self.position += self.direction * self.speed
7 changes: 6 additions & 1 deletion mesa/examples/basic/boid_flockers/app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import os
import sys

sys.path.insert(0, os.path.abspath("../../../.."))

from mesa.examples.basic.boid_flockers.model import BoidFlockers
from mesa.visualization import Slider, SolaraViz, make_space_component

Expand All @@ -17,7 +22,7 @@ def boid_draw(agent):
"value": 42,
"label": "Random Seed",
},
"population": Slider(
"population_size": Slider(
label="Number of boids",
value=100,
min=10,
Expand Down
74 changes: 37 additions & 37 deletions mesa/examples/basic/boid_flockers/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@
Uses numpy arrays to represent vectors.
"""

import os
import sys

sys.path.insert(0, os.path.abspath("../../../.."))


import numpy as np

from mesa import Model
from mesa.examples.basic.boid_flockers.agents import Boid
from mesa.space import ContinuousSpace
from mesa.experimental.continuous_space import ContinuousSpace


class BoidFlockers(Model):
"""Flocker model class. Handles agent creation, placement and scheduling."""

def __init__(
self,
population=100,
population_size=100,
width=100,
height=100,
speed=1,
Expand All @@ -31,7 +37,7 @@
"""Create a new Boids Flocking model.

Args:
population: Number of Boids in the simulation (default: 100)
population_size: Number of Boids in the simulation (default: 100)
width: Width of the space (default: 100)
height: Height of the space (default: 100)
speed: How fast the Boids move (default: 1)
Expand All @@ -44,48 +50,35 @@
"""
super().__init__(seed=seed)

# Model Parameters
self.population = population
self.vision = vision
self.speed = speed
self.separation = separation

# Set up the space
self.space = ContinuousSpace(width, height, torus=True)

# Store flocking weights
self.factors = {"cohere": cohere, "separate": separate, "match": match}
self.space = ContinuousSpace(
[[0, width], [0, height]],
quaquel marked this conversation as resolved.
Show resolved Hide resolved
torus=True,
random=self.random,
n_agents=population_size,
)

# Create and place the Boid agents
self.make_agents()
position = self.rng.random(size=(population_size, 2)) * self.space.size
direction = self.rng.uniform(-1, 1, size=(population_size, 2))
Boid.create_agents(
self,
population_size,
self.space,
position=position,
direction=direction,
cohere=cohere,
separate=separate,
match=match,
speed=speed,
vision=vision,
separation=separation,
)
quaquel marked this conversation as resolved.
Show resolved Hide resolved

# For tracking statistics
self.average_heading = None
self.update_average_heading()

def make_agents(self):
"""Create and place all Boid agents randomly in the space."""
for _ in range(self.population):
# Random position
x = self.random.random() * self.space.x_max
y = self.random.random() * self.space.y_max
pos = np.array((x, y))

# Random initial direction
direction = np.random.random(2) * 2 - 1 # Random vector between -1 and 1
direction /= np.linalg.norm(direction) # Normalize

# Create and place the Boid
boid = Boid(
model=self,
speed=self.speed,
direction=direction,
vision=self.vision,
separation=self.separation,
**self.factors,
)
self.space.place_agent(boid, pos)

def update_average_heading(self):
"""Calculate the average heading (direction) of all Boids."""
if not self.agents:
Expand All @@ -103,3 +96,10 @@
"""
self.agents.shuffle_do("step")
self.update_average_heading()


if __name__ == "__main__":
model = BoidFlockers(population_size=200, width=100, height=100, vision=5, seed=42)

Check warning on line 102 in mesa/examples/basic/boid_flockers/model.py

View check run for this annotation

Codecov / codecov/patch

mesa/examples/basic/boid_flockers/model.py#L102

Added line #L102 was not covered by tests

for _i in range(20):
model.step()

Check warning on line 105 in mesa/examples/basic/boid_flockers/model.py

View check run for this annotation

Codecov / codecov/patch

mesa/examples/basic/boid_flockers/model.py#L105

Added line #L105 was not covered by tests
quaquel marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 2 additions & 2 deletions mesa/experimental/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
- Features graduate from experimental status once their APIs are stabilized
"""

from mesa.experimental import cell_space, devs, mesa_signals
from mesa.experimental import cell_space, continuous_space, devs, mesa_signals

__all__ = ["cell_space", "devs", "mesa_signals"]
__all__ = ["cell_space", "continuous_space", "devs", "mesa_signals"]
8 changes: 8 additions & 0 deletions mesa/experimental/continuous_space/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Continuous space support."""

from mesa.experimental.continuous_space.continuous_space import ContinuousSpace
from mesa.experimental.continuous_space.continuous_space_agents import (
ContinuousSpaceAgent,
)

__all__ = ["ContinuousSpace", "ContinuousSpaceAgent"]
Loading
Loading