ABMEv_Agent.jl 6.03 KB
Newer Older
Victor's avatar
Victor committed
1
2
3
4
abstract type Ancestors{T} end
abstract type Rates{T} end
hasancestors(::Type{Ancestors{T}}) where {T} = T #not sure we need it
hasrates(::Type{Rates{T}}) where {T} = T # not sure we need it
5

Victor's avatar
Victor committed
6
7
abstract type AbstractAgent{A<:Ancestors,R<:Rates} end # tc for time contingency, fit for fitness coeff
AbstractAgentM = Union{Missing,AbstractAgent}
8
9
10
11

"""
$(TYPEDEF)
"""
Victor's avatar
Victor committed
12
mutable struct Agent{A<:Ancestors,R<:Rates,T,U,V} <: AbstractAgent{A,R}
13
    # history of traits for geotraits
Victor's avatar
Victor committed
14
    pos::Array{T,1}
15
    # birth time of ancestors
Victor's avatar
Victor committed
16
    t_history::Array{U,1}
17
    # death rate
Victor's avatar
Victor committed
18
    d::V
19
    #birth rate
Victor's avatar
Victor committed
20
    b::V
21
22
end

Victor's avatar
Victor committed
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# infers position type and zeros
function initpos(s::S) where {S<:AbstractSpacesTuple}
    Eltype = eltype.(s)
    Dims = ndims.(s)
    pos = tuple()
    for i in 1:length(Eltype)
        if Dims[i] > 1
            pos = (pos...,tuple(zeros(Eltype[i],Dims[i])...))
        else
            pos = (pos...,zero(Eltype[i]))
        end
    end
    Tuple{Eltype...},pos
end

function Agent(s::S;ancestors=false,rates=false) where {S  <: AbstractSpacesTuple}
    T,pos = initpos(s)
    t = ancestors ? [Float64(.0)] : [nothing]
    U =  ancestors ? Float64 : Nothing
    d = rates ?  Float64(.0) : nothing
    b = d
    V = rates ?  Float64 : Nothing
    Agent{Ancestors{ancestors},Rates{rates},T,U,V}([pos],t,d,b)
end

# here pos is provided
function Agent(s::S, pos::P;ancestors=false,rates=false) where {P,S  <: AbstractSpacesTuple}
    T = Tuple{eltype.(s)...}
    if !(T <: P)
        throw(ArgumentError("Position provided does not match with underlying space"))
    end
    t = ancestors ? Float64(.0) : [nothing]
    U =  ancestors ? Float64 : Nothing
    d = rates ?  Float64(.0) : nothing
    b = d
    V = rates ?  Float64 : Nothing
    Agent{Ancestors{ancestors},Rates{rates},T,U,V}([pos],t,d,b)
end
61

Victor's avatar
Victor committed
62
# TODO : implement pretty print
63
64

import Base.copy
Victor's avatar
Victor committed
65
copy(a::Agent{A,R,T,U,V}) where {A,R,T,U,V} = Agent{A,R,T,U,V}(copy(a.pos),copy(a.t_history),copy(a.d),copy(a.b))
66
copy(m::Missing) = missing
Victor's avatar
Victor committed
67
copy(n::Nothing) = nothing
68

Victor's avatar
Victor committed
69
70
71
72
#####################
###Agent accessors###
#####################

73
"""
Victor's avatar
Victor committed
74
75
    get_x(a::Agent)
Returns trait i of the agent
76
"""
Victor's avatar
Victor committed
77
get_x(a::AbstractAgent) = a.x_history[end]
Victor's avatar
Victor committed
78
79
80
81
82

"""
    function get_geo(a::Agent{U,T},t::Number) where {U,T}
Returns geotrait of agent `a` at time `t`
"""
Victor's avatar
Victor committed
83
84
function get_geo(a::Agent{Ancestors{true},R,T,U,V},t::Number) where {R,T,U,V}
    tarray = vcat(a.t_history[2:end],convert(U,t))
85
86
87
88
    tarray .-= a.t_history
    return sum(get_xhist(a,1) .* tarray)
end
# This method can acces geotrait, while the second not
Victor's avatar
Victor committed
89
90
91
92
93
94
"""
    get_x(a::Agent,t::Number,i::Integer)
Returns trait `i` of the agent.
Geotrait corresponds to dimension `i=0`.
"""

Victor's avatar
Victor committed
95
96
get_x(a::AbstractAgent,t::Number,i::Integer) = i > 0 ? a.x_history[end][Int(i)] : get_geo(a,t)
get_x(a::AbstractAgent,i::Integer) = a.x_history[end][Int(i)]
Victor's avatar
Victor committed
97
98
99
100
"""
    get_t(a::Agent) = a.t_history[end]
Get time when agent born.
"""
Victor's avatar
Victor committed
101
get_t(a::AbstractAgent) = a.t_history[end]
102
103
get_xhist(a::Agent,i::Number) = a.x_history[Int(i),:]
get_xhist(a::Agent) = a.x_history
104
get_thist(a::Agent) = a.t_history
105
106
107
get_d(a::Agent) = a.d
get_b(a::Agent) = a.b
get_fitness(a::Agent) = a.b - a.d
108
109
get_dim(a::Agent) = size(a.x_history,1)
get_nancestors(a::Agent) = size(a.x_history,2)
110

Victor's avatar
Victor committed
111
112
113
114
115
116
117
#####################
###World accessors###
#####################
"""
    get_x(world::Array{T},trait::Integer) where {T <: Agent}
Get x of world without geotrait.
"""
118
get_x(world::Array{T},trait::Integer) where {T <: Agent} = trait > 0 ? reshape(hcat(get_x.(world,trait)),size(world,1),size(world,2)) : throw(ErrorException("Not the right method, need `t` as an argument"))
119
"""
120
    get_x(world::Array{T},t::Number,trait::Integer) where {T <: Agent}
121
Returns trait of every agents of world in the form of an array which dimensions corresponds to the input.
Victor's avatar
Victor committed
122
If `trait = 0` , we return the geotrait.
123
"""
124
get_x(world::Array{T},t::Number,trait::Integer) where {T <: Agent} = trait > 0 ? reshape(hcat(get_x.(world,trait)),size(world,1),size(world,2)) : reshape(hcat(get_geo.(world,t)),size(world,1),size(world,2))
125

126
"""
Victor's avatar
Victor committed
127
    function get_xarray(world::Array{T,1}) where {T <: Agent}
128
129
Returns every traits of every agents of world in the form of an array
"""
130
131
132
function get_xarray(world::Array{T,1}) where {T <: Agent}
    return hcat(get_x.(world)...)
end
Victor's avatar
Victor committed
133
134
135
136
137
138
"""
    function get_xarray(world::Array{T,1},t::Number,geotrait::Bool=false) where {T <: Agent}
Returns every traits of every agents of `world` in the form **of a one dimensional array** (in contrast to `get_x`).
If `geotrait=true` the geotrait is also added to the set of trait, in the last line.
If you do not want to specify `t` (only useful for geotrait), it is also possible to use `get_xarray(world::Array{T,1}) where {T <: Agent}`.
"""
139
function get_xarray(world::Array{T,1},t::Number,geotrait::Bool=false) where {T <: Agent}
140
141
    xarray = hcat(get_x.(world)...)
    if geotrait
142
        xarray = vcat( xarray, get_geo.(world,t)')
143
    end
Victor's avatar
Victor committed
144
    return xarray
145
146
end

Victor's avatar
Victor committed
147
148
149
150
151
152
## Modifiers
"""
    function increment_x!(a::Agent{StdAgent,U},t::U,p::Dict) where U
This function increments agent by random numbers specified in p
ONLY FOR CONTINUOUS DOMAINS
"""
153
function increment_x!(a::AbstractAgent{A,R},s::AbstractSpacesTuple,p::Dict{String,Any},t::T) where {A<:Ancestors{true},R,T}
Victor's avatar
Victor committed
154
155
156
157
158
159
160
    @unpack D,mu = p
    _x = get_x(a)
    inc = similar(_x)
    for (i,s) in enumerate(ss)
        if rand() < mu[i]
            inc[i] = get_inc.(_x[i],D[i],s)
        end
161
    end
Victor's avatar
Victor committed
162
163
    push!(a.t_history,t)
    a.x_history = push!(a.x_history, _x + inc);
164
165
end

166
function increment_x!(a::AbstractAgent{A,R},s::AbstractSpacesTuple,p::Dict{String,Any},t::T) where {A<:Ancestors{false},R,T}
Victor's avatar
Victor committed
167
168
169
170
171
    @unpack D,mu = p
    _x = get_x(a)
    inc = get_inc.(_x,D,s)
    a.t_history = [t]
    a.x_history = [_x + inc];
172
173
end

174
"""
175
    function tin(t::Number,a::Number,b::Number)
176
177
178
if t in [a,b) returns 1. else returns 0
"""

179
function tin(t::Number,a::Number,b::Number)
180
181
182
183
184
185
186
187
188
189
    return t>=a && t<b ? 1. : 0.
end

function split_move(t)
    return .0 + 1/100*(t-20.)*tin(t,20.,120.) + tin(t,120.,Inf64)
end

function split_merge_move(t)
    return .0 + 1/30*(t-10.)*tin(t,10.,40.) + tin(t,40.,70.) + (1- 1/30*(t-70.))*tin(t,70.,100.)
end