Skip to content

Commit

Permalink
Update multiagent vs. union performance docs for Julia 1.11 (#1091)
Browse files Browse the repository at this point in the history
* Update multiagent vs. union performance docs for Julia 1.11

* Update performance_tips.md

* Update performance_tips.md

* Update performance_tips.md

* Update multiagent_vs_union.jl

* Update performance_tips.md

* Update performance_tips.md

* Update Project.toml

* Update Project.toml

---------

Co-authored-by: George Datseris <[email protected]>
  • Loading branch information
Tortar and Datseris authored Dec 3, 2024
1 parent b7d6824 commit bde1251
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 25 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Agents"
uuid = "46ada45e-f475-11e8-01d0-f70cc89e6671"
authors = ["George Datseris", "Tim DuBois", "Aayush Sabharwal", "Ali Vahdati", "Adriano Meligrana"]
version = "6.1.11"
version = "6.1.12"

[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
Expand Down
14 changes: 5 additions & 9 deletions docs/src/performance_tips.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,7 @@ t = joinpath(dirname(dirname(x)), "test", "performance", "variable_agent_types_s
include(t)
```

We see that Unions of up to three different Agent types do not suffer much.
Hence, if you have less than four agent types in your model, using different types is still a valid option.
For more agent types however we recommend using the [`@multiagent`](@ref) macro.

Finally, we also have a more realistic benchmark of the two approaches at `test/performance/multiagent_vs_union.jl` where the
result of running the model with the two methodologies are
Finally, we also have a more realistic benchmark of the two approaches at [`test/performance/multiagent_vs_union.jl`](https://github.com/JuliaDynamics/Agents.jl/blob/main/test/performance/multiagent_vs_union.jl) where each type has a different set of behaviours, unlike in the previous benchmark. The result of running the model with the two methodologies are

```@example performance_2
using Agents
Expand All @@ -148,7 +143,8 @@ t = joinpath(dirname(dirname(x)), "test", "performance", "multiagent_vs_union.jl
include(t)
```

In reality, we benchmarked the models also in Julia>=1.11 and from that version on a `Union` is considerably
more performant. Though, there is still a general 1.5-2x advantage in many cases in favour of [`@multiagent`](@ref),
so we suggest to use [`@multiagent`](@ref) only when the speed of the multi-agent simulation is really critical.
As you can see, [`@multiagent`](@ref) has the edge over a `Union`: there is a general 1.5-2x advantage in many cases
in its favour. This is true for Julia>=1.11, where we then suggest to go with [`@multiagent`](@ref) only if the speed of the
simulation is critical. However, keep in mind that on Julia<=1.10 the difference is much bigger: [`@multiagent`](@ref)
is almost one order of magnitude faster than a `Union`.

38 changes: 23 additions & 15 deletions test/performance/multiagent_vs_union.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,15 @@ function agent_step!(agent::GridAgentFour, model1)
agent.one += sum(a.one for a in nearby_agents(agent, model1))
end
function agent_step!(agent::GridAgentFive, model1)
targets = filter!(a->a.one > 1.0, collect(types, nearby_agents(agent, model1, 3)))
targets = Iterators.filter(a->a.one > 1.0, nearby_agents(agent, model1, 3))
if !isempty(targets)
idx = argmax(map(t->euclidean_distance(agent, t, model1), targets))
farthest = targets[idx]
walk!(agent, sign.(farthest.pos .- agent.pos), model1)
farthest = 0.0
a = first(targets)
for t in targets
d = euclidean_distance(agent, t, model1)
d > farthest && (a, farthest = t, d)
end
walk!(agent, sign.(a.pos .- agent.pos), model1)
end
end
function agent_step!(agent::GridAgentSix, model1)
Expand All @@ -93,31 +97,35 @@ end

################### DEFINITION 2 ###############

@inline agent_step!(agent, model2) = agent_step!(agent, model2, variant(agent))
agent_step!(agent, model2) = agent_step!(agent, model2, variant(agent))

@inline agent_step!(agent, model2, ::GridAgentOne) = randomwalk!(agent, model2)
@inline function agent_step!(agent, model2, ::GridAgentTwo)
agent_step!(agent, model2, ::GridAgentOne) = randomwalk!(agent, model2)
function agent_step!(agent, model2, ::GridAgentTwo)
agent.one += rand(abmrng(model2))
agent.two = rand(abmrng(model2), Bool)
end
@inline function agent_step!(agent, model2, ::GridAgentThree)
function agent_step!(agent, model2, ::GridAgentThree)
if any(a-> variant(a) isa GridAgentTwo, nearby_agents(agent, model2))
agent.two = true
randomwalk!(agent, model2)
end
end
@inline function agent_step!(agent, model2, ::GridAgentFour)
function agent_step!(agent, model2, ::GridAgentFour)
agent.one += sum(a.one for a in nearby_agents(agent, model2))
end
@inline function agent_step!(agent, model2, ::GridAgentFive)
targets = filter!(a->a.one > 1.0, collect(GridAgentAll, nearby_agents(agent, model2, 3)))
function agent_step!(agent, model2, ::GridAgentFive)
targets = Iterators.filter(a->a.one > 1.0, nearby_agents(agent, model2, 3))
if !isempty(targets)
idx = argmax(map(t->euclidean_distance(agent, t, model2), targets))
farthest = targets[idx]
walk!(agent, sign.(farthest.pos .- agent.pos), model2)
farthest = 0.0
a = first(targets)
for t in targets
d = euclidean_distance(agent, t, model2)
d > farthest && (a, farthest = t, d)
end
walk!(agent, sign.(a.pos .- agent.pos), model2)
end
end
@inline function agent_step!(agent, model2, ::GridAgentSix)
function agent_step!(agent, model2, ::GridAgentSix)
agent.eight += sum(rand(abmrng(model2), (0, 1)) for a in nearby_agents(agent, model2))
end

Expand Down

0 comments on commit bde1251

Please sign in to comment.