Adding multiple agent types to an AgentBasedModel (in Agents.jl)

Hi,

I am trying create an Agent Based Model using the Agents.jl package and wondering how to add multiple agent types in GridSpace based model.

In this instance I want to add two type of agents

using Agents:: AbstractAgent, GridSpace, AgentBasedModel
mutable struct CasAgent <: AbstractAgent
    id::Int
    pos::Dims{2}
    TS::Int64
end

mutable struct RescAgent <: AbstractAgent
    id::Int
    targeted_cas::Bool
    rescued_cas::Array{CasAgent}
end

space = GridSpace((10,10), periodic = false)
model = AgentBasedModel(CasAgent, RescAgent, space)

#Out >
#MethodError: no method matching AgentBasedModel(::Type{CasAgent}, ::Type{RescAgent}, ::GridSpace{2, false, Nothing})

ofcourse adding in single agent works fine. But two agents wont.

model = AgentBasedModel(CasAgent, RescAgent, space)
#Out >
#AgentBasedModel with 0 agents of type CasAgent

Also on a separate note, I want the CasAgents to occupy a position in the GridSpace while the RescAgents are within the model but doesnt occupy a space – is this possible?

You can try AgentBasedModel(Union{RescAgent, CasAgent}, space). Regarding occupation of the position, you can give them all position (1, 1) and ignore it afterwards.

1 Like

Yep, as @Skoffer has pointed out already: Type Unions will enable you to have multiple agent types in your setup.

For your second question concerning RestAgents in the model but not occupying a space:
This sort of means they’re just a model property and not agents per se, correct?

I’d be inclined just to have

using Agents

mutable struct CasAgent <: AbstractAgent
    id::Int
    pos::Dims{2}
    TS::Int64
end

mutable struct RescAgent
    id::Int #Maybe even this is optional now
    targeted_cas::Bool
    rescued_cas::Array{CasAgent}
end

properties = (resc = RescAgent[], other_property = 7.5) 

model = ABM(CasAgent, GridSpace((10, 10), periodic = false), properties)

Depending on how you want to interact with RescAgent, you could change them to a Dict with id as their key and a named tuple as the values of your other properties.

From the looks of it though, are you in need of more than one RescAgent in the system? There may even be a simpler way to represent what you want to do if you give me a bit more detail on your requirements.

1 Like

Additionaly, if your model is something like https://www.pnas.org/content/99/suppl_3/7243, then in my implementation I just added the flag “isjailed” to civil agents and ignored them in all neighbours scan (and didn’t show in visualization).

Actually the model I am hoping to create is reconstruction of an older model I created in Netlogo. But in this instance I am hoping to remove the Geo-spatial elements of the model (Anything relating geospatial elements such as distances, will be hopefully be include as input values and/or random values). So literally in this model, you will only be able to see the boxes on the bottom right, but in a GridSpace format.

I initially thought it would be easier if RescAgents can be modeled as agents, since each rescuer will need to travel a different to get to a casualty (CasAgent). However now that you said this perhaps this is better way of doing it.

Quite an interesting model you have there!

We are in the process of setting up a larger model library. I’ll ping you again in a day or two and provide some links - it’ll be interesting to see how best we can translate this model to Agents.jl. There are some design philosophies that we have consciously chosen that are not so compatible with the way you think about model design in Netlogo, but we feel (and can objectively show) that the models are simpler and easier to understand with our system - but we’re still working on a solid set of Netlogo → Agents.jl examples and documentation.

2 Likes

Hi @Libbum ,

Sorry I am posting this after quite some time. But I am wondering using your approach (properties = (resc = RescAgent[], other_property = 7.5) ), if I am able to add more than one RescAgent as a property, is this possible?.

Let me try to clarify a little about the model I am trying to recreate. Its medical response model for a volcanic disaster scenario. So the idea is to have rescuers RescAgent sent from medical facilities to rescue casualties, CasAgent and bring them back for treatment. Each rescuer rescues multiple casualties at the impact zone (usually 2) before bringing them to medical facility for treatment and then return back to the impact zone for further rescuing of remaining casualties. (In case you want to find more info - https://github.com/imantha-das/CRTT).

I am hoping to create a more generalised model which removes the geospatial elements but represents the other aspects of the model (rescue process, queuing at medical hospital etc.).

Hey @imantha,

The RescAgent[] syntax is a short form of creating an empty Vector{RescAgent}. So you can do

r1 = RescAgent(1, true, [])
r2 = RescAgent(2, true, [])

push!(model.resc, r1)
push!(model.resc, r2)

model.resc[1] #r1
model.resc[2] #r2

Model properties can be a tuple like this example, or a Dict or a Struct, so feel free to align this however you like.

properties = Dict(:r1 => RescAgent(1, true, []), :r2 => RescAgent(2, true, []))
#...
model.r1
model.r2
1 Like