To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

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

Agents and World working

parent 20e4134a
......@@ -10,8 +10,8 @@ module ABMEv
include("ABMEv_Agent.jl")
include("ABMEv_world.jl")
include("ABMEv_Sim.jl")
include("ABMEv_metrics.jl")
include("ABMEv_plot.jl")
# include("ABMEv_metrics.jl")
# include("ABMEv_plot.jl")
include("ABMEv_utils.jl")
include("algo/ABMEv_WF.jl")
include("algo/ABMEv_Gillepsie.jl")
......@@ -32,10 +32,10 @@ module ABMEv
export runWorld!,give_birth,updateWorld!,update_clock!,updateBirthEvent!,
updateDeathEvent!#,runWorld_G!,runWorld_WF!,
export Simulation,add_entry!
export H_discrete,findclusters,var,covgeo,hamming,get_beta_div, get_alpha_div,
get_dist_hist,get_pairwise_average_isolation,
get_local_pairwise_average_isolation,
truncvar,get_xhist_mat
# export H_discrete,findclusters,var,covgeo,hamming,get_beta_div, get_alpha_div,
# get_dist_hist,get_pairwise_average_isolation,
# get_local_pairwise_average_isolation,
# truncvar,get_xhist_mat
export update_afterbirth_std!,update_afterdeath_std!
export generalised_gaussian,gaussian,ma,geomsmooth,arithsmooth,eth_grad_std,
DiversityFunction,geomsmooth2D,arithsmooth2D,interpolate_df,groupby
......
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
abstract type AbstractAgent{A<:Ancestors,R<:Rates} end # tc for time contingency, fit for fitness coeff
AbstractAgentM = Union{Missing,AbstractAgent}
......@@ -10,9 +8,7 @@ export AbstractAgentM
"""
$(TYPEDEF)
"""
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}
mutable struct Agent{A<:Ancestors,R<:Rates,T<:Tuple,U,V} <: AbstractAgent{A,R}
# history of traits for geotraits
x_history::Array{T,1}
# birth time of ancestors
......@@ -23,16 +19,6 @@ mutable struct AgentA{R<:Rates,T<:Tuple,U,V} <: Agent{Ancestors{true},R,T,U,V}
b::V
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
......@@ -58,12 +44,12 @@ $(SIGNATURES)
"""
function Agent(s::S;ancestors=false,rates=false) where {S <: AbstractSpacesTuple}
T,pos = initpos(s)
t = zeros(Float64,1)
t = 0.
U = Float64
d = rates ? Float64(.0) : nothing
b = d
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
# here pos is provided
......@@ -82,22 +68,31 @@ function Agent(s::S, pos::P;ancestors=false,rates=false) where {P,S <: Abstract
end
end
end
t = zeros(Float64,1)
t = 0.
U = Float64
d = rates ? Float64(.0) : nothing
b = d
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
# 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(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###
#####################
......@@ -106,78 +101,59 @@ Base.copy(n::Nothing) = nothing
get_x(a::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`
"""
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 .-= a.t_history
return sum(get_xhist(a,1) .* tarray)
end
# This method can acces geotrait, while the second not
"""
get_x(a::Agent,t::Number,i::Integer)
$(SIGNATURES)
Returns trait `i` of the agent.
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_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) = a.x_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)
#####################
###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_d(a::AbstractAgent) = a.d
"""
function get_xarray(world::Array{T,1}) where {T <: Agent}
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
"""
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
get_b(a::AbstractAgent) = a.b
get_fitness(a::AbstractAgent) = a.b - a.d
Base.ndims(a::Agent{A,R,T,U,V}) where {A,R,T<:(Tuple{Vararg{S,N}} where {S,N}),U,V} = N
nancestors(a::Agent) = length(a.x_history)
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)]...)
......@@ -206,8 +182,8 @@ function increment_x!(a::AbstractAgent{A,R},s::AbstractSpacesTuple,p::Dict,t::T)
end
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)]
a.t_history[1] = t
a.x_history[1] = _get_xinc(a,s,p,t)
return a
end
......
abstract type AbstractAlg end
# 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}
space::S
tspan::Vector{T}
......@@ -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)
end
function world2df(world::Array{T,1},geotrait=false) where {T <: Agent}
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
"""
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
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)
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,t)
end
return dfw
end
#TODO: code it
# function world2df(world::Array{T,1},geotrait=false) where {T <: Agent}
# 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
#
# """
# 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
# 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)
# 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,t)
# end
# return dfw
# end
......@@ -212,3 +212,10 @@ It should correspond to an integer, as it indexes the column to plot
# 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)
return [sum(x[i-smooth+1:i])/smooth for i in smooth:length(x)]
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
import Interpolations:interpolate,Gridded,Linear
struct DiversityFunction
......
......@@ -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))
return nothing
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)
# increment on finite spaces
# 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
#checking if graph works
@test prod([get_inc(1,10,mygraph) + 1 vertices(mygraph.g) for i in 1:30])
......
using LightGraphs
using Test
using Revise,ABMEv
using UnPack
myspace = (GraphSpace(SimpleGraph(10,10)),RealSpace{1,Float64}())
myagents = [Agent(myspace,ancestors=true,rates=true) for i in 1:10]
d(X,Y) = gaussian(X[1],Y[1],1)
......@@ -12,10 +13,10 @@ p = Dict{String,Any}();@pack! p = d,b,D,mu,NMax
@test eltype(agents) <: AbstractAgentM
@test typeof(agents) <: Vector{A} where {A<:AbstractAgentM}
@test eltype(myagents) <: 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
newa = give_birth(1,w)
addAgent!(w,newa)
......@@ -24,8 +25,8 @@ removeAgent!(w,11)
@test size(w) 10
@test isnothing(update_clock!(w,.1))
using BenchmarkTools
if false
using BenchmarkTools
# TODO
# 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
......
Markdown is supported
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