diff --git a/benchmarks/BoltzmannWealth/boltzmann_wealth.py b/benchmarks/BoltzmannWealth/boltzmann_wealth.py index f6b1bf3d6f9..56443c6f476 100644 --- a/benchmarks/BoltzmannWealth/boltzmann_wealth.py +++ b/benchmarks/BoltzmannWealth/boltzmann_wealth.py @@ -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) @@ -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): diff --git a/benchmarks/Flocking/flocking.py b/benchmarks/Flocking/flocking.py index ff9f97c0c96..284d831850c 100644 --- a/benchmarks/Flocking/flocking.py +++ b/benchmarks/Flocking/flocking.py @@ -27,7 +27,6 @@ class Boid(mesa.Agent): def __init__( self, - unique_id, model, speed, direction, @@ -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. @@ -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 @@ -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, diff --git a/benchmarks/Schelling/schelling.py b/benchmarks/Schelling/schelling.py index b7702a84bed..b582e7af585 100644 --- a/benchmarks/Schelling/schelling.py +++ b/benchmarks/Schelling/schelling.py @@ -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 @@ -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) diff --git a/benchmarks/WolfSheep/wolf_sheep.py b/benchmarks/WolfSheep/wolf_sheep.py index 655d51bba63..ceb6efef8b8 100644 --- a/benchmarks/WolfSheep/wolf_sheep.py +++ b/benchmarks/WolfSheep/wolf_sheep.py @@ -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 @@ -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, @@ -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) @@ -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 @@ -189,7 +188,6 @@ def __init__( ) energy = self.random.randrange(2 * sheep_gain_from_food) sheep = Sheep( - self.next_id(), self, energy, sheep_reproduce, @@ -205,7 +203,6 @@ def __init__( ) energy = self.random.randrange(2 * wolf_gain_from_food) wolf = Wolf( - self.next_id(), self, energy, wolf_reproduce, @@ -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): diff --git a/docs/tutorials/MoneyModel.py b/docs/tutorials/MoneyModel.py index 94555f98035..93e19dec11f 100644 --- a/docs/tutorials/MoneyModel.py +++ b/docs/tutorials/MoneyModel.py @@ -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): diff --git a/mesa/agent.py b/mesa/agent.py index 8d04df9e30f..225e89cda79 100644 --- a/mesa/agent.py +++ b/mesa/agent.py @@ -10,6 +10,8 @@ import contextlib import copy +import functools +import itertools import operator import warnings import weakref @@ -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)) + + 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) diff --git a/mesa/experimental/cell_space/cell_agent.py b/mesa/experimental/cell_space/cell_agent.py index abc5155a670..5f1cca5cbcc 100644 --- a/mesa/experimental/cell_space/cell_agent.py +++ b/mesa/experimental/cell_space/cell_agent.py @@ -19,7 +19,7 @@ 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. @@ -27,7 +27,7 @@ def __init__(self, unique_id: int, model: Model) -> None: 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: diff --git a/mesa/experimental/devs/examples/epstein_civil_violence.py b/mesa/experimental/devs/examples/epstein_civil_violence.py index 9a7314e0ff3..c976bb73898 100644 --- a/mesa/experimental/devs/examples/epstein_civil_violence.py +++ b/mesa/experimental/devs/examples/epstein_civil_violence.py @@ -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 @@ -46,7 +46,6 @@ class Citizen(EpsteinAgent): def __init__( self, - unique_id, model, vision, movement, @@ -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). @@ -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 @@ -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): @@ -236,7 +234,6 @@ 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, @@ -244,7 +241,6 @@ def __init__( ) elif self.random.random() < (self.cop_density + self.citizen_density): agent = Citizen( - self.next_id(), self, citizen_vision, movement, @@ -270,4 +266,4 @@ def step(self): simulator.setup(model) - simulator.run(time_delta=100) + simulator.run_for(time_delta=100) diff --git a/mesa/experimental/devs/examples/wolf_sheep.py b/mesa/experimental/devs/examples/wolf_sheep.py index 99fde6a9c8f..cd81cb2ff04 100644 --- a/mesa/experimental/devs/examples/wolf_sheep.py +++ b/mesa/experimental/devs/examples/wolf_sheep.py @@ -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 @@ -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, @@ -109,7 +108,7 @@ 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 @@ -117,7 +116,7 @@ def __init__(self, unique_id, model, fully_grown, countdown, grass_regrowth_time 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 @@ -191,7 +190,6 @@ def __init__( ) energy = self.random.randrange(2 * sheep_gain_from_food) sheep = Sheep( - self.next_id(), self, moore, energy, @@ -208,7 +206,6 @@ def __init__( ) energy = self.random.randrange(2 * wolf_gain_from_food) wolf = Wolf( - self.next_id(), self, moore, energy, @@ -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): diff --git a/mesa/model.py b/mesa/model.py index f276cc82284..f859aea314f 100644 --- a/mesa/model.py +++ b/mesa/model.py @@ -28,7 +28,6 @@ class Model: Attributes: running: A boolean indicating if the model should continue running. schedule: An object to manage the order and execution of agent steps. - current_id: A counter for assigning unique IDs to agents. Properties: agents: An AgentSet containing all agents in the model @@ -74,7 +73,6 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.running = True self.schedule = None - self.current_id = 0 self.steps: int = 0 self._setup_agent_registration() @@ -90,6 +88,14 @@ def _wrapped_step(self, *args: Any, **kwargs: Any) -> None: # Call the original user-defined step method self._user_step(*args, **kwargs) + def next_id(self) -> int: + warnings.warn( + "using model.next_id() is deprecated. Agents track their unique ID automatically", + DeprecationWarning, + stacklevel=2, + ) + return 0 + @property def agents(self) -> AgentSet: """Provides an AgentSet of all agents in the model, combining agents from all types.""" @@ -189,11 +195,6 @@ def run_model(self) -> None: def step(self) -> None: """A single step. Fill in here.""" - def next_id(self) -> int: - """Return the next unique ID for agents, increment current_id""" - self.current_id += 1 - return self.current_id - def reset_randomizer(self, seed: int | None = None) -> None: """Reset the model random number generator. diff --git a/tests/test_agent.py b/tests/test_agent.py index bb61ae1c1bd..e78a4dcec93 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -15,17 +15,16 @@ def get_unique_identifier(self): class TestAgentDo(Agent): def __init__( self, - unique_id, model, ): - super().__init__(unique_id, model) + super().__init__(model) self.agent_set = None def get_unique_identifier(self): return self.unique_id def do_add(self): - agent = TestAgentDo(self.model.next_id(), self.model) + agent = TestAgentDo(self.model) self.agent_set.add(agent) def do_remove(self): @@ -34,7 +33,7 @@ def do_remove(self): def test_agent_removal(): model = Model() - agent = TestAgent(model.next_id(), model) + agent = TestAgent(model) # Check if the agent is added assert agent in model.agents @@ -46,7 +45,7 @@ def test_agent_removal(): def test_agentset(): # create agentset model = Model() - agents = [TestAgent(model.next_id(), model) for _ in range(10)] + agents = [TestAgent(model) for _ in range(10)] agentset = AgentSet(agents, model) @@ -117,14 +116,14 @@ def test_agentset_initialization(): empty_agentset = AgentSet([], model) assert len(empty_agentset) == 0 - agents = [TestAgent(model.next_id(), model) for _ in range(10)] + agents = [TestAgent(model) for _ in range(10)] agentset = AgentSet(agents, model) assert len(agentset) == 10 def test_agentset_serialization(): model = Model() - agents = [TestAgent(model.next_id(), model) for _ in range(5)] + agents = [TestAgent(model) for _ in range(5)] agentset = AgentSet(agents, model) serialized = pickle.dumps(agentset) @@ -138,16 +137,16 @@ def test_agentset_serialization(): def test_agent_membership(): model = Model() - agents = [TestAgent(model.next_id(), model) for _ in range(5)] + agents = [TestAgent(model) for _ in range(5)] agentset = AgentSet(agents, model) assert agents[0] in agentset - assert TestAgent(model.next_id(), model) not in agentset + assert TestAgent(model) not in agentset def test_agent_add_remove_discard(): model = Model() - agent = TestAgent(model.next_id(), model) + agent = TestAgent(model) agentset = AgentSet([], model) agentset.add(agent) @@ -166,7 +165,7 @@ def test_agent_add_remove_discard(): def test_agentset_get_item(): model = Model() - agents = [TestAgent(model.next_id(), model) for _ in range(10)] + agents = [TestAgent(model) for _ in range(10)] agentset = AgentSet(agents, model) assert agentset[0] == agents[0] @@ -179,7 +178,7 @@ def test_agentset_get_item(): def test_agentset_do_str(): model = Model() - agents = [TestAgent(model.next_id(), model) for _ in range(10)] + agents = [TestAgent(model) for _ in range(10)] agentset = AgentSet(agents, model) with pytest.raises(AttributeError): @@ -192,7 +191,7 @@ def test_agentset_do_str(): # setup n = 10 model = Model() - agents = [TestAgentDo(model.next_id(), model) for _ in range(n)] + agents = [TestAgentDo(model) for _ in range(n)] agentset = AgentSet(agents, model) for agent in agents: agent.agent_set = agentset @@ -202,7 +201,7 @@ def test_agentset_do_str(): # setup model = Model() - agents = [TestAgentDo(model.next_id(), model) for _ in range(10)] + agents = [TestAgentDo(model) for _ in range(10)] agentset = AgentSet(agents, model) for agent in agents: agent.agent_set = agentset @@ -213,7 +212,7 @@ def test_agentset_do_str(): def test_agentset_do_callable(): model = Model() - agents = [TestAgent(model.next_id(), model) for _ in range(10)] + agents = [TestAgent(model) for _ in range(10)] agentset = AgentSet(agents, model) # Test callable with non-existent function @@ -227,7 +226,7 @@ def test_agentset_do_callable(): # setup for lambda function tests n = 10 model = Model() - agents = [TestAgentDo(model.next_id(), model) for _ in range(n)] + agents = [TestAgentDo(model) for _ in range(n)] agentset = AgentSet(agents, model) for agent in agents: agent.agent_set = agentset @@ -238,7 +237,7 @@ def test_agentset_do_callable(): # setup again for lambda function tests model = Model() - agents = [TestAgentDo(model.next_id(), model) for _ in range(10)] + agents = [TestAgentDo(model) for _ in range(10)] agentset = AgentSet(agents, model) for agent in agents: agent.agent_set = agentset @@ -256,7 +255,7 @@ def remove_function(agent): # setup again for actual function tests model = Model() - agents = [TestAgentDo(model.next_id(), model) for _ in range(n)] + agents = [TestAgentDo(model) for _ in range(n)] agentset = AgentSet(agents, model) for agent in agents: agent.agent_set = agentset @@ -267,7 +266,7 @@ def remove_function(agent): # setup again for actual function tests model = Model() - agents = [TestAgentDo(model.next_id(), model) for _ in range(10)] + agents = [TestAgentDo(model) for _ in range(10)] agentset = AgentSet(agents, model) for agent in agents: agent.agent_set = agentset @@ -279,7 +278,7 @@ def remove_function(agent): def test_agentset_agg(): model = Model() - agents = [TestAgent(i, model) for i in range(10)] + agents = [TestAgent(model) for i in range(10)] # Assign some values to attributes for i, agent in enumerate(agents): @@ -315,12 +314,12 @@ def custom_func(values): def test_agentset_set_method(): # Initialize the model and agents with and without existing attributes class TestAgentWithAttribute(Agent): - def __init__(self, unique_id, model, age=None): - super().__init__(unique_id, model) + def __init__(self, model, age=None): + super().__init__(model) self.age = age model = Model() - agents = [TestAgentWithAttribute(model.next_id(), model, age=i) for i in range(5)] + agents = [TestAgentWithAttribute(model, age=i) for i in range(5)] agentset = AgentSet(agents, model) # Set a new attribute "health" and an existing attribute "age" for all agents @@ -338,7 +337,7 @@ def __init__(self, unique_id, model, age=None): def test_agentset_map_str(): model = Model() - agents = [TestAgent(model.next_id(), model) for _ in range(10)] + agents = [TestAgent(model) for _ in range(10)] agentset = AgentSet(agents, model) with pytest.raises(AttributeError): @@ -350,7 +349,7 @@ def test_agentset_map_str(): def test_agentset_map_callable(): model = Model() - agents = [TestAgent(model.next_id(), model) for _ in range(10)] + agents = [TestAgent(model) for _ in range(10)] agentset = AgentSet(agents, model) # Test callable with non-existent function @@ -367,7 +366,7 @@ def test_agentset_map_callable(): def test_agentset_get_attribute(): model = Model() - agents = [TestAgent(model.next_id(), model) for _ in range(10)] + agents = [TestAgent(model) for _ in range(10)] agentset = AgentSet(agents, model) unique_ids = agentset.get("unique_id") @@ -379,7 +378,7 @@ def test_agentset_get_attribute(): model = Model() agents = [] for i in range(10): - agent = TestAgent(model.next_id(), model) + agent = TestAgent(model) agent.i = i**2 agents.append(agent) agentset = AgentSet(agents, model) @@ -403,8 +402,8 @@ def get_unique_identifier(self): def test_agentset_select_by_type(): model = Model() # Create a mix of agents of two different types - test_agents = [TestAgent(model.next_id(), model) for _ in range(4)] - other_agents = [OtherAgentType(model.next_id(), model) for _ in range(6)] + test_agents = [TestAgent(model) for _ in range(4)] + other_agents = [OtherAgentType(model) for _ in range(6)] # Combine the two types of agents mixed_agents = test_agents + other_agents @@ -428,7 +427,7 @@ def test_agentset_select_by_type(): def test_agentset_shuffle(): model = Model() - test_agents = [TestAgent(model.next_id(), model) for _ in range(12)] + test_agents = [TestAgent(model) for _ in range(12)] agentset = AgentSet(test_agents, model=model) agentset = agentset.shuffle() @@ -441,15 +440,15 @@ def test_agentset_shuffle(): def test_agentset_groupby(): class TestAgent(Agent): - def __init__(self, unique_id, model): - super().__init__(unique_id, model) + def __init__(self, model): + super().__init__(model) self.even = self.unique_id % 2 == 0 def get_unique_identifier(self): return self.unique_id model = Model() - agents = [TestAgent(model.next_id(), model) for _ in range(10)] + agents = [TestAgent(model) for _ in range(10)] agentset = AgentSet(agents, model) groups = agentset.groupby("even") @@ -479,3 +478,14 @@ def get_unique_identifier(self): groups = agentset.groupby("even", result_type="agentset") another_ref_to_groups = groups.do(lambda x: x.do("step")) assert groups == another_ref_to_groups + + +def test_oldstyle_agent_instantiation(): + """Old behavior of Agent creation with unique_id and model as positional arguments. + Can be removed/updated in the future.""" + model = Model() + agent = Agent("some weird unique id", model) + assert isinstance(agent.unique_id, int) + assert agent.model == model + assert isinstance(agent.model, Model) + assert agent.unique_id == 1 # test that we ignore unique ID that is passed diff --git a/tests/test_batch_run.py b/tests/test_batch_run.py index 2de7c44735f..784c041679a 100644 --- a/tests/test_batch_run.py +++ b/tests/test_batch_run.py @@ -28,9 +28,8 @@ class MockAgent(Agent): Minimalistic agent implementation for testing purposes """ - def __init__(self, unique_id, model, val): - super().__init__(unique_id, model) - self.unique_id = unique_id + def __init__(self, model, val): + super().__init__(model) self.val = val self.local = 0 @@ -76,8 +75,8 @@ def init_agents(self): agent_val = 1 else: agent_val = self.variable_agent_param - for i in range(self.n_agents): - self.schedule.add(MockAgent(i, self, agent_val)) + for _ in range(self.n_agents): + self.schedule.add(MockAgent(self, agent_val)) def get_local_model_param(self): return 42 @@ -95,8 +94,8 @@ def test_batch_run(): "iteration": 0, "Step": 1000, "reported_model_param": 42, - "AgentID": 0, - "agent_id": 0, + "AgentID": 1, + "agent_id": 1, "agent_local": 250.0, }, { @@ -104,8 +103,8 @@ def test_batch_run(): "iteration": 0, "Step": 1000, "reported_model_param": 42, - "AgentID": 1, - "agent_id": 1, + "AgentID": 2, + "agent_id": 2, "agent_local": 250.0, }, { @@ -113,8 +112,8 @@ def test_batch_run(): "iteration": 0, "Step": 1000, "reported_model_param": 42, - "AgentID": 2, - "agent_id": 2, + "AgentID": 3, + "agent_id": 3, "agent_local": 250.0, }, ] @@ -172,29 +171,29 @@ def test_batch_run_unhashable_param(): { "RunId": 0, "iteration": 0, - "AgentID": 0, - "agent_id": 0, + "AgentID": 1, + "agent_id": 1, **template, }, { "RunId": 0, "iteration": 0, - "AgentID": 1, - "agent_id": 1, + "AgentID": 2, + "agent_id": 2, **template, }, { "RunId": 1, "iteration": 1, - "AgentID": 0, - "agent_id": 0, + "AgentID": 1, + "agent_id": 1, **template, }, { "RunId": 1, "iteration": 1, - "AgentID": 1, - "agent_id": 1, + "AgentID": 2, + "agent_id": 2, **template, }, ] diff --git a/tests/test_cell_space.py b/tests/test_cell_space.py index a918f59e53b..4127847d17b 100644 --- a/tests/test_cell_space.py +++ b/tests/test_cell_space.py @@ -408,7 +408,7 @@ def test_empties_space(): model = Model() for i in range(8): - grid._cells[i].add_agent(CellAgent(i, model)) + grid._cells[i].add_agent(CellAgent(model)) cell = grid.select_random_empty_cell() assert cell.coordinate in {8, 9} @@ -432,7 +432,7 @@ def test_cell(): # add_agent model = Model() - agent = CellAgent(1, model) + agent = CellAgent(model) cell1.add_agent(agent) assert agent in cell1.agents @@ -445,11 +445,11 @@ def test_cell(): cell1.remove_agent(agent) cell1 = Cell((1,), capacity=1, random=random.Random()) - cell1.add_agent(CellAgent(1, model)) + cell1.add_agent(CellAgent(model)) assert cell1.is_full with pytest.raises(Exception): - cell1.add_agent(CellAgent(2, model)) + cell1.add_agent(CellAgent(model)) def test_cell_collection(): @@ -475,9 +475,9 @@ def test_cell_collection(): cells = collection.cells model = Model() - cells[0].add_agent(CellAgent(1, model)) - cells[3].add_agent(CellAgent(2, model)) - cells[7].add_agent(CellAgent(3, model)) + cells[0].add_agent(CellAgent(model)) + cells[3].add_agent(CellAgent(model)) + cells[7].add_agent(CellAgent(model)) agents = collection.agents assert len(list(agents)) == 3 diff --git a/tests/test_datacollector.py b/tests/test_datacollector.py index bf74e3790d8..94e7742afab 100644 --- a/tests/test_datacollector.py +++ b/tests/test_datacollector.py @@ -13,8 +13,8 @@ class MockAgent(Agent): Minimalistic agent for testing purposes. """ - def __init__(self, unique_id, model, val=0): - super().__init__(unique_id, model) + def __init__(self, model, val=0): + super().__init__(model) self.val = val self.val2 = val @@ -40,14 +40,6 @@ def agent_function_with_params(agent, multiplier, offset): return (agent.val * multiplier) + offset -class DifferentMockAgent(MockAgent): - # We define a different MockAgent to test for attributes that are present - # only in 1 type of agent, but not the other. - def __init__(self, unique_id, model, val=0): - super().__init__(unique_id, model, val=val) - self.val3 = val + 42 - - class MockModel(Model): """ Minimalistic model for testing purposes. @@ -61,8 +53,8 @@ def __init__(self): self.model_val = 100 self.n = 10 - for i in range(self.n): - self.schedule.add(MockAgent(i, self, val=i)) + for i in range(1, self.n + 1): + self.schedule.add(MockAgent(self, val=i)) self.initialize_data_collector( model_reporters={ "total_agents": lambda m: m.schedule.get_agent_count(), diff --git a/tests/test_lifespan.py b/tests/test_lifespan.py index cfd60cdeb74..00dd878c8e9 100644 --- a/tests/test_lifespan.py +++ b/tests/test_lifespan.py @@ -29,9 +29,7 @@ def __init__(self, agent_lifetime=1, n_agents=10): self.schedule = RandomActivation(self) for _ in range(n_agents): - self.schedule.add( - FiniteLifeAgent(self.next_id(), self.agent_lifetime, self) - ) + self.schedule.add(FiniteLifeAgent(self.agent_lifetime, self)) def step(self): """Add agents back to n_agents in each step""" @@ -40,9 +38,7 @@ def step(self): if len(self.schedule.agents) < self.n_agents: for _ in range(self.n_agents - len(self.schedule.agents)): - self.schedule.add( - FiniteLifeAgent(self.next_id(), self.agent_lifetime, self) - ) + self.schedule.add(FiniteLifeAgent(self.agent_lifetime, self)) def run_model(self, step_count=100): for _ in range(step_count): @@ -54,8 +50,8 @@ class FiniteLifeAgent(Agent): Also has a 10% chance of dying in each tick. """ - def __init__(self, unique_id, lifetime, model): - super().__init__(unique_id, model) + def __init__(self, lifetime, model): + super().__init__(model) self.remaining_life = lifetime self.steps = 0 self.model = model diff --git a/tests/test_model.py b/tests/test_model.py index c92fcb2e4a9..016185e6084 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -6,9 +6,6 @@ def test_model_set_up(): model = Model() assert model.running is True assert model.schedule is None - assert model.current_id == 0 - assert model.current_id + 1 == model.next_id() - assert model.current_id == 1 assert model.steps == 0 model.step() assert model.steps == 1 @@ -50,7 +47,7 @@ class TestAgent(Agent): pass model = Model() - test_agent = TestAgent(model.next_id(), model) + test_agent = TestAgent(model) assert test_agent in model.agents assert type(test_agent) in model.agent_types @@ -63,8 +60,8 @@ class Sheep(Agent): pass model = Model() - wolf = Wolf(1, model) - sheep = Sheep(2, model) + wolf = Wolf(model) + sheep = Sheep(model) assert model.agents_by_type[Wolf] == AgentSet([wolf], model) assert model.agents_by_type[Sheep] == AgentSet([sheep], model) diff --git a/tests/test_time.py b/tests/test_time.py index 4203ca5d222..13d71d22eb0 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -25,8 +25,8 @@ class MockAgent(Agent): Minimalistic agent for testing purposes. """ - def __init__(self, unique_id, model): - super().__init__(unique_id, model) + def __init__(self, model): + super().__init__(model) self.steps = 0 self.advances = 0 @@ -38,10 +38,10 @@ def kill_other_agent(self): def stage_one(self): if self.model.enable_kill_other_agent: self.kill_other_agent() - self.model.log.append(self.unique_id + "_1") + self.model.log.append(f"{self.unique_id}_1") def stage_two(self): - self.model.log.append(self.unique_id + "_2") + self.model.log.append(f"{self.unique_id}_2") def advance(self): self.advances += 1 @@ -89,8 +89,8 @@ def __init__(self, shuffle=False, activation=STAGED, enable_kill_other_agent=Fal self.schedule = BaseScheduler(self) # Make agents - for name in ["A", "B"]: - agent = MockAgent(name, self) + for _ in range(2): + agent = MockAgent(self) self.schedule.add(agent) def step(self): @@ -105,7 +105,7 @@ class TestStagedActivation(TestCase): Test the staged activation. """ - expected_output = ["A_1", "B_1", "model_stage", "A_2", "B_2"] + expected_output = ["1_1", "1_1", "model_stage", "1_2", "1_2"] def test_no_shuffle(self): """ @@ -168,7 +168,7 @@ class TestRandomActivation(TestCase): def test_init(self): model = Model() - agents = [MockAgent(model.next_id(), model) for _ in range(10)] + agents = [MockAgent(model) for _ in range(10)] scheduler = RandomActivation(model, agents) assert all(agent in scheduler.agents for agent in agents) @@ -227,7 +227,7 @@ def test_not_sequential(self): model = MockModel(activation=RANDOM) # Create 10 agents for _ in range(10): - model.schedule.add(MockAgent(model.next_id(), model)) + model.schedule.add(MockAgent(model)) # Run 3 steps for _ in range(3): model.step() @@ -273,8 +273,8 @@ class TestRandomActivationByType(TestCase): def test_init(self): model = Model() - agents = [MockAgent(model.next_id(), model) for _ in range(10)] - agents += [Agent(model.next_id(), model) for _ in range(10)] + agents = [MockAgent(model) for _ in range(10)] + agents += [Agent(model) for _ in range(10)] scheduler = RandomActivationByType(model, agents) assert all(agent in scheduler.agents for agent in agents)