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

track unique_id automatically #2260

Merged
merged 34 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d90b0f7
further updates
quaquel Jan 21, 2024
9586490
Update benchmarks/WolfSheep/__init__.py
quaquel Jan 21, 2024
4aaa35d
Merge remote-tracking branch 'upstream/main'
quaquel Feb 21, 2024
d31478c
Merge remote-tracking branch 'upstream/main'
quaquel Apr 22, 2024
6e4c72e
Merge remote-tracking branch 'upstream/main'
quaquel Aug 14, 2024
70fbaf5
Merge remote-tracking branch 'upstream/main'
quaquel Aug 18, 2024
724c8db
Merge remote-tracking branch 'upstream/main'
quaquel Aug 21, 2024
45184a4
Merge remote-tracking branch 'upstream/main'
quaquel Aug 22, 2024
3d75d30
Merge remote-tracking branch 'upstream/main'
quaquel Aug 27, 2024
2759244
Update __init__.py
quaquel Aug 27, 2024
fc8aaea
Merge remote-tracking branch 'upstream/main'
quaquel Aug 28, 2024
1ba465d
Merge remote-tracking branch 'upstream/main'
quaquel Aug 30, 2024
2b5e822
Merge remote-tracking branch 'upstream/main'
quaquel Sep 2, 2024
3847799
Merge remote-tracking branch 'upstream/main'
quaquel Sep 4, 2024
301d80e
Merge remote-tracking branch 'upstream/main'
quaquel Sep 4, 2024
8ef5794
track unique_id automatically
quaquel Aug 30, 2024
8d24591
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 30, 2024
a113e24
remove model.next_id and fix tests
quaquel Aug 31, 2024
3bc29e1
remove model. next_id
quaquel Aug 31, 2024
27d54eb
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 31, 2024
5a3c4ce
remove next_id from benchmarks
quaquel Sep 4, 2024
7e8952d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 4, 2024
5ddf910
remove next_id from devs examples
quaquel Sep 4, 2024
2a762a7
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 4, 2024
d4eeb0d
enforce internal unique_id
quaquel Sep 4, 2024
08b885c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 4, 2024
15a384b
ensure all tests are consistent with internal assignment of unique_id
quaquel Sep 4, 2024
e7ca6de
Update agent.py
quaquel Sep 4, 2024
ffe1a6c
additional test
quaquel Sep 4, 2024
e4b887f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 4, 2024
bdfa094
ruff related fixes
quaquel Sep 4, 2024
ef7add3
Merge remote-tracking branch 'upstream/main' into unique_id
quaquel Sep 4, 2024
32ee2d3
requested modifications
quaquel Sep 4, 2024
d3947ac
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 4, 2024
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
8 changes: 4 additions & 4 deletions benchmarks/BoltzmannWealth/boltzmann_wealth.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ def __init__(self, seed=None, n=100, width=10, height=10):
model_reporters={"Gini": compute_gini}, agent_reporters={"Wealth": "wealth"}
)
# Create agents
for i in range(self.num_agents):
a = MoneyAgent(i, self)
for _ in range(self.num_agents):
a = MoneyAgent(self)
# Add the agent to a random grid cell
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
Expand All @@ -50,8 +50,8 @@ def run_model(self, n):
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""

def __init__(self, unique_id, model):
super().__init__(unique_id, model)
def __init__(self, model):
super().__init__(model)
self.wealth = 1

def move(self):
Expand Down
7 changes: 2 additions & 5 deletions benchmarks/Flocking/flocking.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ class Boid(mesa.Agent):

def __init__(
self,
unique_id,
model,
speed,
direction,
Expand All @@ -41,7 +40,6 @@ def __init__(
Create a new Boid flocker agent.

Args:
unique_id: Unique agent identifier.
speed: Distance to move per step.
direction: numpy vector for the Boid's direction of movement.
vision: Radius to look around for nearby Boids.
Expand All @@ -51,7 +49,7 @@ def __init__(
match: the relative importance of matching neighbors' directions

"""
super().__init__(unique_id, model)
super().__init__(model)
self.speed = speed
self.direction = direction
self.vision = vision
Expand Down Expand Up @@ -131,13 +129,12 @@ def __init__(
"match": match,
}

for i in range(self.population):
for _ in range(self.population):
x = self.random.random() * self.space.x_max
y = self.random.random() * self.space.y_max
pos = np.array((x, y))
direction = np.random.random(2) * 2 - 1
boid = Boid(
unique_id=i,
model=self,
speed=speed,
direction=direction,
Expand Down
9 changes: 3 additions & 6 deletions benchmarks/Schelling/schelling.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ class SchellingAgent(CellAgent):
Schelling segregation agent
"""

def __init__(self, unique_id, model, agent_type, radius, homophily):
def __init__(self, model, agent_type, radius, homophily):
"""
Create a new Schelling agent.
Args:
unique_id: Unique identifier for the agent.
x, y: Agent initial location.
agent_type: Indicator for the agent's type (minority=1, majority=0)
"""
super().__init__(unique_id, model)
super().__init__(model)
self.type = agent_type
self.radius = radius
self.homophily = homophily
Expand Down Expand Up @@ -81,9 +80,7 @@ def __init__(
for cell in self.grid:
if self.random.random() < density:
agent_type = 1 if self.random.random() < self.minority_pc else 0
agent = SchellingAgent(
self.next_id(), self, agent_type, radius, homophily
)
agent = SchellingAgent(self, agent_type, radius, homophily)
agent.move_to(cell)
self.schedule.add(agent)

Expand Down
15 changes: 5 additions & 10 deletions benchmarks/WolfSheep/wolf_sheep.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@


class Animal(CellAgent):
def __init__(self, unique_id, model, energy, p_reproduce, energy_from_food):
super().__init__(unique_id, model)
def __init__(self, model, energy, p_reproduce, energy_from_food):
super().__init__(model)
self.energy = energy
self.p_reproduce = p_reproduce
self.energy_from_food = energy_from_food
Expand All @@ -29,7 +29,6 @@ def random_move(self):
def spawn_offspring(self):
self.energy /= 2
offspring = self.__class__(
self.model.next_id(),
self.model,
self.energy,
self.p_reproduce,
Expand Down Expand Up @@ -107,7 +106,7 @@ def fully_grown(self, value: bool) -> None:
function_args=[self, "fully_grown", True],
)

def __init__(self, unique_id, model, fully_grown, countdown, grass_regrowth_time):
def __init__(self, model, fully_grown, countdown, grass_regrowth_time):
"""
TODO:: fully grown can just be an int --> so one less param (i.e. countdown)

Expand All @@ -119,7 +118,7 @@ def __init__(self, unique_id, model, fully_grown, countdown, grass_regrowth_time
grass_regrowth_time : time to fully regrow grass
countdown : Time for the patch of grass to be fully regrown if fully grown is False
"""
super().__init__(unique_id, model)
super().__init__(model)
self._fully_grown = fully_grown
self.grass_regrowth_time = grass_regrowth_time

Expand Down Expand Up @@ -189,7 +188,6 @@ def __init__(
)
energy = self.random.randrange(2 * sheep_gain_from_food)
sheep = Sheep(
self.next_id(),
self,
energy,
sheep_reproduce,
Expand All @@ -205,7 +203,6 @@ def __init__(
)
energy = self.random.randrange(2 * wolf_gain_from_food)
wolf = Wolf(
self.next_id(),
self,
energy,
wolf_reproduce,
Expand All @@ -221,9 +218,7 @@ def __init__(
countdown = grass_regrowth_time
else:
countdown = self.random.randrange(grass_regrowth_time)
patch = GrassPatch(
self.next_id(), self, fully_grown, countdown, grass_regrowth_time
)
patch = GrassPatch(self, fully_grown, countdown, grass_regrowth_time)
patch.move_to(cell)

def step(self):
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorials/MoneyModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def compute_gini(model):
class MoneyAgent(mesa.Agent):
"""An agent with fixed initial wealth."""

def __init__(self, unique_id, model):
super().__init__(unique_id, model)
def __init__(self, model):
super().__init__(model)
self.wealth = 1

def move(self):
Expand Down
42 changes: 36 additions & 6 deletions mesa/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import contextlib
import copy
import functools
import itertools
import operator
import warnings
import weakref
Expand All @@ -32,21 +34,49 @@ class Agent:
Base class for a model agent in Mesa.

Attributes:
unique_id (int): A unique identifier for this agent.
model (Model): A reference to the model instance.
self.pos: Position | None = None
unique_id (int): A unique identifier for this agent.
pos (Position): A reference to the position where this agent is located.

Notes:
unique_id is unique relative to a model instance and starts from 1

"""

def __init__(self, unique_id: int, model: Model) -> None:
# this is a class level attribute
# it is a dictionary, indexed by model instance
# so, unique_id is unique relative to a model, and counting starts from 1
_ids = defaultdict(functools.partial(itertools.count, 1))
quaquel marked this conversation as resolved.
Show resolved Hide resolved

def __init__(self, *args, **kwargs) -> None:
"""
Create a new agent.

Args:
unique_id (int): A unique identifier for this agent.
model (Model): The model instance in which the agent exists.
"""
self.unique_id = unique_id
self.model = model
# TODO: Cleanup in future Mesa version (3.1+)
match args:
# Case 1: Only the model is provided. The new correct behavior.
case [model]:
self.model = model
self.unique_id = next(self._ids[model])
# Case 2: Both unique_id and model are provided, deprecated
case [_, model]:
warnings.warn(
"unique ids are assigned automatically to Agents in Mesa 3. The use of custom unique_id is "
"deprecated. Only input a model when calling `super()__init__(model)`. The unique_id inputted is not used.",
DeprecationWarning,
stacklevel=2,
)
self.model = model
self.unique_id = next(self._ids[model])
# Case 3: Anything else, raise an error
case _:
raise ValueError(
"Invalid arguments provided to initialize the Agent. Only input a model: `super()__init__(model)`."
)

self.pos: Position | None = None

self.model.register_agent(self)
Expand Down
4 changes: 2 additions & 2 deletions mesa/experimental/cell_space/cell_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ class CellAgent(Agent):
cell: (Cell | None): the cell which the agent occupies
"""

def __init__(self, unique_id: int, model: Model) -> None:
def __init__(self, model: Model) -> None:
"""
Create a new agent.

Args:
unique_id (int): A unique identifier for this agent.
model (Model): The model instance in which the agent exists.
"""
super().__init__(unique_id, model)
super().__init__(model)
self.cell: Cell | None = None

def move_to(self, cell) -> None:
Expand Down
16 changes: 6 additions & 10 deletions mesa/experimental/devs/examples/epstein_civil_violence.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@


class EpsteinAgent(Agent):
def __init__(self, unique_id, model, vision, movement):
super().__init__(unique_id, model)
def __init__(self, model, vision, movement):
super().__init__(model)
self.vision = vision
self.movement = movement

Expand Down Expand Up @@ -46,7 +46,6 @@ class Citizen(EpsteinAgent):

def __init__(
self,
unique_id,
model,
vision,
movement,
Expand All @@ -59,7 +58,6 @@ def __init__(
"""
Create a new Citizen.
Args:
unique_id: unique int
model : model instance
hardship: Agent's 'perceived hardship (i.e., physical or economic
privation).' Exogenous, drawn from U(0,1).
Expand All @@ -71,7 +69,7 @@ def __init__(
vision: number of cells in each direction (N, S, E and W) that
agent can inspect. Exogenous.
"""
super().__init__(unique_id, model, vision, movement)
super().__init__(model, vision, movement)
self.hardship = hardship
self.regime_legitimacy = regime_legitimacy
self.risk_aversion = risk_aversion
Expand Down Expand Up @@ -144,8 +142,8 @@ class Cop(EpsteinAgent):
able to inspect
"""

def __init__(self, unique_id, model, vision, movement, max_jail_term):
super().__init__(unique_id, model, vision, movement)
def __init__(self, model, vision, movement, max_jail_term):
super().__init__(model, vision, movement)
self.max_jail_term = max_jail_term

def step(self):
Expand Down Expand Up @@ -236,15 +234,13 @@ def __init__(
for _, pos in self.grid.coord_iter():
if self.random.random() < self.cop_density:
agent = Cop(
self.next_id(),
self,
cop_vision,
movement,
max_jail_term,
)
elif self.random.random() < (self.cop_density + self.citizen_density):
agent = Citizen(
self.next_id(),
self,
citizen_vision,
movement,
Expand All @@ -270,4 +266,4 @@ def step(self):

simulator.setup(model)

simulator.run(time_delta=100)
simulator.run_for(time_delta=100)
15 changes: 5 additions & 10 deletions mesa/experimental/devs/examples/wolf_sheep.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@


class Animal(mesa.Agent):
def __init__(self, unique_id, model, moore, energy, p_reproduce, energy_from_food):
super().__init__(unique_id, model)
def __init__(self, model, moore, energy, p_reproduce, energy_from_food):
super().__init__(model)
self.energy = energy
self.p_reproduce = p_reproduce
self.energy_from_food = energy_from_food
Expand All @@ -30,7 +30,6 @@ def random_move(self):
def spawn_offspring(self):
self.energy /= 2
offspring = self.__class__(
self.model.next_id(),
self.model,
self.moore,
self.energy,
Expand Down Expand Up @@ -109,15 +108,15 @@ def fully_grown(self, value: bool):
function_args=[self, "fully_grown", True],
)

def __init__(self, unique_id, model, fully_grown, countdown, grass_regrowth_time):
def __init__(self, model, fully_grown, countdown, grass_regrowth_time):
"""
Creates a new patch of grass

Args:
grown: (boolean) Whether the patch of grass is fully grown or not
countdown: Time for the patch of grass to be fully grown again
"""
super().__init__(unique_id, model)
super().__init__(model)
self._fully_grown = fully_grown
self.grass_regrowth_time = grass_regrowth_time

Expand Down Expand Up @@ -191,7 +190,6 @@ def __init__(
)
energy = self.random.randrange(2 * sheep_gain_from_food)
sheep = Sheep(
self.next_id(),
self,
moore,
energy,
Expand All @@ -208,7 +206,6 @@ def __init__(
)
energy = self.random.randrange(2 * wolf_gain_from_food)
wolf = Wolf(
self.next_id(),
self,
moore,
energy,
Expand All @@ -225,9 +222,7 @@ def __init__(
countdown = grass_regrowth_time
else:
countdown = self.random.randrange(grass_regrowth_time)
patch = GrassPatch(
self.next_id(), self, fully_grown, countdown, grass_regrowth_time
)
patch = GrassPatch(self, fully_grown, countdown, grass_regrowth_time)
self.grid.place_agent(patch, pos)

def step(self):
Expand Down
Loading
Loading