ABMEv_Agent.jl 6.96 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
export AbstractAgentM
9
10
11
12

"""
$(TYPEDEF)
"""
13
14
15
16
17
18
19
20
21
22
23
24
25
26
abstract type Agent{A<:Ancestors,R<:Rates,T<:Tuple,U,V} <: AbstractAgent{A,R}

mutable struct AgentA{R<:Rates,T<:Tuple,U,V} <: Agent{Ancestors{true},R,T,U,V}
    # history of traits for geotraits
    x_history::Array{T,1}
    # birth time of ancestors
    t_history::Array{U,1}
    # death rate
    d::V
    #birth rate
    b::V
end

struct AgentNA{R<:Rates,T<:Tuple,U,V} <: Agent{Ancestors{false},R,T,U,V}
27
    # history of traits for geotraits
28
    x_history::Array{T,1}
29
    # birth time of ancestors
Victor's avatar
Victor committed
30
    t_history::Array{U,1}
31
    # death rate
Victor's avatar
Victor committed
32
    d::V
33
    #birth rate
Victor's avatar
Victor committed
34
    b::V
35
36
end

37
38
eltype(a::Agent{A,R,T,U,V}) where {A,R,T,U,V} = T

Victor's avatar
Victor committed
39
40
41
42
43
44
45
# 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
46
            pos = (pos...,Eltype[i](ones(Dims[i])))
Victor's avatar
Victor committed
47
        else
48
            pos = (pos...,one(Eltype[i]))
Victor's avatar
Victor committed
49
50
51
52
53
        end
    end
    Tuple{Eltype...},pos
end

54
55
56
57
58
# default initialiser
"""
$(SIGNATURES)
    Initialises agent with 0 values everywhere
"""
Victor's avatar
Victor committed
59
60
function Agent(s::S;ancestors=false,rates=false) where {S  <: AbstractSpacesTuple}
    T,pos = initpos(s)
61
62
    t = zeros(Float64,1)
    U =  Float64
Victor's avatar
Victor committed
63
64
65
66
67
68
69
    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
70
71
72
73
"""
$(SIGNATURES)
    Initialises agent with `pos` provided
"""
Victor's avatar
Victor committed
74
function Agent(s::S, pos::P;ancestors=false,rates=false) where {P,S  <: AbstractSpacesTuple}
75
76
77
78
79
80
81
82
83
    T = eltype.(s)
    for (i,p) in enumerate(pos)
        if typeof(p) !== T[i]
            try
                p = convert(T[i],p)
            catch e
                throw(ArgumentError("Position provided does not match with underlying space"))
            end
        end
Victor's avatar
Victor committed
84
    end
85
86
    t = zeros(Float64,1)
    U =  Float64
Victor's avatar
Victor committed
87
88
89
    d = rates ?  Float64(.0) : nothing
    b = d
    V = rates ?  Float64 : Nothing
90
91
    @show pos, T
    Agent{Ancestors{ancestors},Rates{rates},Tuple{T...},U,V}([pos],t,d,b)
Victor's avatar
Victor committed
92
end
93

Victor's avatar
Victor committed
94
# TODO : implement pretty print
95
96

import Base.copy
97
98
99
Base.copy(a::Agent{A,R,T,U,V}) where {A,R,T,U,V} = Agent{A,R,T,U,V}(copy(a.x_history),copy(a.t_history),copy(a.d),copy(a.b))
Base.copy(m::Missing) = missing
Base.copy(n::Nothing) = nothing
100

Victor's avatar
Victor committed
101
102
103
104
#####################
###Agent accessors###
#####################

105
"""
Victor's avatar
Victor committed
106
107
    get_x(a::Agent)
Returns trait i of the agent
108
"""
Victor's avatar
Victor committed
109
get_x(a::AbstractAgent) = a.x_history[end]
Victor's avatar
Victor committed
110
111
112
113
114

"""
    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
115
116
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))
117
118
119
120
    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
121
122
123
124
125
126
"""
    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
127
128
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
129
130
131
132
"""
    get_t(a::Agent) = a.t_history[end]
Get time when agent born.
"""
Victor's avatar
Victor committed
133
get_t(a::AbstractAgent) = a.t_history[end]
134
get_xhist(a::Agent,i::Number) = [a.x_history[t][Int(i)] for t in 1:length(a.xhistory)]
135
get_xhist(a::Agent) = a.x_history
136
get_thist(a::Agent) = a.t_history
137
138
139
get_d(a::Agent) = a.d
get_b(a::Agent) = a.b
get_fitness(a::Agent) = a.b - a.d
140
141
ndims(a::Agent) = size(a.x_history[end],1)
nancestors(a::Agent) = length(a.x_history)
142

Victor's avatar
Victor committed
143
144
145
146
147
148
149
#####################
###World accessors###
#####################
"""
    get_x(world::Array{T},trait::Integer) where {T <: Agent}
Get x of world without geotrait.
"""
150
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"))
151
"""
152
    get_x(world::Array{T},t::Number,trait::Integer) where {T <: Agent}
153
Returns trait of every agents of world in the form of an array which dimensions corresponds to the input.
Victor's avatar
Victor committed
154
If `trait = 0` , we return the geotrait.
155
"""
156
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))
157

158
"""
Victor's avatar
Victor committed
159
    function get_xarray(world::Array{T,1}) where {T <: Agent}
160
161
Returns every traits of every agents of world in the form of an array
"""
162
163
164
function get_xarray(world::Array{T,1}) where {T <: Agent}
    return hcat(get_x.(world)...)
end
Victor's avatar
Victor committed
165
166
167
168
169
170
"""
    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}`.
"""
171
function get_xarray(world::Array{T,1},t::Number,geotrait::Bool=false) where {T <: Agent}
172
173
    xarray = hcat(get_x.(world)...)
    if geotrait
174
        xarray = vcat( xarray, get_geo.(world,t)')
175
    end
Victor's avatar
Victor committed
176
    return xarray
177
178
end

179
180
181
182
183
184
import Base.zero
Base.zero(t::Tuple{Vararg{Union{Number,Tuple{Vararg{Number}}}}}) = [zero.(e) for e in t]
import Base.(+)
(+)(t1::Tuple{Vararg{T,N}},t2::Tuple{Vararg{T,N}}) where {T<:Number,N}= tuple([t1[i] + t2[i] for i in 1:length(t1)]...)

function _get_xinc(a::AbstractAgent,s::AbstractSpacesTuple,p::Dict,t::Number)
Victor's avatar
Victor committed
185
186
    @unpack D,mu = p
    _x = get_x(a)
187
188
    inc = zero(_x)
    for (i,ss) in enumerate(s)
Victor's avatar
Victor committed
189
        if rand() < mu[i]
190
            inc[i] = get_inc(_x[i],D[i],ss)
Victor's avatar
Victor committed
191
        end
192
    end
193
194
195
196
197
198
199
200
201
202
    tuple((_x .+ inc)...)
end

## Modifiers
"""
    $(SIGNATURES)
This function increments agent by random numbers specified in p
ONLY FOR CONTINUOUS DOMAINS
"""
function increment_x!(a::AbstractAgent{A,R},s::AbstractSpacesTuple,p::Dict,t::T) where {A<:Ancestors{true},R,T}
Victor's avatar
Victor committed
203
    push!(a.t_history,t)
204
205
    a.x_history = push!(a.x_history,_get_xinc(a,s,p,t))
    return a
206
207
end

208
209
210
211
function increment_x!(a::AbstractAgent{A,R},s::AbstractSpacesTuple,p::Dict,t::T) where {A<:Ancestors{false},R,T}
    a.t_history = [ t ]
    a.x_history = [_get_xinc(a,s,p,t)]
    return a
212
213
end

214
"""
215
    function tin(t::Number,a::Number,b::Number)
216
217
218
if t in [a,b) returns 1. else returns 0
"""

219
function tin(t::Number,a::Number,b::Number)
220
221
222
223
224
225
226
227
228
229
    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