Mesa¶
Mesa is a framework for agent-based models in Python.
The phyelds-mesa package runs phyelds programs on the agents of a Mesa model: Mesa
moves the agents, phyelds computes fields on top of them.
pip install phyelds-mesa
It installs a compatible phyelds release and Mesa.
How it works¶
phyelds.mesa.AggregateRuntime is a host that follows the round
protocol, with Mesa agents as devices:
- Devices: each agent is a device, identified by its
unique_id. - Rounds:
run_round(agents)runs the program once on each agent, and returns its results byunique_id. Call it from thestepof the model. - Synchronous rounds: in a round every agent receives what its neighbors sent in the previous round, so the order of the agents does not matter.
- Neighbors: a function of the agent decides who it talks to.
within(radius): the agents closer thanradiusin a continuous space.cell_neighbors: the other agents in the same cell and in its neighborhood, in a grid or a network.- Any function from an agent to agents, for instance to cut the links that cross a wall.
- Sensors: every agent senses
position(its position, or the coordinate of its cell) andtime(the time of the model).sensors=adds more, from a function of the agent. - Outputs: what the program
stores is inruntime.outputs, byunique_id. - Agents that leave: an agent missing from a round is forgotten, with its state and its messages.
Example¶
Agents wander in a square, and each one computes how many radio hops it is from the source:
@aggregate
def hops_to_source():
"""Hops to the source; agents that cannot reach it store that they are cut off."""
hops = distance_to(sense("source"), hops_distance())
store("cut_off", hops == math.inf)
return hops
class Swarm(mesa.Model):
"""Agents wandering in the unit square, with a phyelds field on top."""
def __init__(self, agents: int = 30, radius: float = 0.3, speed: float = 0.02, seed: int = 42):
super().__init__(rng=seed)
self.speed = speed
space = ContinuousSpace([[0, 1], [0, 1]], torus=False, random=self.random, n_agents=agents)
for _ in range(agents):
ContinuousSpaceAgent(space, self).position = self.rng.random(2)
self.source = self.agents[0]
self.runtime = AggregateRuntime(
hops_to_source,
neighbors=within(radius),
sensors=lambda agent: {"source": agent is self.source},
)
self.hops: dict[int, float] = {}
def step(self):
for agent in self.agents:
move = self.rng.uniform(-self.speed, self.speed, 2)
agent.position = np.clip(agent.position + move, 0.0, 1.0)
self.hops = self.runtime.run_round(self.agents) # one round of phyelds per step
The complete example is
docs/examples/mesa_swarm.py.
Notes¶
- Messages are shared, not copied: as in the phyelds simulator, an agent receives the very objects its neighbors sent. Never mutate a value received from a neighbor (see common pitfalls).
- One runtime per program: a runtime keeps the state of its program on each agent.
To run two independent programs, use two runtimes.
reset()forgets everything, for instance between episodes.