Agents.jl: questions regarding the API

Created on 15 Oct 2019  Â·  16Comments  Â·  Source: JuliaDynamics/Agents.jl

Hello there,

I've got some questions regarding the current API. I am looking specifically at the forest fire example, but I think the same thing applies to all examples.

  1. Why use the lengthy syntax, like for node in 1:gridsize(forest.space.dimensions) instead of using for node in verteces(space) ?
  2. In this loop:
      tree = Tree(node, (1,1), true)
      add_agent!(tree, node, forest) # TODO: why is the agent getting (1,1)?

why do the agents get position (1,1)? Shouldn't they be getting the position of the node? This confuses me a lot...

  1. Later on, there is shuffle(1:gridsize(forest.space.dimensions)) which could instead become shuffle(verteces(forest.space))

In general, while I am working on #20 , I am trying to simplify the API. I am asking these questions to see if there is a fundamental design decision behind them. If not, then I think the simplest, clearest, and shortest version should be used.

I don't think it is beneficial to define a second API on top of the LightGraphs API, which I think is what happens at the moment with gridsize.

All 16 comments

One more Q:

the documentation states that a field of a Space object must be:

Second, dimensions of the grid or network in a Tuple.

What is this supposed to be for a social network graph?

The more I think about it, the more I wonder: can we completely remove the type Space, and use a graph directly as a subfield of the Model, and make agent_positions a subfield of the Model?

That's what I was wondering too. Seems like a clean / elegant way to go.

Yeah, this would simplify things a lot, and I think LightGraphs provides quite a robust API, making it not necessary to make our own on top of it.

If @kavir1698 gives the okay, I'll start working on a new branch that removes the Space types and subtypes and instead links graphs directly.

If you have energy, I say "Go for it" while its hot :)

Hi,
Thank you for your suggestions.
Answers to the questions:

  1. Yes, we could use the vertices function here, which would be used as for node in vertices(forest.space.space). I do not have a strong opinion for either implementation.

  2. tree = Tree(node, (1,1), true) creates a tree object at coordinates (1,1). Then, add_agent!(tree, node, forest) adds this tree to a random location on the grid and automatically changes its coordinates. In this model, and many classic agent-based models, the space is a grid. Therefore, the space handles grid spaces without confusing the user with graphs.

  3. Same as 1.

I have added the Space object so that the user will not have to learn to use LightGraphs too before using the Agents. Additionally, there are functions to make certain grids that would be too much for a user to make. For example, one can easily create a simple grid where the borders connect to the opposite side with grid(3, 4, periodic=true) or grid(3, 4, periodic=true, Moore=true) only keeps edges to orthogonal neighbors.

More common space structures can similarly be added to the model.

If you think by removing the space object, we can keep the functionality and make the package easier to use, I would be happy to go that direction.

By the way, I am not too available these days, so apologies in advance for delayed responses.

No problem @kavir1698 , I just started working on this now.

I have added the Space object so that the user will not have to learn to use LightGraphs too before using the Agents. Additionally, there are functions to make certain grids that would be too much for a user to make. For example, one can easily create a simple grid where the borders connect to the opposite side with grid(3, 4, periodic=true) or grid(3, 4, periodic=true, Moore=true) only keeps edges to orthogonal neighbors.

In my eyes this does not justify the requirement from the user side to create a Space object. Because, everything you describe we can (and I think we will) provide with a single function, the proposal of #24 .

In the meantime, the current documentation states that the Space must have a field dimension. Can you please explain:

  • What is it supposed to be for non grid-like graphs for social agent experiments, like the ones that @EricForgy mentioned ?

This dimensions field is used in the functions vertex_to_coord and coord_to_vertex. Since I want to make this Space work with also aribtrary graphs, as stated here: https://github.com/JuliaDynamics/Agents.jl/issues/24#issuecomment-520040341 , then I need a way to make sense of dimensions for them.

(Or, if Agents.jl does not support arbitrary graphs but instead only grids, then let me know)

The more I read the code, the more I realize that functionality related with coord_to_vertex is hard-coded. How does this allow for arbitrary graphs?

The documentation states:

Users may also provide arbitrary networks as their model's spatial structure.

But I have not seen any example where this is possible. The only case without a grid is the Boltzmann wealth, which has no space at all (and left me utterly confused, since the "Tutorial" page very clearly says that space must be part of any AbstractModel subtype).

Regardless, I have a good idea on how to make everything general: allow a function to be (optionally) provided, that does the job of vertex_to_coord: given a vertex index of the graph, the function returns its coordinates in "real space". By default we use our own internal vertex_to_coord, but this also allow arbitrary graphs to be provided by a user.

In my first startup, we had a "Hard Coding" jar. If you are caught hard coding, you need to put a dollar in the jar 😊

What is it supposed to be for non grid-like graphs for social agent experiments, like the ones that @EricForgy mentioned ?

In which case, the user can insert his own graph directly. For example, in the "forest fire" example, we have a MyGrid Space object who has a space subfield. We initialized the MyGrid object like this: mygrid = MyGrid(griddims, grid(griddims, false, true), agent_positions). Here, we used the grid function from Agents.jl, which creates a grid using LightGraphs. If one wants a non-grid graph, then he would simply create it separately and put in there. So the initialization would change to mygrid = MyGrid(griddims, custom_graph, agent_positions). The space subfield is a SimpleGraph object.

For non-grid graphs, the dimensions field would be an integer, the number of nodes. However, for such graphs, coord_to_vertex and vertex_to_coord functions are irrelevant and do not need to be used.

Thanks, this simplifies things massively. I have a very promising API improvement in the works. But I'll need your help reviewing it. I know you are short on time, so when I open my Pull Request take as much time as necessary; I think it will be important to spend some time discussing it.

That's great. I am looking forward to seeing your improvements.

@kavir1698 can you please clarify what is happening in Base.iterate(::Node_iter), specifically here:

if nagents == 0
    element = (Integer[], Array{AbstractArray}(undef,0))

so what exactly do you want to return if there are no agents? These datastructures are ineficient, why create two empty vectors if there is nothing? Maybe we should take advantage of nothing here...

and especially, why is the first entry Integer[] ? Shouldn't it be the position of the node _regardless_ of whether the node has agents or not?!

Also, if we make it return the node index, as well as the agent IDs in that node, then the return type of this iteration will always be clear.

This iterator is for the convenience of the users. If I remember correctly,
it is not used anywhere in the package. So it is a good idea and
non-breaking change to return nothing when there are no agents.

You are right about the return type that should be the position of the node. But when the space is a grid, the position will be a tuple. When the space is non-grid, the position will be an integer. So, The return type will depend on how the space is defined.

On Sun, Oct 20, 2019, 3:56 PM George Datseris notifications@github.com
wrote:

@kavir1698 https://github.com/kavir1698 can you please clarify what is
happening in Base.iterate(::Node_iter), specifically here:

if nagents == 0
element = (Integer[], Array{AbstractArray}(undef,0))

so what exactly do you want to return if there are no agents? These
datastructures are terribly ineficient, why create two empty vectors if
there is nothing? Maybe we should take advantage of nothing here...

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/JuliaDynamics/Agents.jl/issues/36?email_source=notifications&email_token=AA47OUPZOZPPLEXVJ3PK4QDQPRPQ5A5CNFSM4JA3PNPKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBYKWEI#issuecomment-544254737,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AA47OUJK4OYSI63WNASVKP3QPRPQ5ANCNFSM4JA3PNPA
.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Datseris picture Datseris  Â·  5Comments

Libbum picture Libbum  Â·  5Comments

Datseris picture Datseris  Â·  12Comments

itsdfish picture itsdfish  Â·  11Comments

flipgthb picture flipgthb  Â·  5Comments