ABMEv_Agent.jl 6.21 KB
Newer Older
1
2
3
4
abstract type StdAgent end
abstract type MixedAgent end

mutable struct Agent{T,U}
5
    # history of traits for geotraits
6
    x_history::Array{U}
7
    # birth time of ancestors
8
    t_history::Array{Float64,1}
9
10
11
12
13
14
15
    # death rate
    d::Float64
    #birth rate
    b::Float64
end

# Constructors
16
# This  constructor should be used when one wants to impose the type of the agent (e.g. Mixed)
17
Agent{T}(xhist::Array{U}) where {T,U} = Agent{T,U}(reshape(xhist,:,1),[0.],0.,1.)
18
19

# This constructor is used by default
20
Agent(xhist::Array{U}) where {U <: Number} = Agent{StdAgent}(xhist)
21

22
Agent() = Agent(Float64[],0.,0.,1.)
23
import Base.copy
24
copy(a::Agent{T,U}) where {T,U} = Agent{T,U}(copy(a.x_history),copy(a.t_history),copy(a.d),copy(a.b))
25
26
copy(m::Missing) = missing

Victor's avatar
Victor committed
27
28
29
30
#####################
###Agent accessors###
#####################

31
"""
Victor's avatar
Victor committed
32
33
    get_x(a::Agent)
Returns trait i of the agent
34
"""
35
get_x(a::Agent) = a.x_history[:,end]
Victor's avatar
Victor committed
36
37
38
39
40

"""
    function get_geo(a::Agent{U,T},t::Number) where {U,T}
Returns geotrait of agent `a` at time `t`
"""
41
42
43
44
45
46
function get_geo(a::Agent{U,T},t::Number) where {U,T}
    tarray = vcat(a.t_history[2:end],convert(T,t))
    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
47
48
49
50
51
52
"""
    get_x(a::Agent,t::Number,i::Integer)
Returns trait `i` of the agent.
Geotrait corresponds to dimension `i=0`.
"""

53
54
get_x(a::Agent,t::Number,i::Integer) = i > 0 ? a.x_history[Int(i),end] : get_geo(a,t)
get_x(a::Agent,i::Integer) = a.x_history[Int(i),end]
Victor's avatar
Victor committed
55
56
57
58
"""
    get_t(a::Agent) = a.t_history[end]
Get time when agent born.
"""
59
get_t(a::Agent) = a.t_history[end]
60
61
get_xhist(a::Agent,i::Number) = a.x_history[Int(i),:]
get_xhist(a::Agent) = a.x_history
62
get_thist(a::Agent) = a.t_history
63
64
65
get_d(a::Agent) = a.d
get_b(a::Agent) = a.b
get_fitness(a::Agent) = a.b - a.d
66
67
get_dim(a::Agent) = size(a.x_history,1)
get_nancestors(a::Agent) = size(a.x_history,2)
68

Victor's avatar
Victor committed
69
70
71
72
73
74
75
#####################
###World accessors###
#####################
"""
    get_x(world::Array{T},trait::Integer) where {T <: Agent}
Get x of world without geotrait.
"""
76
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"))
77
"""
78
    get_x(world::Array{T},t::Number,trait::Integer) where {T <: Agent}
79
Returns trait of every agents of world in the form of an array which dimensions corresponds to the input.
Victor's avatar
Victor committed
80
If `trait = 0` , we return the geotrait.
81
"""
82
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))
83

84
"""
Victor's avatar
Victor committed
85
    function get_xarray(world::Array{T,1}) where {T <: Agent}
86
87
Returns every traits of every agents of world in the form of an array
"""
88
89
90
function get_xarray(world::Array{T,1}) where {T <: Agent}
    return hcat(get_x.(world)...)
end
Victor's avatar
Victor committed
91
92
93
94
95
96
"""
    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}`.
"""
97
function get_xarray(world::Array{T,1},t::Number,geotrait::Bool=false) where {T <: Agent}
98
99
    xarray = hcat(get_x.(world)...)
    if geotrait
100
        xarray = vcat( xarray, get_geo.(world,t)')
101
    end
Victor's avatar
Victor committed
102
    return xarray
103
104
end

105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# """
#     get_xhist(world::Vector{Agent},geotrait = false)
# Returns the trait history of every agents of world in the form of an 3 dimensional array,
# with
# - first dimension as the agent index
# - second as time index
# - third as trait index
# If geotrait = true, then a last trait dimension is added, corresponding to geotrait.
# Note that because number of ancestors are different between agents, we return an array which size corresponds to the minimum of agents ancestors,
# and return the last generations, dropping the youngest ones
# """
# function get_xhist(world::Vector{T}) where {T <: Agent}
#     hist = minimum(get_nancestors.(world))
#     ntraits = get_dim(first(world));
#     xhist = zeros(length(world), hist, ntraits + geotrait);
#     for (i,a) in enumerate(world)
#         xhist[i,:,1:end-geotrait] = get_xhist(a)[:,end-hist+1:end]';
#     end
#     return xhist
# end
125

126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# TODO: This method broken, when one ask for the geotraits
# function get_xhist(world::Vector{T},t::Number,geotrait = false) where {T <: Agent}
#     hist = minimum(get_nancestors.(world))
#     ntraits = get_dim(first(world));
#     xhist = zeros(length(world), hist, ntraits + geotrait);
#     for (i,a) in enumerate(world)
#         xhist[i,:,1:end-geotrait] = get_xhist(a)[:,end-hist+1:end]';
#         if geotrait
#             xhist[i,:,ntraits+geotrait] = cumsum(get_xhist(a,1))[end-hist+1:end]
#         end
#     end
#     return xhist
# end


141
function world2df(world::Array{T,1},geotrait=false) where {T <: Agent}
142
143
144
145
146
147
148
149
150
151
152
    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

153
"""
154
    world2df(world::Array{T,1},t::Number,geotrait = false) where {T <: Agent}
155
156
157
158
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
"""
159
function world2df(world::Array{T,1},t::Number,geotrait = false) where {T <: Agent}
160
161
162
163
164
165
    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
166
        dfw[:g] = get_geo.(world,t)
167
168
169
170
    end
    return dfw
end

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

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