Skip to content

Commit 6707135

Browse files
simsuraceTortar
andauthored
Remove ValidPos type (#1093)
--------- Co-authored-by: Adriano Meligrana <[email protected]>
1 parent 79e70cf commit 6707135

17 files changed

+85
-80
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "Agents"
22
uuid = "46ada45e-f475-11e8-01d0-f70cc89e6671"
33
authors = ["George Datseris", "Tim DuBois", "Aayush Sabharwal", "Ali Vahdati", "Adriano Meligrana"]
4-
version = "6.1.9"
4+
version = "6.1.10"
55

66
[deps]
77
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"

docs/src/devdocs.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ Creating a new space type within Agents.jl is quite simple and requires the exte
5353

5454
In principle, the following should be done:
5555

56-
1. Think about what the agent position type should be. Add this type to the `ValidPos` union type in `src/core/model_abstract.jl`.
57-
1. Think about how the space type will keep track of the agent positions, so that it is possible to implement the function [`nearby_ids`](@ref).
58-
1. Implement the `struct` that represents your new space, while making it a subtype of `AbstractSpace`.
59-
1. Extend `random_position(model)`.
60-
1. Extend `add_agent_to_space!(agent, model), remove_agent_from_space!(agent, model)`. This already provides access to `add_agent!, kill_agent!` and `move_agent!`.
61-
1. Extend `nearby_ids(pos, model, r)`.
62-
1. Create a new "minimal" agent type to be used with [`@agent`](@ref) (see the source code of [`GraphAgent`](@ref) for an example).
56+
1. Think about what the agent position type should be.
57+
2. Think about how the space type will keep track of the agent positions, so that it is possible to implement the function [`nearby_ids`](@ref).
58+
3. Implement the `struct` that represents your new space, while making it a subtype of `AbstractSpace`.
59+
4. Extend `random_position(model)`.
60+
5. Extend `add_agent_to_space!(agent, model), remove_agent_from_space!(agent, model)`. This already provides access to `add_agent!, kill_agent!` and `move_agent!`.
61+
6. Extend `nearby_ids(pos, model, r)`.
62+
7. Create a new "minimal" agent type to be used with [`@agent`](@ref) (see the source code of [`GraphAgent`](@ref) for an example).
6363

6464
And that's it! Every function of the main API will now work. In some situations you might want to explicitly extend other functions such as `move_agent!` for performance reasons.
6565

src/Agents.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ include("deprecations.jl")
6666
# visualizations (singleton methods for package extension)
6767
include("visualizations.jl")
6868

69+
include("ambiguities.jl")
70+
6971
include("precompile.jl")
7072

7173
# Update messages:

src/ambiguities.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
# non-functional ambiguity fixes
3+
4+
add_agent!(::AbstractAgent, ::Union{Function, Type}, ::AgentBasedModel, ::Vararg{Any, N}; kwargs...) where N = error()
5+
add_agent!(::AbstractAgent, ::AgentBasedModel, ::AgentBasedModel) = error()
6+
add_agent!(::AgentBasedModel, ::Union{Function, Type}, ::AgentBasedModel, ::Vararg{Any, N}; kwargs...) where N = error()
7+
add_agent!(::AgentBasedModel, ::AgentBasedModel, ::Vararg{Any, N}; kwargs...) where N = error()

src/core/model_abstract.jl

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,6 @@ abstract type AbstractSpace end
1717
abstract type DiscreteSpace <: AbstractSpace end
1818
SpaceType = Union{Nothing, AbstractSpace}
1919

20-
# This is a collection of valid position types, sometimes used for ambiguity resolution
21-
ValidPos = Union{
22-
Int, # graph
23-
NTuple{N,Int}, # grid
24-
NTuple{M,<:AbstractFloat}, # continuous
25-
SVector{M,<:AbstractFloat}, # continuous
26-
Tuple{Int,Int,Float64} # osm
27-
} where {N,M}
28-
2920

3021
"""
3122
AgentBasedModel

src/core/space_interaction_API.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ Move agent to the given position, or to a random one if a position is not given.
124124
125125
The agent's position is updated to match `pos` after the move.
126126
"""
127-
function move_agent!(agent::AbstractAgent, pos::ValidPos, model::ABM)
127+
function move_agent!(agent::AbstractAgent, pos::Any, model::ABM)
128128
remove_agent_from_space!(agent, model)
129129
agent.pos = pos
130130
add_agent_to_space!(agent, model)
@@ -217,7 +217,7 @@ function add_agent!(agent::AbstractAgent, model::ABM)
217217
add_agent_own_pos!(agent, model)
218218
end
219219

220-
function add_agent!(agent::AbstractAgent, pos::ValidPos, model::ABM)
220+
function add_agent!(agent::AbstractAgent, pos::Any, model::ABM)
221221
agent.pos = pos
222222
add_agent_own_pos!(agent, model)
223223
end
@@ -268,7 +268,7 @@ function add_agent!(A::Union{Function, Type}, model::ABM,
268268
end
269269

270270
function add_agent!(
271-
pos::ValidPos,
271+
pos::Any,
272272
model::ABM,
273273
args::Vararg{Any, N};
274274
kwargs...,
@@ -279,7 +279,7 @@ end
279279

280280
# lowest level - actually constructs the agent
281281
function add_agent!(
282-
pos::ValidPos,
282+
pos::Any,
283283
A::Union{Function, Type},
284284
model::ABM,
285285
args::Vararg{Any, N};

src/spaces/continuous.jl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ struct ContinuousSpace{D,P,T<:AbstractFloat,F} <: AbstractSpace
99
spacing::T
1010
extent::SVector{D,T}
1111
end
12-
Base.eltype(s::ContinuousSpace{D,P,T,F}) where {D,P,T,F} = T
12+
const ContinuousPos{D,T} = Union{SVector{D,T},NTuple{D,T}} where {T<:AbstractFloat}
13+
Base.eltype(::ContinuousSpace{D,P,T,F}) where {D,P,T,F} = T
1314
no_vel_update(a, m) = nothing
1415
spacesize(space::ContinuousSpace) = space.extent
1516
function Base.show(io::IO, space::ContinuousSpace{D,P}) where {D,P}
@@ -108,10 +109,10 @@ end
108109

109110
"given position in continuous space, return cell coordinates in grid space."
110111
pos2cell(a::AbstractAgent, model::ABM) = pos2cell(a.pos, model)
111-
pos2cell(pos::ValidPos, model::ABM) = Tuple(max.(1, ceil.(Int, pos./abmspace(model).spacing)))
112+
pos2cell(pos::ContinuousPos, model::ABM) = Tuple(max.(1, ceil.(Int, pos./abmspace(model).spacing)))
112113

113114
"given position in continuous space, return continuous space coordinates of cell center."
114-
function cell_center(pos::ValidPos, model)
115+
function cell_center(pos::ContinuousPos, model)
115116
abmspace(model).spacing .* (pos2cell(pos, model) .- 0.5)
116117
end
117118

@@ -146,7 +147,7 @@ end
146147

147148
# We re-write this for performance, because if cell doesn't change, we don't have to
148149
# move the agent in the GridSpace; only change its position field
149-
function move_agent!(agent::AbstractAgent, pos::ValidPos, model::ABM{<:ContinuousSpace})
150+
function move_agent!(agent::AbstractAgent, pos::ContinuousPos, model::ABM{<:ContinuousSpace})
150151
space_size = spacesize(model)
151152
D = length(space_size)
152153
all(i -> 0 <= pos[i] <= space_size[i], 1:D) || error("position is outside space extent!")
@@ -202,7 +203,7 @@ function offsets_within_radius(model::ABM{<:ContinuousSpace}, r::Real)
202203
return offsets_within_radius(abmspace(model).grid, r)
203204
end
204205

205-
function nearby_ids(pos::ValidPos, model::ABM{<:ContinuousSpace}, r = 1; search = :approximate)
206+
function nearby_ids(pos::ContinuousPos, model::ABM{<:ContinuousSpace}, r = 1; search = :approximate)
206207
if search === :approximate
207208
return nearby_ids_approx(pos, model, r)
208209
elseif search === :exact
@@ -211,7 +212,7 @@ function nearby_ids(pos::ValidPos, model::ABM{<:ContinuousSpace}, r = 1; search
211212
error("`search` keyword should be either `:approximate` or `:exact`")
212213
end
213214

214-
function nearby_ids_approx(pos::ValidPos, model::ABM{<:ContinuousSpace}, r = 1)
215+
function nearby_ids_approx(pos::ContinuousPos, model::ABM{<:ContinuousSpace}, r = 1)
215216
# Calculate maximum grid distance (distance + distance from cell center)
216217
δ = distance_from_cell_center(pos, model)
217218
# Ceiling since we want always to overestimate the radius
@@ -222,7 +223,7 @@ function nearby_ids_approx(pos::ValidPos, model::ABM{<:ContinuousSpace}, r = 1)
222223
return nearby_ids(focal_cell, abmspace(model).grid, grid_r)
223224
end
224225

225-
function nearby_ids_exact(pos::ValidPos, model::ABM{<:ContinuousSpace}, r = 1)
226+
function nearby_ids_exact(pos::ContinuousPos, model::ABM{<:ContinuousSpace}, r = 1)
226227
# TODO:
227228
# Simply filtering nearby_ids_approx leads to 4x faster code than the commented-out logic.
228229
# It is because the code of the "fast logic" is actually super type unstable.

src/spaces/discrete.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ end
7878
isempty(pos, model::ABM{<:DiscreteSpace})
7979
Return `true` if there are no agents in `position`.
8080
"""
81-
Base.isempty(pos::ValidPos, model::ABM{<:DiscreteSpace}) = isempty(pos, abmspace(model))
82-
Base.isempty(pos::ValidPos, space::DiscreteSpace) = isempty(ids_in_position(pos, space))
81+
Base.isempty(pos::Int, model::ABM{<:DiscreteSpace}) = isempty(pos, abmspace(model))
82+
Base.isempty(pos::Int, space::DiscreteSpace) = isempty(ids_in_position(pos, space))
8383

8484
"""
8585
has_empty_positions(model::ABM{<:DiscreteSpace})

src/spaces/grid_general.jl

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export GridAgent
1+
export GridAgent, GridPos
22

33
"""
44
AbstractGridSpace{D,P}
@@ -10,13 +10,15 @@ indices are the possible positions in the space.
1010
Furthermore, all spaces should have at least the fields
1111
* `offsets_within_radius`
1212
* `offsets_within_radius_no_0`
13-
which are `Dict{Float64,Vector{NTuple{D,Int}}}`, mapping radii
13+
which are `Dict{Float64,Vector{GridPos{D}}}`, mapping radii
1414
to vector of indices within each radius.
1515
1616
`D` is the dimension and `P` is whether the space is periodic (boolean).
1717
"""
1818
abstract type AbstractGridSpace{D,P} <: DiscreteSpace end
1919

20+
const GridPos{D} = NTuple{D,Int}
21+
2022
"""
2123
GridAgent{D} <: AbstractAgent
2224
The minimal agent struct for usage with `D`-dimensional [`GridSpace`](@ref).
@@ -176,13 +178,13 @@ end
176178
# utilizes the above `offsets_within_radius_no_0`. We complicated it a bit more because
177179
# we want to be able to re-use it in `ContinuousSpace`, so we allow it to either
178180
# find positions with the 0 or without.
179-
function nearby_positions(pos::ValidPos, model::ABM{<:AbstractGridSpace}, args::Vararg{Any, N}) where {N}
181+
function nearby_positions(pos::GridPos{D}, model::ABM{<:AbstractGridSpace{D}}, args::Vararg{Any,N}) where {D,N}
180182
return nearby_positions(pos, abmspace(model), args...)
181183
end
182184
function nearby_positions(
183-
pos::ValidPos, space::AbstractGridSpace{D,false}, r = 1,
184-
get_indices_f = offsets_within_radius_no_0 # NOT PUBLIC API! For `ContinuousSpace`.
185-
) where {D}
185+
pos::GridPos{D}, space::AbstractGridSpace{D,false}, r=1,
186+
get_indices_f=offsets_within_radius_no_0 # NOT PUBLIC API! For `ContinuousSpace`.
187+
) where {D}
186188
nindices = get_indices_f(space, r)
187189
space_size = spacesize(space)
188190
# check if we are far from the wall to skip bounds checks
@@ -194,9 +196,9 @@ function nearby_positions(
194196
end
195197
end
196198
function nearby_positions(
197-
pos::ValidPos, space::AbstractGridSpace{D,true}, r = 1,
198-
get_indices_f = offsets_within_radius_no_0 # NOT PUBLIC API! For `ContinuousSpace`.
199-
) where {D}
199+
pos::GridPos{D}, space::AbstractGridSpace{D,true}, r=1,
200+
get_indices_f=offsets_within_radius_no_0 # NOT PUBLIC API! For `ContinuousSpace`.
201+
) where {D}
200202
nindices = get_indices_f(space, r)
201203
space_size = spacesize(space)
202204
# check if we are far from the wall to skip bounds checks
@@ -209,8 +211,8 @@ function nearby_positions(
209211
end
210212
end
211213
function nearby_positions(
212-
pos::ValidPos, space::AbstractGridSpace{D,P}, r = 1,
213-
get_indices_f = offsets_within_radius_no_0 # NOT PUBLIC API! For `ContinuousSpace`.
214+
pos::GridPos{D}, space::AbstractGridSpace{D,P}, r=1,
215+
get_indices_f=offsets_within_radius_no_0 # NOT PUBLIC API! For `ContinuousSpace`.
214216
) where {D,P}
215217
stored_ids = space.stored_ids
216218
nindices = get_indices_f(space, r)
@@ -228,7 +230,7 @@ function nearby_positions(
228230
end
229231
end
230232

231-
function random_nearby_position(pos::ValidPos, model::ABM{<:AbstractGridSpace{D,false}}, r=1; kwargs...) where {D}
233+
function random_nearby_position(pos::Any, model::ABM{<:AbstractGridSpace{D,false}}, r=1; kwargs...) where {D}
232234
nindices = offsets_within_radius_no_0(abmspace(model), r)
233235
stored_ids = abmspace(model).stored_ids
234236
rng = abmrng(model)
@@ -239,15 +241,15 @@ function random_nearby_position(pos::ValidPos, model::ABM{<:AbstractGridSpace{D,
239241
end
240242
end
241243

242-
function random_nearby_position(pos::ValidPos, model::ABM{<:AbstractGridSpace{D,true}}, r=1; kwargs...) where {D}
244+
function random_nearby_position(pos::GridPos{D}, model::ABM{<:AbstractGridSpace{D,true}}, r=1; kwargs...) where {D}
243245
nindices = offsets_within_radius_no_0(abmspace(model), r)
244246
stored_ids = abmspace(model).stored_ids
245247
chosen_offset = rand(abmrng(model), nindices)
246248
chosen_pos = pos .+ chosen_offset
247249
checkbounds(Bool, stored_ids, chosen_pos...) && return chosen_pos
248250
return mod1.(chosen_pos, spacesize(model))
249251
end
250-
252+
251253
###################################################################
252254
# pretty printing
253255
###################################################################

src/spaces/grid_multi.jl

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ function remove_agent_from_space!(a::AbstractAgent, model::ABM{<:GridSpace})
101101
return a
102102
end
103103

104+
Base.isempty(pos::GridPos, model::ABM{<:GridSpace}) = isempty(pos, abmspace(model))
105+
Base.isempty(pos::GridPos, space::GridSpace) = isempty(space.stored_ids[pos...])
106+
104107
##########################################################################################
105108
# nearby_stuff for GridSpace
106109
##########################################################################################
@@ -230,17 +233,17 @@ invalid_access_nocheck(pos_index, iter::GridSpaceIdIterator) = @inbounds isempty
230233
# TODO: We can re-write this to create its own `indices_within_radius_tuple`.
231234
# This would also allow it to work for any metric, not just Chebyshev!
232235

233-
function nearby_ids(pos::ValidPos, model::ABM{<:GridSpace}, r::NTuple{D,Int}) where {D}
236+
function nearby_ids(pos::GridPos{D}, model::ABM{<:GridSpace{D}}, r::NTuple{D,Int}) where {D}
234237
# simply transform `r` to the Vector format expected by the below function
235238
newr = [(i, -r[i]:r[i]) for i in 1:D]
236239
nearby_ids(pos, model, newr)
237240
end
238241

239242
function nearby_ids(
240-
pos::ValidPos,
243+
pos::GridPos{D},
241244
model::ABM{<:GridSpace},
242245
r::Vector{Tuple{Int64, UnitRange{Int64}}},
243-
)
246+
) where D
244247
@assert abmspace(model).metric == :chebyshev
245248
dims = first.(r)
246249
vidx = []
@@ -261,7 +264,7 @@ end
261264
#######################################################################################
262265
# %% Further discrete space functions
263266
#######################################################################################
264-
ids_in_position(pos::ValidPos, model::ABM{<:GridSpace}) = ids_in_position(pos, abmspace(model))
265-
function ids_in_position(pos::ValidPos, space::GridSpace)
267+
ids_in_position(pos::GridPos, model::ABM{<:GridSpace}) = ids_in_position(pos, abmspace(model))
268+
function ids_in_position(pos::GridPos, space::GridSpace)
266269
return space.stored_ids[pos...]
267270
end

0 commit comments

Comments
 (0)