Commit 1c79e98f authored by Victor's avatar Victor
Browse files

Agents and World working

parent 20e4134a
...@@ -10,8 +10,8 @@ module ABMEv ...@@ -10,8 +10,8 @@ module ABMEv
include("ABMEv_Agent.jl") include("ABMEv_Agent.jl")
include("ABMEv_world.jl") include("ABMEv_world.jl")
include("ABMEv_Sim.jl") include("ABMEv_Sim.jl")
include("ABMEv_metrics.jl") # include("ABMEv_metrics.jl")
include("ABMEv_plot.jl") # include("ABMEv_plot.jl")
include("ABMEv_utils.jl") include("ABMEv_utils.jl")
include("algo/ABMEv_WF.jl") include("algo/ABMEv_WF.jl")
include("algo/ABMEv_Gillepsie.jl") include("algo/ABMEv_Gillepsie.jl")
...@@ -32,10 +32,10 @@ module ABMEv ...@@ -32,10 +32,10 @@ module ABMEv
export runWorld!,give_birth,updateWorld!,update_clock!,updateBirthEvent!, export runWorld!,give_birth,updateWorld!,update_clock!,updateBirthEvent!,
updateDeathEvent!#,runWorld_G!,runWorld_WF!, updateDeathEvent!#,runWorld_G!,runWorld_WF!,
export Simulation,add_entry! export Simulation,add_entry!
export H_discrete,findclusters,var,covgeo,hamming,get_beta_div, get_alpha_div, # export H_discrete,findclusters,var,covgeo,hamming,get_beta_div, get_alpha_div,
get_dist_hist,get_pairwise_average_isolation, # get_dist_hist,get_pairwise_average_isolation,
get_local_pairwise_average_isolation, # get_local_pairwise_average_isolation,
truncvar,get_xhist_mat # truncvar,get_xhist_mat
export update_afterbirth_std!,update_afterdeath_std! export update_afterbirth_std!,update_afterdeath_std!
export generalised_gaussian,gaussian,ma,geomsmooth,arithsmooth,eth_grad_std, export generalised_gaussian,gaussian,ma,geomsmooth,arithsmooth,eth_grad_std,
DiversityFunction,geomsmooth2D,arithsmooth2D,interpolate_df,groupby DiversityFunction,geomsmooth2D,arithsmooth2D,interpolate_df,groupby
......
abstract type Ancestors{T} end abstract type Ancestors{T} end
abstract type Rates{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
abstract type AbstractAgent{A<:Ancestors,R<:Rates} end # tc for time contingency, fit for fitness coeff abstract type AbstractAgent{A<:Ancestors,R<:Rates} end # tc for time contingency, fit for fitness coeff
AbstractAgentM = Union{Missing,AbstractAgent} AbstractAgentM = Union{Missing,AbstractAgent}
...@@ -10,9 +8,7 @@ export AbstractAgentM ...@@ -10,9 +8,7 @@ export AbstractAgentM
""" """
$(TYPEDEF) $(TYPEDEF)
""" """
abstract type Agent{A<:Ancestors,R<:Rates,T<:Tuple,U,V} <: AbstractAgent{A,R} mutable struct 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 # history of traits for geotraits
x_history::Array{T,1} x_history::Array{T,1}
# birth time of ancestors # birth time of ancestors
...@@ -23,16 +19,6 @@ mutable struct AgentA{R<:Rates,T<:Tuple,U,V} <: Agent{Ancestors{true},R,T,U,V} ...@@ -23,16 +19,6 @@ mutable struct AgentA{R<:Rates,T<:Tuple,U,V} <: Agent{Ancestors{true},R,T,U,V}
b::V b::V
end end
struct AgentNA{R<:Rates,T<:Tuple,U,V} <: Agent{Ancestors{false},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
eltype(a::Agent{A,R,T,U,V}) where {A,R,T,U,V} = T eltype(a::Agent{A,R,T,U,V}) where {A,R,T,U,V} = T
...@@ -58,12 +44,12 @@ $(SIGNATURES) ...@@ -58,12 +44,12 @@ $(SIGNATURES)
""" """
function Agent(s::S;ancestors=false,rates=false) where {S <: AbstractSpacesTuple} function Agent(s::S;ancestors=false,rates=false) where {S <: AbstractSpacesTuple}
T,pos = initpos(s) T,pos = initpos(s)
t = zeros(Float64,1) t = 0.
U = Float64 U = Float64
d = rates ? Float64(.0) : nothing d = rates ? Float64(.0) : nothing
b = d b = d
V = rates ? Float64 : Nothing V = rates ? Float64 : Nothing
Agent{Ancestors{ancestors},Rates{rates},T,U,V}([pos],t,d,b) Agent{Ancestors{ancestors},Rates{rates},T,U,V}([pos],[t],d,b)
end end
# here pos is provided # here pos is provided
...@@ -82,22 +68,31 @@ function Agent(s::S, pos::P;ancestors=false,rates=false) where {P,S <: Abstract ...@@ -82,22 +68,31 @@ function Agent(s::S, pos::P;ancestors=false,rates=false) where {P,S <: Abstract
end end
end end
end end
t = zeros(Float64,1) t = 0.
U = Float64 U = Float64
d = rates ? Float64(.0) : nothing d = rates ? Float64(.0) : nothing
b = d b = d
V = rates ? Float64 : Nothing V = rates ? Float64 : Nothing
@show pos, T Agent{Ancestors{ancestors},Rates{rates},Tuple{T...},U,V}([pos],[t],d,b)
Agent{Ancestors{ancestors},Rates{rates},Tuple{T...},U,V}([pos],t,d,b)
end end
# TODO : implement pretty print 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))
import Base.copy
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(m::Missing) = missing
Base.copy(n::Nothing) = nothing Base.copy(n::Nothing) = nothing
function Base.show(io::IO, a::AbstractAgent)
print(io,"pos: ")
show(io, a.x_history)
println(io)
print(io,"t: ")
show(io, a.t_history)
end
Base.summary(A::AbstractAgent) = string(TYPE_COLOR,nameof(typeof(a)),NO_COLOR," with uType ",TYPE_COLOR,eltype(a.x_history))
##################### #####################
###Agent accessors### ###Agent accessors###
##################### #####################
...@@ -106,78 +101,59 @@ Base.copy(n::Nothing) = nothing ...@@ -106,78 +101,59 @@ Base.copy(n::Nothing) = nothing
get_x(a::Agent) get_x(a::Agent)
Returns trait i of the agent Returns trait i of the agent
""" """
get_x(a::AbstractAgent) = a.x_history[end]
Base.getindex(a::Agent,i::Int) = a.x_history[end][i]
Base.getindex(a::Agent,I::Vararg{Int, 2}) = a.x_history[end][I]
get_x(a::Agent) = a.x_history[end]
@deprecate get_x(a) a[:]
""" """
function get_geo(a::Agent{U,T},t::Number) where {U,T} $(SIGNATURES)
Returns geotrait of agent `a` at time `t` Returns geotrait of agent `a` at time `t`
""" """
function get_geo(a::Agent{Ancestors{true},R,T,U,V},t::Number) where {R,T,U,V} function get_geo(a::Agent{A,R,T,U,V},t::Number) where {A<:Ancestors{true},R,T,U,V}
tarray = vcat(a.t_history[2:end],convert(U,t)) tarray = vcat(a.t_history[2:end],convert(U,t))
tarray .-= a.t_history tarray .-= a.t_history
return sum(get_xhist(a,1) .* tarray) return sum(get_xhist(a,1) .* tarray)
end end
# This method can acces geotrait, while the second not # This method can acces geotrait, while the second not
""" """
get_x(a::Agent,t::Number,i::Integer) $(SIGNATURES)
Returns trait `i` of the agent. Returns trait `i` of the agent.
Geotrait corresponds to dimension `i=0`. Geotrait corresponds to dimension `i=0`.
""" """
get_x(a::Agent,t::Number,i::Integer) = i > 0 ? a.x_history[end][Int(i)] : get_geo(a,t)
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)]
""" """
get_t(a::Agent) = a.t_history[end] $(SIGNATURES)
Get time when agent born. Get time when agent born.
""" """
get_t(a::AbstractAgent) = a.t_history[end] get_t(a::Agent) = a.t_history[end]
# TODO: change this with getindex
get_xhist(a::Agent,i::Number) = [a.x_history[t][Int(i)] for t in 1:length(a.xhistory)] get_xhist(a::Agent,i::Number) = [a.x_history[t][Int(i)] for t in 1:length(a.xhistory)]
get_xhist(a::Agent) = a.x_history get_xhist(a::Agent) = a.x_history
get_thist(a::Agent) = a.t_history get_thist(a::Agent) = a.t_history
get_d(a::Agent) = a.d
get_b(a::Agent) = a.b
get_fitness(a::Agent) = a.b - a.d
ndims(a::Agent) = size(a.x_history[end],1)
nancestors(a::Agent) = length(a.x_history)
##################### get_d(a::AbstractAgent) = a.d
###World accessors###
#####################
"""
get_x(world::Array{T},trait::Integer) where {T <: Agent}
Get x of world without geotrait.
"""
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"))
"""
get_x(world::Array{T},t::Number,trait::Integer) where {T <: Agent}
Returns trait of every agents of world in the form of an array which dimensions corresponds to the input.
If `trait = 0` , we return the geotrait.
"""
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))
""" get_b(a::AbstractAgent) = a.b
function get_xarray(world::Array{T,1}) where {T <: Agent}
Returns every traits of every agents of world in the form of an array get_fitness(a::AbstractAgent) = a.b - a.d
"""
function get_xarray(world::Array{T,1}) where {T <: Agent} Base.ndims(a::Agent{A,R,T,U,V}) where {A,R,T<:(Tuple{Vararg{S,N}} where {S,N}),U,V} = N
return hcat(get_x.(world)...)
end nancestors(a::Agent) = length(a.x_history)
"""
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}`.
"""
function get_xarray(world::Array{T,1},t::Number,geotrait::Bool=false) where {T <: Agent}
xarray = hcat(get_x.(world)...)
if geotrait
xarray = vcat( xarray, get_geo.(world,t)')
end
return xarray
end
import Base.zero import Base.zero
Base.zero(t::Tuple{Vararg{Union{Number,Tuple{Vararg{Number}}}}}) = [zero.(e) for e in t] Base.zero(t::Tuple{Vararg{Union{Number,Tuple{Vararg{Number}}}}}) = [zero.(e) for e in t]
import Base.(+) 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)]...) (+)(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)]...)
...@@ -206,8 +182,8 @@ function increment_x!(a::AbstractAgent{A,R},s::AbstractSpacesTuple,p::Dict,t::T) ...@@ -206,8 +182,8 @@ function increment_x!(a::AbstractAgent{A,R},s::AbstractSpacesTuple,p::Dict,t::T)
end end
function increment_x!(a::AbstractAgent{A,R},s::AbstractSpacesTuple,p::Dict,t::T) where {A<:Ancestors{false},R,T} function increment_x!(a::AbstractAgent{A,R},s::AbstractSpacesTuple,p::Dict,t::T) where {A<:Ancestors{false},R,T}
a.t_history = [ t ] a.t_history[1] = t
a.x_history = [_get_xinc(a,s,p,t)] a.x_history[1] = _get_xinc(a,s,p,t)
return a return a
end end
......
abstract type AbstractAlg end abstract type AbstractAlg end
# this used to be world # this used to be world
mutable struct Simulation{A<:AbstractAgentM, S<:AbstractSpacesTuple,T<:Number,F} mutable struct Simulation{A<:AbstractAgent, S<:AbstractSpacesTuple,T<:Number,F}
agentarray::Vector{AbstractAgentM} agentarray::Vector{AbstractAgentM}
space::S space::S
tspan::Vector{T} tspan::Vector{T}
...@@ -47,32 +47,33 @@ function add_entry!(s::Simulation{A,S,T,F},w::World) where {A,S,T,F<:Nothing} ...@@ -47,32 +47,33 @@ function add_entry!(s::Simulation{A,S,T,F},w::World) where {A,S,T,F<:Nothing}
push!(s.tspan,w.t) push!(s.tspan,w.t)
end end
function world2df(world::Array{T,1},geotrait=false) where {T <: Agent} #TODO: code it
xx = get_xarray(world) # function world2df(world::Array{T,1},geotrait=false) where {T <: Agent}
dfw = DataFrame(:f => get_fitness.(world)) # xx = get_xarray(world)
for i in 1:size(xx,1) # dfw = DataFrame(:f => get_fitness.(world))
dfw[Meta.parse("x$i")] = xx[i,:] # for i in 1:size(xx,1)
end # dfw[Meta.parse("x$i")] = xx[i,:]
if geotrait # end
dfw[:g] = get_geo.(world) # if geotrait
end # dfw[:g] = get_geo.(world)
return dfw # end
end # return dfw
# end
""" #
world2df(world::Array{T,1},t::Number,geotrait = false) where {T <: Agent} # """
Converts the array of agent world to a datafram, where each column corresponds to a trait of the # world2df(world::Array{T,1},t::Number,geotrait = false) where {T <: Agent}
agent, and an extra column captures fitness. # Converts the array of agent world to a datafram, where each column corresponds to a trait of the
Each row corresponds to an agent # agent, and an extra column captures fitness.
""" # Each row corresponds to an agent
function world2df(world::Array{T,1},t::Number,geotrait = false) where {T <: Agent} # """
xx = get_xarray(world) # function world2df(world::Array{T,1},t::Number,geotrait = false) where {T <: Agent}
dfw = DataFrame(:f => get_fitness.(world)) # xx = get_xarray(world)
for i in 1:size(xx,1) # dfw = DataFrame(:f => get_fitness.(world))
dfw[Meta.parse("x$i")] = xx[i,:] # for i in 1:size(xx,1)
end # dfw[Meta.parse("x$i")] = xx[i,:]
if geotrait # end
dfw[:g] = get_geo.(world,t) # if geotrait
end # dfw[:g] = get_geo.(world,t)
return dfw # end
end # return dfw
# end
...@@ -212,3 +212,10 @@ It should correspond to an integer, as it indexes the column to plot ...@@ -212,3 +212,10 @@ It should correspond to an integer, as it indexes the column to plot
# end # end
# end # end
end end
import Plots:cgrad
# asymmetry towards red, blue is only a fifth of the color range
const eth_grad_small = cgrad([colorant"#1F407A", RGB(0.671,0.851,0.914),RGB(1.0,1.0,0.749), RGB(0.992,0.682,0.38),RGB(0.647,0.0,0.149),],[.0,.1])
# symmetry between red and blue
const eth_grad_std = cgrad([colorant"#1F407A", RGB(0.671,0.851,0.914),RGB(1.0,1.0,0.749), RGB(0.992,0.682,0.38),RGB(0.647,0.0,0.149),],[.0,1.])
...@@ -39,12 +39,6 @@ function arithsmooth(x,smooth) ...@@ -39,12 +39,6 @@ function arithsmooth(x,smooth)
return [sum(x[i-smooth+1:i])/smooth for i in smooth:length(x)] return [sum(x[i-smooth+1:i])/smooth for i in smooth:length(x)]
end end
import Plots:cgrad
# asymmetry towards red, blue is only a fifth of the color range
const eth_grad_small = cgrad([colorant"#1F407A", RGB(0.671,0.851,0.914),RGB(1.0,1.0,0.749), RGB(0.992,0.682,0.38),RGB(0.647,0.0,0.149),],[.0,.1])
# symmetry between red and blue
const eth_grad_std = cgrad([colorant"#1F407A", RGB(0.671,0.851,0.914),RGB(1.0,1.0,0.749), RGB(0.992,0.682,0.38),RGB(0.647,0.0,0.149),],[.0,1.])
# This is all about interpolations # This is all about interpolations
import Interpolations:interpolate,Gridded,Linear import Interpolations:interpolate,Gridded,Linear
struct DiversityFunction struct DiversityFunction
......
...@@ -45,3 +45,39 @@ update_clock!(w::World{A,S,T},dt) where {A,S,T} = begin ...@@ -45,3 +45,39 @@ update_clock!(w::World{A,S,T},dt) where {A,S,T} = begin
w.t = convert(T,sum(w.t + dt)) w.t = convert(T,sum(w.t + dt))
return nothing return nothing
end end
## Accessors
"""
$(SIGNATURES)
Get x of world without geotrait.
"""
Base.getindex(w::World,i::Integer) = getindex.(agents(w),i)
#TODO : code it
# """
# $(SIGNATURES)
# Returns trait of every agents of world in the form of an array which dimensions corresponds to the input.
# If `trait = 0` , we return the geotrait.
# """
# get_x(w::World,t::Number,trait::Integer) = trait > 0 ? w[i] : reshape(hcat(get_geo.(w,t)),size(w,1),size(w,2))
#
# """
# $(SIGNATURES)
# Returns every traits of every agents of world in the form of an array
# """
# function get_xarray(world::Array{T,1}) where {T <: Agent}
# return hcat(get_x.(world)...)
# end
# """
# $(SIGNATURES)
# 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}`.
# """
# function get_xarray(world::Array{T,1},t::Number,geotrait::Bool=false) where {T <: Agent}
# xarray = hcat(get_x.(world)...)
# if geotrait
# xarray = vcat( xarray, get_geo.(world,t)')
# end
# return xarray
# end
...@@ -34,7 +34,7 @@ ABMEv.initpos(myspace2) ...@@ -34,7 +34,7 @@ ABMEv.initpos(myspace2)
# increment on finite spaces # increment on finite spaces
# checking if reflection works # checking if reflection works
@test mysegment.s < get_inc(5.,100.,mysegment) + 5. < mysegment.e @test mysegment.s - eps() < get_inc(5.,100.,mysegment) + 5. < mysegment.e + eps()
@test mycontinuoussegment.s < get_inc(0.,100.,mycontinuoussegment) < mycontinuoussegment.e @test mycontinuoussegment.s < get_inc(0.,100.,mycontinuoussegment) < mycontinuoussegment.e
#checking if graph works #checking if graph works
@test prod([get_inc(1,10,mygraph) + 1 vertices(mygraph.g) for i in 1:30]) @test prod([get_inc(1,10,mygraph) + 1 vertices(mygraph.g) for i in 1:30])
......
using LightGraphs using LightGraphs
using Test using Test
using Revise,ABMEv using Revise,ABMEv
using UnPack
myspace = (GraphSpace(SimpleGraph(10,10)),RealSpace{1,Float64}()) myspace = (GraphSpace(SimpleGraph(10,10)),RealSpace{1,Float64}())
myagents = [Agent(myspace,ancestors=true,rates=true) for i in 1:10] myagents = [Agent(myspace,ancestors=true,rates=true) for i in 1:10]
d(X,Y) = gaussian(X[1],Y[1],1) d(X,Y) = gaussian(X[1],Y[1],1)
...@@ -12,10 +13,10 @@ p = Dict{String,Any}();@pack! p = d,b,D,mu,NMax ...@@ -12,10 +13,10 @@ p = Dict{String,Any}();@pack! p = d,b,D,mu,NMax
@test eltype(agents) <: AbstractAgentM @test eltype(myagents) <: AbstractAgentM
@test typeof(agents) <: Vector{A} where {A<:AbstractAgentM} @test typeof(myagents) <: Vector{A} where {A<:AbstractAgentM}
w = World(agents,myspace,p,0.) w = World(myagents,myspace,p,0.)
@test size(w) 10 @test size(w) 10
newa = give_birth(1,w) newa = give_birth(1,w)
addAgent!(w,newa) addAgent!(w,newa)
...@@ -24,8 +25,8 @@ removeAgent!(w,11) ...@@ -24,8 +25,8 @@ removeAgent!(w,11)
@test size(w) 10 @test size(w) 10
@test isnothing(update_clock!(w,.1)) @test isnothing(update_clock!(w,.1))
using BenchmarkTools
if false if false
using BenchmarkTools
# TODO # TODO
# Here we observe that deleting an agent is a bit of a pain # Here we observe that deleting an agent is a bit of a pain
# Since one has to look where this agent is located in the structure # Since one has to look where this agent is located in the structure
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment