ABMEv_Agent.jl 6.07 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
8
abstract type AbstractAgent{A<:Ancestors,R<:Rates} end # tc for time contingency, fit for fitness coeff
AbstractAgentM = Union{Missing,AbstractAgent}
mutable struct Agent{A<:Ancestors,R<:Rates,T,U,V} <: AbstractAgent{A,R}
9
    # history of traits for geotraits
Victor's avatar
Victor committed
10
    pos::Array{T,1}
11
    # birth time of ancestors
Victor's avatar
Victor committed
12
    t_history::Array{U,1}
13
    # death rate
Victor's avatar
Victor committed
14
    d::V
15
    #birth rate
Victor's avatar
Victor committed
16
    b::V
17
18
end

Victor's avatar
Victor committed
19
20
21
22
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
# 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
57

Victor's avatar
Victor committed
58
# TODO : implement pretty print
59
60

import Base.copy
Victor's avatar
Victor committed
61
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))
62
copy(m::Missing) = missing
Victor's avatar
Victor committed
63
copy(n::Nothing) = nothing
64

Victor's avatar
Victor committed
65
66
67
68
#####################
###Agent accessors###
#####################

69
"""
Victor's avatar
Victor committed
70
71
    get_x(a::Agent)
Returns trait i of the agent
72
"""
Victor's avatar
Victor committed
73
get_x(a::AbstractAgent) = a.x_history[end]
Victor's avatar
Victor committed
74
75
76
77
78

"""
    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
79
80
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))
81
82
83
84
    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
85
86
87
88
89
90
"""
    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
91
92
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
93
94
95
96
"""
    get_t(a::Agent) = a.t_history[end]
Get time when agent born.
"""
Victor's avatar
Victor committed
97
get_t(a::AbstractAgent) = a.t_history[end]
98
99
get_xhist(a::Agent,i::Number) = a.x_history[Int(i),:]
get_xhist(a::Agent) = a.x_history
100
get_thist(a::Agent) = a.t_history
101
102
103
get_d(a::Agent) = a.d
get_b(a::Agent) = a.b
get_fitness(a::Agent) = a.b - a.d
104
105
get_dim(a::Agent) = size(a.x_history,1)
get_nancestors(a::Agent) = size(a.x_history,2)
106

Victor's avatar
Victor committed
107
108
109
110
111
112
113
#####################
###World accessors###
#####################
"""
    get_x(world::Array{T},trait::Integer) where {T <: Agent}
Get x of world without geotrait.
"""
114
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"))
115
"""
116
    get_x(world::Array{T},t::Number,trait::Integer) where {T <: Agent}
117
Returns trait of every agents of world in the form of an array which dimensions corresponds to the input.
Victor's avatar
Victor committed
118
If `trait = 0` , we return the geotrait.
119
"""
120
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))
121

122
"""
Victor's avatar
Victor committed
123
    function get_xarray(world::Array{T,1}) where {T <: Agent}
124
125
Returns every traits of every agents of world in the form of an array
"""
126
127
128
function get_xarray(world::Array{T,1}) where {T <: Agent}
    return hcat(get_x.(world)...)
end
Victor's avatar
Victor committed
129
130
131
132
133
134
"""
    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}`.
"""
135
function get_xarray(world::Array{T,1},t::Number,geotrait::Bool=false) where {T <: Agent}
136
137
    xarray = hcat(get_x.(world)...)
    if geotrait
138
        xarray = vcat( xarray, get_geo.(world,t)')
139
    end
Victor's avatar
Victor committed
140
    return xarray
141
142
end

143
function world2df(world::Array{T,1},geotrait=false) where {T <: Agent}
144
145
146
147
148
149
150
151
152
153
154
    xx = get_xarray(world)
    dfw = DataFrame(:f => get_fitness.(world))
    for i in 1:size(xx,1)
        dfw[Meta.parse("x$i")] = xx[i,:]
    end
    if geotrait
        dfw[:g] = get_geo.(world)
    end
    return dfw
end

155
"""
156
    world2df(world::Array{T,1},t::Number,geotrait = false) where {T <: Agent}
157
158
159
160
Converts the array of agent world to a datafram, where each column corresponds to a trait of the
agent, and an extra column captures fitness.
Each row corresponds to an agent
"""
161
function world2df(world::Array{T,1},t::Number,geotrait = false) where {T <: Agent}
162
163
164
165
166
167
    xx = get_xarray(world)
    dfw = DataFrame(:f => get_fitness.(world))
    for i in 1:size(xx,1)
        dfw[Meta.parse("x$i")] = xx[i,:]
    end
    if geotrait
168
        dfw[:g] = get_geo.(world,t)
169
170
171
172
    end
    return dfw
end

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

178
function tin(t::Number,a::Number,b::Number)
179
180
181
182
183
184
185
186
187
188
    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