Skip to content

Commit

Permalink
fine tuning performance
Browse files Browse the repository at this point in the history
  • Loading branch information
quaquel committed Jan 3, 2025
1 parent 4b3bb91 commit 8f04312
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 34 deletions.
16 changes: 4 additions & 12 deletions mesa/examples/basic/boid_flockers/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,31 +59,23 @@ def __init__(
self.match_factor = match
self.neighbors = []

@property
def pos(self):
return self.position

@pos.setter
def pos(self, value):
pass

def step(self):
"""Get the Boid's neighbors, compute the new vector, and move accordingly."""
neighbors, distances = self.get_neighbors_in_radius(
radius=self.vision, include_distance=True
)
self.neighbors = neighbors.tolist()
self.neighbors = neighbors

# If no neighbors, maintain current direction
if neighbors.size == 0:
self.position += self.direction * self.speed
return

delta = self.space.calculate_difference_vector(
self.position, [n._mesa_index for n in neighbors]
self.position, agents=neighbors
)

cohere = np.sum(delta, axis=0) * self.cohere_factor
cohere_vector = np.sum(delta, axis=0) * self.cohere_factor
separation_vector = (
-1
* np.sum(delta[distances < self.separation], axis=0)
Expand All @@ -95,7 +87,7 @@ def step(self):
)

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

# Normalize direction vector
self.direction /= np.linalg.norm(self.direction)
Expand Down
76 changes: 54 additions & 22 deletions mesa/experimental/continuous_space/continuous_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,41 @@

from mesa.agent import Agent, AgentSet

from line_profiler_pycharm import profile

class ContinuousSpace:
"""Continuous space where each agent can have an arbitrary position."""

@property
def x_min(self):
# compatability with solara_viz
return self.dimensions[0,0]

@property
def x_max(self):
# compatability with solara_viz
return self.dimensions[0,1]

@property
def y_min(self):
# compatability with solara_viz
return self.dimensions[1,0]

@property
def y_max(self):
# compatability with solara_viz
return self.dimensions[1,1]

@property
def width(self):
# compatability with solara_viz
return self.size[0]

@property
def height(self):
# compatability with solara_viz
return self.size[1]

def __init__(
self,
dimensions: Sequence[Sequence[float]],
Expand Down Expand Up @@ -53,10 +84,10 @@ def agents(self) -> AgentSet:
"""Return an AgentSet with the agents in the space."""
return AgentSet(self._agents[self._positions_in_use], random=self.random)

@property
def agent_positions(self) -> np.ndarray:
"""Return the positions of the agents in the space."""
return self._agent_positions[self._positions_in_use]
# @property
# def agent_positions(self) -> np.ndarray:
# """Return the positions of the agents in the space."""
# return self._agent_positions[self._positions_in_use]

def _get_index_for_agent(self, agent: Agent) -> int:
"""Helper method to get the index for the agent.
Expand Down Expand Up @@ -95,6 +126,9 @@ def _get_index_for_agent(self, agent: Agent) -> int:
self._agent_to_index[agent] = index
self._index_to_agent[index] = agent

self.agent_positions = self._agent_positions[self._positions_in_use]
self.active_agents = self._agents[self._positions_in_use]

return index

def _remove_agent(self, agent: Agent) -> None:
Expand All @@ -106,40 +140,38 @@ def _remove_agent(self, agent: Agent) -> None:
self._agents[index] = None

def calculate_difference_vector(
self, point: np.ndarray, indices=None
self, point: np.ndarray, agents=None
) -> np.ndarray:
"""Calculate the difference vector between the point and all agents"""
"""Calculate the difference vector between the point and all agents."""
point = np.asanyarray(point)
positions = (
self._agent_positions[indices]
if indices is not None
else self.agent_positions
)
positions = self.agent_positions if agents is None else self._agent_positions[[self._agent_to_index[a] for a in agents]]

delta = positions - point[np.newaxis, :]

if self.torus:
inverse_delta = delta - np.sign(delta) * self.size

# we need to use the lowest absolute value from delta and inverse delta
logical = np.abs(delta) < np.abs(inverse_delta)

out = np.zeros(delta.shape)
out[logical] = delta[logical]
out[~logical] = inverse_delta[~logical]

delta = out

return delta

def calculate_distances(self, point, indices=None) -> tuple[np.ndarray, np.ndarray]:
def calculate_distances(self, point, agents=None) -> tuple[np.ndarray, np.ndarray]:
"""Calculate the distance between the point and all agents."""
point = np.asanyarray(point)
positions = (
self._agent_positions[indices]
if indices is not None
else self.agent_positions
)
agents = (
self._agents[indices]
if indices is not None
else self._agents[self._positions_in_use]
)

if agents is None:
positions = self.agent_positions
agents = self.active_agents
else:
positions = self._agent_positions[[self._agent_to_index[a] for a in agents]]
agents = np.asarray(agents)

if self.torus:
delta = point[np.newaxis, :] - positions
Expand Down
10 changes: 10 additions & 0 deletions mesa/experimental/continuous_space/continuous_space_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ def position(self, value: np.ndarray) -> None:

self.space._agent_positions[self._mesa_index] = value

@property
def pos(self):
# just here for compatability with solara_viz.
return self.position

@pos.setter
def pos(self, value):
# just here for compatability solara_viz.
pass

def __init__(self, space: ContinuousSpace, model):
"""Initialize a continuous space agent.
Expand Down

0 comments on commit 8f04312

Please sign in to comment.