Closed drdozer closed 3 years ago
We are working on removing this methodology from our codebase due to the inherent performance issues we face at scale, so we've moved our examples away from this pattern. For small systems the issue isn't that noticeable though.
https://github.com/JuliaDynamics/Agents.jl/blob/master/examples/predator_prey_multiagent.jl
Is still around, but not listed. So feel free to take a look through that.
Thanks @Libbum. I think perhaps not all of the example text has been fully copy-edited. In my situation I'm wanting to build a very simplified model of a game to explore speedrun strategies. Here there are at least 4 very different kinds of agents - the player, the tech tree, and two different categories of entities the player can interact with. Will I still hit performance issues if I encode my distinctive behaviours into different structs, but them wrap them in a union field, or group them with an abstract type in a single agent struct? So something like:
abstract type AgentType end
struct Player <: AgentType end
struct TechTree <: AgentType end
struct Machine1 <: AgentType end
struct Machine2 <: AgentType end
struct SpeedrunAgent <: AbstractAgent
id::Int
pos::NTuple{2,Int}
agent_type::AgentType
end
# dispatch on the agent type
step!(model, agent) = step!(model, agent, agent.agent_type)
I honestly don't think performance is likely to be my primary concern, but I would prefer to use agents in the way it is intended.
This would still dispatch dynamically, since the value of the agent_type
field is only known at runtime. It would have the same/similar performance issues as non-concrete agent types. However, this really wouldn't be as noticeable until you scale it up.
If you still want to avoid dynamic dispatch, you can turn agent_type
into a Symbol
field, and do something similar to predator-prey.
Since the version I linked to is not in our documentation it is no longer updated and may indeed fail on recent versions. The concept is there though.
As Aayush points out, there's no need to go through that process, using a union type is sufficient.
@agent Player GridAgent{2} begin
# ...
end
@agent TechTree GridAgent{2} begin
# ...
end
@agent MachineOne GridAgent{2} begin
# ...
end
@agent MachineTwo GridAgent{2} begin
# ...
end
space = GridSpace((100, 100))
model = ABM(Union{Player, TechTree, MachineOne, MachineTwo}, space)
agent_step!(agent::Player, model) = # ...
agent_step!(agent::TechTree, model) = # ...
agent_step!(agent::MachineOne, model) = # ...
agent_step!(agent::MachineTwo, model) = # ...
Is the template you should start with.
@Libbum I hadn't even considered using a union type. I'm still very new to julia, so often don't see the obvious. thanks :D
The agents API appears to support models where agents come from more than one struct. However, there are no examples of this in the examples. All of them model agents using a single struct with some field to switch behaviour. Would it be possible to have an example where there is more than one kind of agent which requires more than one struct to model?