ABMEv_Agent.jl 5.95 KB
Newer Older
Victor's avatar
Victor committed
1
2
abstract type Ancestors{T} end
abstract type Rates{T} end
3

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

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

22
23
import Base:eltype
# This definition of eltype is to be discussed
24
25
eltype(a::Agent{A,R,T,U,V}) where {A,R,T,U,V} = T

Victor's avatar
Victor committed
26
27
28
29
# infers position type and zeros
function initpos(s::S) where {S<:AbstractSpacesTuple}
    Eltype = eltype.(s)
    Dims = ndims.(s)
30
    pos = []
Victor's avatar
Victor committed
31
32
    for i in 1:length(Eltype)
        if Dims[i] > 1
33
            push!(pos,ones(Eltype[i],Dims[i]))
Victor's avatar
Victor committed
34
        else
35
            pos = push!(pos,one(Eltype[i]))
Victor's avatar
Victor committed
36
37
        end
    end
38
39
    _Type = eltype.(pos)
    Tuple{_Type...},pos
Victor's avatar
Victor committed
40
41
end

42
43
44
45
46
# default initialiser
"""
$(SIGNATURES)
    Initialises agent with 0 values everywhere
"""
Victor's avatar
Victor committed
47
48
function Agent(s::S;ancestors=false,rates=false) where {S  <: AbstractSpacesTuple}
    T,pos = initpos(s)
Victor's avatar
Victor committed
49
    t = 0.
50
    U =  Float64
Victor's avatar
Victor committed
51
52
53
    d = rates ?  Float64(.0) : nothing
    b = d
    V = rates ?  Float64 : Nothing
Victor's avatar
Victor committed
54
    Agent{Ancestors{ancestors},Rates{rates},T,U,V}([pos],[t],d,b)
Victor's avatar
Victor committed
55
56
57
end

# here pos is provided
58
59
60
61
"""
$(SIGNATURES)
    Initialises agent with `pos` provided
"""
62
function Agent(s::S, pos::P;ancestors=false,rates=false) where {P<:Vector,S  <: AbstractSpacesTuple}
63
64
    T = eltype.(s)
    for (i,p) in enumerate(pos)
65
        if eltype(p) !== T[i]
66
            try
67
                p = convert.(T[i],p)
68
69
70
71
            catch e
                throw(ArgumentError("Position provided does not match with underlying space"))
            end
        end
Victor's avatar
Victor committed
72
    end
Victor's avatar
Victor committed
73
    t = 0.
74
    U =  Float64
Victor's avatar
Victor committed
75
76
77
    d = rates ?  Float64(.0) : nothing
    b = d
    V = rates ?  Float64 : Nothing
Victor's avatar
Victor committed
78
    Agent{Ancestors{ancestors},Rates{rates},Tuple{T...},U,V}([pos],[t],d,b)
Victor's avatar
Victor committed
79
end
80

Victor's avatar
Victor committed
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# TODO : to be modified
function Agent(s::S,pos::Vector,t::Vector{U};ancestors=false,rates=false) where {S  <: AbstractSpacesTuple,U}
    T = eltype.(s)
    for (i,p) in enumerate(pos[1])
        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
    end
    d = rates ?  Float64(.0) : nothing
    b = d
    V = rates ?  Float64 : Nothing
    Agent{Ancestors{ancestors},Rates{rates},Tuple{T...},U,V}(pos,t,d,b)
end

Victor's avatar
Victor committed
99
100
import Base:copy,show
Base.copy(a::A) where {A<:AbstractAgent} = A(copy(a.x_history),copy(a.t_history),copy(a.d),copy(a.b))
Victor's avatar
Victor committed
101
102
103
104
# this function only copies the trait history and time (x,t), and set birth and death rates to 0.
copyxt(a::Agent{A,R,T,U,V}) where {A,R,T,U,V<:Number} = Agent{A,R,T,U,V}(copy(a.x_history),copy(a.t_history),zero(V),zero(V))
copyxt(a::Agent{A,R,T,U,Nothing}) where {A,R,T,U} = Agent{A,R,T,U,Nothing}(copy(a.x_history),copy(a.t_history),nothing,nothing)
# this has to be overloaded for Base.copy(a::Agent) to work properly
105
106
Base.copy(m::Missing) = missing
Base.copy(n::Nothing) = nothing
107

Victor's avatar
Victor committed
108
109
110
function Base.show(io::IO, a::Agent{A,R,T,U,V}) where {A,R,T,U,V}
     println(io, "Agent with indices of type", T)
end
Victor's avatar
Victor committed
111
112
113

Base.summary(A::AbstractAgent) = string(TYPE_COLOR,nameof(typeof(a)),NO_COLOR," with uType ",TYPE_COLOR,eltype(a.x_history))

Victor's avatar
Victor committed
114
115
116
117
#####################
###Agent accessors###
#####################

118
"""
Victor's avatar
Victor committed
119
120
    get_x(a::Agent)
Returns trait i of the agent
121
"""
Victor's avatar
Victor committed
122

123
Base.getindex(a::Agent,i) = a.x_history[end][i]
Victor's avatar
Victor committed
124
125
126

get_x(a::Agent) = a.x_history[end]
@deprecate get_x(a) a[:]
Victor's avatar
Victor committed
127
128

"""
Victor's avatar
Victor committed
129
$(SIGNATURES)
Victor's avatar
Victor committed
130
131
Returns geotrait of agent `a` at time `t`
"""
Victor's avatar
Victor committed
132
function get_geo(a::Agent{A,R,T,U,V},t::Number) where {A<:Ancestors{true},R,T,U,V}
Victor's avatar
Victor committed
133
    tarray = vcat(a.t_history[2:end],convert(U,t))
134
135
136
    tarray .-= a.t_history
    return sum(get_xhist(a,1) .* tarray)
end
Victor's avatar
Victor committed
137

138
# This method can acces geotrait, while the second not
Victor's avatar
Victor committed
139
"""
Victor's avatar
Victor committed
140
$(SIGNATURES)
Victor's avatar
Victor committed
141
142
143
Returns trait `i` of the agent.
Geotrait corresponds to dimension `i=0`.
"""
144
get_x(a::AbstractAgent,t::Number,i::Integer) = i > 0 ? a.x_history[end][Int(i)] : get_geo(a,t)
Victor's avatar
Victor committed
145
146

"""
Victor's avatar
Victor committed
147
$(SIGNATURES)
Victor's avatar
Victor committed
148
149
Get time when agent born.
"""
Victor's avatar
Victor committed
150
151
152
get_t(a::Agent) = a.t_history[end]

# TODO: change this with getindex
153
get_xhist(a::AbstractAgent,i::Number) = [a.x_history[t][Int(i)] for t in 1:length(a.x_history)]
Victor's avatar
Victor committed
154

155
get_xhist(a::AbstractAgent) = a.x_history
Victor's avatar
Victor committed
156

157
get_thist(a::AbstractAgent) = a.t_history
158

Victor's avatar
Victor committed
159
get_d(a::AbstractAgent) = a.d
160

Victor's avatar
Victor committed
161
162
163
164
get_b(a::AbstractAgent) = a.b

get_fitness(a::AbstractAgent) = a.b - a.d

165
166
167
# TODO : we can surely extract N in Agent{A,R,Tuple{Vararg{S,N}},U,V}
# Inspiration : where U <: Union{Missing,Agent{T}} where T
Base.length(a::AbstractAgent) = length(a.x_history[end])
Victor's avatar
Victor committed
168
169

nancestors(a::Agent) = length(a.x_history)
170

171
import Base.zero
Victor's avatar
Victor committed
172

173
Base.zero(t::Tuple{Vararg{Union{Number,Tuple{Vararg{Number}}}}}) = [zero.(e) for e in t]
Victor's avatar
Victor committed
174

175
176
177
178
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
179
    @unpack D,mu = p
180
    _x = deepcopy(get_x(a))
181
    for (i,ss) in enumerate(s)
vboussange's avatar
vboussange committed
182
        if length(mu[i]) > 1
183
184
185
            mut = rand(eltype(mu[i]),ndims(ss)) .< mu[i]
            _x[i] .+= mut .* get_inc(_x[i],D[i],ss,t)
        else
vboussange's avatar
vboussange committed
186
            mut = rand(eltype(mu[i])) < mu[i]
187
            _x[i] += mut * get_inc(_x[i],D[i],ss,t)
Victor's avatar
Victor committed
188
        end
189
    end
190
    _x
191
192
193
194
195
196
197
198
199
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
200
    push!(a.t_history,t)
201
202
    a.x_history = push!(a.x_history,_get_xinc(a,s,p,t))
    return a
203
204
end

205
function increment_x!(a::AbstractAgent{A,R},s::AbstractSpacesTuple,p::Dict,t::T) where {A<:Ancestors{false},R,T}
Victor's avatar
Victor committed
206
207
    a.t_history[1] = t
    a.x_history[1] = _get_xinc(a,s,p,t)
208
    return a
209
end