Skip to content

Commit

Permalink
Apply style to src
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobusmmsmit committed Mar 9, 2023
1 parent 14d869a commit 6c080da
Show file tree
Hide file tree
Showing 34 changed files with 533 additions and 562 deletions.
50 changes: 25 additions & 25 deletions src/Agents.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,35 +49,35 @@ include("deprecations.jl")
using Scratch

function __init__()
display_update = true
version_number = "5.7"
update_name = "update_v$(version_number)"
update_message = """
Update message: Agents v$(version_number)
Welcome to this new update of Agents.jl!
display_update = true
version_number = "5.7"
update_name = "update_v$(version_number)"
update_message = """
Update message: Agents v$(version_number)
Welcome to this new update of Agents.jl!
Noteworthy changes:
Noteworthy changes:
- Internals of `AgentBasedModel` got reworked.
It is now an abstract type, defining an abstract interface that concrete
implementations may satisfy. This paves the way for flexibly defining new
variants of `AgentBasedModel` that are more specialized in their applications.
- The old `AgentBasedModel` is now `StandardABM`
Nothing is breaking because the call to `AgentBasedModel` gives `StandardABM`.
- Two new variants of agent based models: `UnkillableABM` and `FixedMassABM`.
They yield huge performance benefits **(up to twice the speed!!!)**
on iterating over agents if the agents can't get killed, or even added,
during model evolution!
"""
- Internals of `AgentBasedModel` got reworked.
It is now an abstract type, defining an abstract interface that concrete
implementations may satisfy. This paves the way for flexibly defining new
variants of `AgentBasedModel` that are more specialized in their applications.
- The old `AgentBasedModel` is now `StandardABM`
Nothing is breaking because the call to `AgentBasedModel` gives `StandardABM`.
- Two new variants of agent based models: `UnkillableABM` and `FixedMassABM`.
They yield huge performance benefits **(up to twice the speed!!!)**
on iterating over agents if the agents can't get killed, or even added,
during model evolution!
"""

if display_update
# Get scratch space for this package
versions_dir = @get_scratch!("versions")
if !isfile(joinpath(versions_dir, update_name))
printstyled(stdout, "\n"*update_message; color=:light_magenta)
touch(joinpath(versions_dir, update_name))
if display_update
# Get scratch space for this package
versions_dir = @get_scratch!("versions")
if !isfile(joinpath(versions_dir, update_name))
printstyled(stdout, "\n" * update_message; color=:light_magenta)
touch(joinpath(versions_dir, update_name))
end
end
end
end # _init__ function.

end # module
2 changes: 1 addition & 1 deletion src/core/agents.jl
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ macro agent(new_name, base_type, extra_fields)
# `super_type = AbstractAgent`. This requires us to disable 'macro hygiene', see here
# for a brief explanation of the potential issues with this:
# https://discourse.julialang.org/t/calling-a-macro-from-within-a-macro-revisited/19680/16?u=fbanning
esc(quote
return esc(quote
Agents.@agent($new_name, $base_type, Agents.AbstractAgent, $extra_fields)
end)
end
Expand Down
6 changes: 3 additions & 3 deletions src/core/higher_order_iteration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ e.g. `(agent1, agent7, agent8)`. `order` must be larger than `1` but has no uppe
Index order is provided by the model scheduler by default,
but can be altered with the `scheduler` keyword.
"""
iter_agent_groups(order::Int, model::ABM; scheduler = model.scheduler) =
iter_agent_groups(order::Int, model::ABM; scheduler=model.scheduler) =
Iterators.product((map(i -> model[i], scheduler(model)) for _ in 1:order)...)

"""
Expand All @@ -38,7 +38,7 @@ map_agent_groups(order::Int, f::Function, model::ABM, filter::Function; kwargs..
index_mapped_groups(order::Int, model::ABM, filter::Function; scheduler = Schedulers.by_id)
Return an iterable of agent ids in the model, meeting the `filter` criteria if used.
"""
index_mapped_groups(order::Int, model::ABM; scheduler = Schedulers.by_id) =
index_mapped_groups(order::Int, model::ABM; scheduler=Schedulers.by_id) =
Iterators.product((scheduler(model) for _ in 1:order)...)
index_mapped_groups(order::Int, model::ABM, filter::Function; scheduler = Schedulers.by_id) =
index_mapped_groups(order::Int, model::ABM, filter::Function; scheduler=Schedulers.by_id) =
Iterators.filter(filter, Iterators.product((scheduler(model) for _ in 1:order)...))
18 changes: 8 additions & 10 deletions src/core/model_abstract.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ ValidPos = Union{
Int, # graph
NTuple{N,Int}, # grid
NTuple{M,<:AbstractFloat}, # continuous
Tuple{Int,Int,Float64} # osm
Tuple{Int,Int,Float64}, # osm
} where {N,M}


"""
AgentBasedModel
Expand Down Expand Up @@ -81,12 +80,12 @@ Here we the most important information on how to query an instance of `AgentBase
Many more functions exist in the API page, such as [`allagents`](@ref).
"""
abstract type AgentBasedModel{S<:SpaceType, A<:AbstractAgent} end
abstract type AgentBasedModel{S<:SpaceType,A<:AbstractAgent} end
const ABM = AgentBasedModel

function notimplemented(model)
error("Function not implemented for model of type $(nameof(typeof(model))) "*
"with space type $(nameof(typeof(abmspace(model))))")
return error("Function not implemented for model of type $(nameof(typeof(model))) " *
"with space type $(nameof(typeof(abmspace(model))))")
end

###########################################################################################
Expand Down Expand Up @@ -180,7 +179,7 @@ function allocating_random_agent(model, condition)
return nothing
end

function optimistic_random_agent(model, condition; n_attempts = 3*nagents(model))
function optimistic_random_agent(model, condition; n_attempts=3 * nagents(model))
rng = abmrng(model)
for _ in 1:n_attempts
idx = rand(rng, allids(model))
Expand Down Expand Up @@ -240,7 +239,6 @@ function Base.setproperty!(m::ABM, s::Symbol, x)
end
end


###########################################################################################
# %% Non-public methods. Must be implemented but are not exported
###########################################################################################
Expand Down Expand Up @@ -268,6 +266,6 @@ Return the space instance stored in the `model`.
abmspace(model::ABM) = getfield(model, :space)

function Base.setindex!(m::ABM, args...; kwargs...)
error("`setindex!` or `model[id] = agent` are invalid. Use `add_agent!(model, agent)` "*
"or other variants of an `add_agent_...` function to add agents to an ABM.")
end
return error("`setindex!` or `model[id] = agent` are invalid. Use `add_agent!(model, agent)` " *
"or other variants of an `add_agent_...` function to add agents to an ABM.")
end
56 changes: 29 additions & 27 deletions src/core/model_concrete.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export ABM, StandardABM, UnkillableABM, FixedMassABM
using StaticArrays: SizedVector

ContainerType{A} = Union{AbstractDict{Int,A}, AbstractVector{A}}
ContainerType{A} = Union{AbstractDict{Int,A},AbstractVector{A}}

# And the three implementations here are just variants with different `C` type.
struct SingleContainerABM{S<:SpaceType,A<:AbstractAgent,C<:ContainerType{A},F,P,R<:AbstractRNG} <: AgentBasedModel{S,A}
Expand Down Expand Up @@ -39,12 +39,12 @@ single container. Offers the variants:
"""
function SingleContainerABM(
::Type{A},
space::S = nothing;
container::Type = Dict{Int},
scheduler::F = Schedulers.fastest,
properties::P = nothing,
rng::R = Random.default_rng(),
warn = true
space::S=nothing;
container::Type=Dict{Int},
scheduler::F=Schedulers.fastest,
properties::P=nothing,
rng::R=Random.default_rng(),
warn=true,
) where {A<:AbstractAgent,S<:SpaceType,F,P,R<:AbstractRNG}
agent_validator(A, space, warn)
C = construct_agent_container(container, A)
Expand All @@ -59,7 +59,7 @@ end
construct_agent_container(::Type{<:Dict}, A) = Dict{Int,A}
construct_agent_container(::Type{<:Vector}, A) = Vector{A}
construct_agent_container(container, A) = throw(
"Unrecognised container $container, please specify either Dict or Vector."
"Unrecognised container $container, please specify either Dict or Vector.",
)

"""
Expand Down Expand Up @@ -101,13 +101,13 @@ in the given `agent_vector`.
"""
function FixedMassABM(
agents::AbstractVector{A},
space::S = nothing;
scheduler::F = Schedulers.fastest,
properties::P = nothing,
rng::R = Random.default_rng(),
warn = true
) where {A<:AbstractAgent, S<:SpaceType,F,P,R<:AbstractRNG}
C = SizedVector{length(agents), A}
space::S=nothing;
scheduler::F=Schedulers.fastest,
properties::P=nothing,
rng::R=Random.default_rng(),
warn=true,
) where {A<:AbstractAgent,S<:SpaceType,F,P,R<:AbstractRNG}
C = SizedVector{length(agents),A}
fixed_agents = C(agents)
# Validate that agent ID is the same as its order in the vector.
for (i, a) in enumerate(agents)
Expand All @@ -120,11 +120,11 @@ end
#######################################################################################
# %% Model accessing api
#######################################################################################
nextid(model::SingleContainerABM{<:SpaceType,A,Dict{Int, A}}) where {A} = getfield(model, :maxid)[] + 1
nextid(model::SingleContainerABM{<:SpaceType,A,Dict{Int,A}}) where {A} = getfield(model, :maxid)[] + 1
nextid(model::SingleContainerABM{<:SpaceType,A,Vector{A}}) where {A} = nagents(model) + 1
nextid(::SingleContainerABM{<:SpaceType,A,<:SizedVector}) where {A} = error("There is no `nextid` in a `FixedMassABM`. Most likely an internal error.")

function add_agent_to_model!(agent, model::SingleContainerABM{<:SpaceType,A,Dict{Int, A}}) where {A<:AbstractAgent}
function add_agent_to_model!(agent, model::SingleContainerABM{<:SpaceType,A,Dict{Int,A}}) where {A<:AbstractAgent}
if haskey(agent_container(model), agent.id)
error("Can't add agent to model. There is already an agent with id=$(agent.id)")
else
Expand All @@ -133,7 +133,9 @@ function add_agent_to_model!(agent, model::SingleContainerABM{<:SpaceType,A,Dict
# Only the `Dict` implementation actually uses the `maxid` field.
# The `Vector` one uses the defaults, and the `Sized` one errors anyways.
maxid = getfield(model, :maxid)
if maxid[] < agent.id; maxid[] = agent.id; end
if maxid[] < agent.id
maxid[] = agent.id
end
return
end

Expand All @@ -144,12 +146,12 @@ function add_agent_to_model!(agent, model::SingleContainerABM{<:SpaceType,A,Vect
end

function remove_agent_from_model!(agent::A, model::SingleContainerABM{<:SpaceType,A,<:AbstractDict{Int,A}}) where {A<:AbstractAgent}
delete!(agent_container(model), agent.id)
return delete!(agent_container(model), agent.id)
end
function remove_agent_from_model!(::A, model::SingleContainerABM{<:SpaceType,A,<:AbstractVector}) where {A<:AbstractAgent}
error(
"Cannot remove agents stored in $(containertype(model)). "*
"Use the vanilla `SingleContainerABM` to be able to remove agents."
return error(
"Cannot remove agents stored in $(containertype(model)). " *
"Use the vanilla `SingleContainerABM` to be able to remove agents.",
)
end

Expand Down Expand Up @@ -188,18 +190,18 @@ end
do_checks(agent, space)
Helper function for `agent_validator`.
"""
function do_checks(::Type{A}, space::S, warn::Bool) where {A<:AbstractAgent, S<:SpaceType}
function do_checks(::Type{A}, space::S, warn::Bool) where {A<:AbstractAgent,S<:SpaceType}
if warn
isbitstype(A) &&
@warn "Agent type is not mutable, and most library functions assume that it is."
@warn "Agent type is not mutable, and most library functions assume that it is."
end
(any(isequal(:id), fieldnames(A)) && fieldnames(A)[1] == :id) ||
throw(ArgumentError("First field of agent type must be `id` (and should be of type `Int`)."))
throw(ArgumentError("First field of agent type must be `id` (and should be of type `Int`)."))
fieldtype(A, :id) <: Integer ||
throw(ArgumentError("`id` field in agent type must be of type `Int`."))
throw(ArgumentError("`id` field in agent type must be of type `Int`."))
if space !== nothing
(any(isequal(:pos), fieldnames(A)) && fieldnames(A)[2] == :pos) ||
throw(ArgumentError("Second field of agent type must be `pos` when using a space."))
throw(ArgumentError("Second field of agent type must be `pos` when using a space."))
# Check `pos` field in A has the correct type
pos_type = fieldtype(A, :pos)
space_type = typeof(space)
Expand Down
Loading

0 comments on commit 6c080da

Please sign in to comment.