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

Cell space: Place agents in AgentSet randomly on (empty) cells #2530

Closed
EwoutH opened this issue Dec 3, 2024 · 11 comments
Closed

Cell space: Place agents in AgentSet randomly on (empty) cells #2530

EwoutH opened this issue Dec 3, 2024 · 11 comments
Labels
enhancement Release notes label

Comments

@EwoutH
Copy link
Member

EwoutH commented Dec 3, 2024

Often you create a bunch of Agents, and then you need to place them on the grid. Either you loop over them, or do some other unwieldy thing, none of it is elegant.

So it would be great if there was a simple function that would get all agents and place them on, optionally empty, cells. This could be implemented faster than placing them individually, since now only once has to be checked which cells are available / empty.

It's especially handy to be used together with create_agents (#2351), combined you can create and place all your agents with two lines of code.

some_agents = Ant.create_agents(n=100)
self.space.place_agents(some_agents, only_empty=True)
@EwoutH EwoutH added the enhancement Release notes label label Dec 3, 2024
@quaquel
Copy link
Member

quaquel commented Dec 3, 2024

Yes either have a place_agents method, or have a way of getting a list of positions drawn either with it without replacement:

cells = self.space.choices_empty_cells(100,) # with replacement, follows random.choices
cells = self.space.sample_empty_cells(100)  # no replacement, follows random.sample

@EwoutH
Copy link
Member Author

EwoutH commented Dec 4, 2024

once we agree on how to go about it: do it via sampling/choosing empty cells or do it via placing agents, or even have both?

Sorry, didn't recognize there also was a question in there. I would say its a two-stage function:

  1. Select a random sample of cells, with or without replacement (keyword) and only empty or all (keyword)
  2. Place the agents on these sampled cells.
self.space.place(agents, unique=False, empty=False)

@quaquel
Copy link
Member

quaquel commented Dec 4, 2024

I am not sure. A key design choice with the new discrete spaces is to put the agent central and in control of its movement. So, to me it makes more sense to just sample/choice the cells, pass a cell to the agent as an argument and let the agent place itself via self.cell = cell. In that design, there is no need for a space-level place method.

@EwoutH
Copy link
Member Author

EwoutH commented Dec 4, 2024

Interesting, I'm not that familiar with the cell space yet.

In that case you could doe something like:

some_agents = MyAgent.create_agents(n=100)
cells = self.space ...
some_agents.map(lambda agent, cell: setattr(agent, 'cell', cell), zip(agents, cells))

That map is a bit cumbersome.

However, changing it around might work, right?

cells = self.space ...
some_agents = MyAgent.create_agents(n=100, cell=cells)

Can create_agents handle a CellCollection?

@quaquel
Copy link
Member

quaquel commented Dec 4, 2024

A CellCollection is a sequence so it supports item-based access. This is what is used in create_agents, so yes that should work.

Looking at the code again, there are actually a couple more options on how to implement this. A DiscreteSpace has an empties attribute and aan all_cells attribute. Both return a CellCollection, so sample and choices might also be implemented on the CellCollection so you could do

cells = self.space.empties.sample(100)
cells = self.space.empties.choices(100)
cells = self.space.all_cells.sample(100)
cells = self.space.all_cells.choices(100)

and then

class MyAgent(CellAgent):
    def __init__(self, model, cell):
        super().__init__(model)
        self.cell = cell

agents = MyAgent.create_agents(100, cells)

@EwoutH
Copy link
Member Author

EwoutH commented Dec 4, 2024

So we don't need anything new at all to do this. Damn. Powerful stuff.

I will update a few example models tomorrow.

@quaquel
Copy link
Member

quaquel commented Dec 4, 2024

sample and choices are currently not implemented on CellCollection, but self.random.sample(self.space.empties, 100) might already work.

@quaquel
Copy link
Member

quaquel commented Dec 6, 2024

I quickly checked, self.random.sample(self.space.empties, k=100) does not currently work. The issue is with the current implementation of __getitem__. A CellCollection is not a sequence, so some_cellcollection[1] does not work. Instead, currently __getitem__ returns the agents for the cell. So it does agents = some_cellcollection[my_cell].

@Corvince, do you remember why __getitem__ is implemented this way?

@Corvince
Copy link
Contributor

No I don't remember exactly, but yes, the CellCollection itself is more of like a dict than a sequence and you can't sample directly from a dict. But CellCollection also exposes a cells property. So I think self.random.sample(self.space.empties.cells, k=100) should work? It will give you a list of cells that you can use directly or just convert to another collection like CellCollection(sampled_cells). Pretty flexible!

@EwoutH
Copy link
Member Author

EwoutH commented Dec 10, 2024

Great insight! So now it's just:

some_empty_cells = self.random.sample(self.space.empties.cells, k=100)
some_agents = MyAgent.create_agents(n=100, cell=some_empty_cells)

Shows how powerful and flexible the cell space is.

@quaquel
Copy link
Member

quaquel commented Dec 12, 2024

I added this to some of the examples so it is clear to others as well how to do this. I am closing this issue.

@quaquel quaquel closed this as completed Dec 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Release notes label
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants