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

Fix AgentSet inplace shuffle (and thus RandomActivation), add tests #2007

Merged
merged 10 commits into from
Jan 26, 2024
1 change: 1 addition & 0 deletions mesa/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
except AttributeError:
# model super has not been called
self.model.agents_ = defaultdict(dict)
self.model.agents_[type(self)][self] = None

Check warning on line 57 in mesa/agent.py

View check run for this annotation

Codecov / codecov/patch

mesa/agent.py#L57

Added line #L57 was not covered by tests
Copy link
Contributor

Choose a reason for hiding this comment

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

This fix is out of the scope of this PR, but it's fine to add it here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah preferably this would have been a seperate PR.

self.model.agentset_experimental_warning_given = False

warnings.warn(
Expand Down
4 changes: 2 additions & 2 deletions mesa/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ def get_agent_keys(self, shuffle: bool = False) -> list[int]:

def do_each(self, method, shuffle=False):
if shuffle:
self.agents.shuffle(inplace=True)
self.agents.do(method)
self._agents.shuffle(inplace=True)
self._agents.do(method)


class RandomActivation(BaseScheduler):
Expand Down
13 changes: 13 additions & 0 deletions tests/test_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,16 @@ def test_agentset_select_by_type():
# Test with no type specified (should select all agents)
all_agents = agentset.select()
assert len(all_agents) == len(mixed_agents)


def test_agentset_shuffle():
model = Model()
test_agents = [TestAgent(model.next_id(), model) for _ in range(12)]

agentset = AgentSet(test_agents, model=model)
agentset = agentset.shuffle()
assert not all(a1 == a2 for a1, a2 in zip(test_agents, agentset))

agentset = AgentSet(test_agents, model=model)
agentset.shuffle(inplace=True)
assert not all(a1 == a2 for a1, a2 in zip(test_agents, agentset))
22 changes: 22 additions & 0 deletions tests/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,28 @@ def test_get_agent_keys(self):
agent_ids = {agent.unique_id for agent in model.agents}
assert all(entry in agent_ids for entry in keys)

def test_not_sequential(self):
model = MockModel(activation=RANDOM)
# Create 10 agents
for _ in range(10):
model.schedule.add(MockAgent(model.next_id(), model))
# Run 3 steps
for _ in range(3):
model.step()
# Filter out non-integer elements from the log
filtered_log = [item for item in model.log if isinstance(item, int)]

# Check that there are no 18 consecutive agents id's in the filtered log
total_agents = 10
assert not any(
all(
(filtered_log[(i + j) % total_agents] - filtered_log[i]) % total_agents
== j % total_agents
for j in range(18)
)
for i in range(len(filtered_log))
), f"Agents are activated sequentially:\n{filtered_log}"


class TestSimultaneousActivation(TestCase):
"""
Expand Down
Loading