从示例连续空间社交距离开始,我尝试创建一个模型,该模型涉及将每对附近的代理合并为具有其他属性的不同类型的代理。
using Agents
@agent struct Single(ContinuousAgent{2, Float64})
mass :: Float64
propertyA :: Integer
end
@agent struct Double(ContinuousAgent{2, Float64})
mass :: Float64
propertyB :: Float64
propertyC :: Integer
end
using Random
agent_step!(agent, model) = move_agent!(agent, model, model.dt)
function merge_agents!(a1, a2, model)
new_mass = a1.mass + a2.mass
new_pos = ((a1.pos[1]+a2.pos[1])/2.0, (a1.pos[2]+a2.pos[2])/2.0)
new_vel = sincos(2π * rand(abmrng(model))) .* 0.0
add_agent!(Double, model; pos = new_pos, vel = new_vel, mass = new_mass, propertyB = 20.0, propertyC = 5)
remove_agent!(a1, model)
remove_agent!(a2, model)
end
function model_step!(model)
for (a1, a2) in interacting_pairs(model, 0.01, :nearest)
if isa(a1, Single) && isa(a2, Single)
merge_agents!(a1, a2, model)
end
end
end
function ball_model(; speed = 0.002)
space2d = ContinuousSpace((1, 1); spacing = 0.02)
model = StandardABM(Union{Single, Double}, space2d; agent_step!, model_step!, properties = Dict(:dt => 1.0),rng = MersenneTwister(42))
for ind in 1:100
new_pos = Tuple(rand(abmrng(model), 2))
new_vel = sincos(2π * rand(abmrng(model))) .* speed
add_agent!(Single, model; pos = new_pos, vel = new_vel, mass = 1.0, propertyA = 10)
end
return model
end
model = ball_model()
using CairoMakie
abmvideo(
"mergingAgents-Union.mp4",
model;
title = "Merging agents (Union)",
frames = 500,
dt = 1,
framerate = 25,
agent_size = agent -> isa(agent, Double) ? 20 : 10,
agent_color = agent -> isa(agent, Double) ? :blue : :green
)
上面的代码可以按预期工作。
但是,我看到Agents.jl文档建议使用
@multiagent
而不是Union
,所以我尝试相应地调整代码:
using Agents
@agent struct Single(ContinuousAgent{2, Float64})
mass :: Float64
propertyA :: Integer
end
@agent struct Double(ContinuousAgent{2, Float64})
mass :: Float64
propertyB :: Float64
propertyC :: Integer
end
@multiagent Nucleus(Single, Double) <: AbstractAgent
using Random
agent_step!(agent, model) = move_agent!(agent, model, model.dt)
function merge_agents!(a1, a2, model)
new_mass = a1.mass + a2.mass
new_pos = ((a1.pos[1]+a2.pos[1])/2.0, (a1.pos[2]+a2.pos[2])/2.0)
new_vel = sincos(2π * rand(abmrng(model))) .* 0.0
new_agent = Nucleus(Double(model, new_pos, new_vel, new_mass, 20.0, 5))
add_agent!(new_agent, model)
remove_agent!(a1, model)
remove_agent!(a2, model)
end
function model_step!(model)
for (a1, a2) in interacting_pairs(model, 0.01, :nearest)
if isa(a1, Single) && isa(a2, Single)
merge_agents!(a1, a2, model)
end
end
end
function ball_model(; speed = 0.002)
space2d = ContinuousSpace((1, 1); spacing = 0.02)
model = StandardABM(Nucleus, space2d; agent_step!, model_step!, properties = Dict(:dt => 1.0),rng = MersenneTwister(42))
for ind in 1:100
new_pos = Tuple(rand(abmrng(model), 2))
new_vel = sincos(2π * rand(abmrng(model))) .* speed
new_agent = Nucleus(Single(model, new_pos, new_vel, 1.0, 10))
add_agent_own_pos!(new_agent, model)
end
return model
end
model = ball_model()
using CairoMakie
abmvideo(
"mergingAgents-multiagent.mp4",
model;
title = "Merging agents (multiagent)",
frames = 500,
dt = 1,
framerate = 25,
agent_size = agent -> isa(agent, Double) ? 20 : 10,
agent_color = agent -> isa(agent, Double) ? :blue : :green
)
现在,代理不再合并了。
我做错了什么?
Agents.@multiagent
(当前为 v6.1)文档说
@multiagent YourAgentType(AgentTypesToMerge...) [<: OptionalSupertype]
定义多个代理“子类型”,它们是唯一类型 YourAgentType 的变体。这意味着所有“子类型”都包含在总体类型中。那么,你就无法根据
来区分它们,而需要使用typeof
函数来代替。 [...]variantof
检索代理变量的方法是通过函数
。 [...]variantof
您还可以使用
函数访问随附的变体实例。 [...]variant
使用用
Nucleus
包裹 Single
或 Double
构建的代理,问题在于像 isa(anAgent, Single)
和 isa(anAgent, Double)
这样的表达式是错误的。
anAgent = Nucleus(Single(id=-1; pos=[-2.0,-3.0], vel=[-0.2,-0.3], mass=-4.0, propertyA=-5))
typeof(anAgent) # Nucleus
isa(anAgent, Nucleus) # true
isa(anAgent, Single) # false
解决方案是用
Nucleus
或 variant(anAgent)
打开 variantof(anAgent)
。
isa(variant(anAgent), Single) # true
variantof(anAgent) == Single # true
例如
function model_step!(model)
for (a1, a2) in interacting_pairs(model, 0.01, :nearest)
if isa(variant(a1), Single) && isa(variant(a2), Single) # modified
merge_agents!(a1, a2, model)
end
end
end
abmvideo(
"mergingAgents-multiagent.mp4",
model;
title = "Merging agents (multiagent)",
frames = 500,
dt = 1,
framerate = 25,
agent_size = agent -> isa(variant(agent), Double) ? 20 : 10, # modified
agent_color = agent -> isa(variant(agent), Double) ? :blue : :green # modified
)