Skip to content
Snippets Groups Projects
Commit d7458155 authored by Bentriou Mahmoud's avatar Bentriou Mahmoud
Browse files

Implement of ModelPrior + test.

Add several convenient methods for parameters of model.

Next step: implementation of simulate with resize!.
parent 5b7fc78f
No related branches found
No related tags found
No related merge requests found
...@@ -13,7 +13,7 @@ pygmalion.load_model(str_m) ...@@ -13,7 +13,7 @@ pygmalion.load_model(str_m)
str_oml = "P,R,time" str_oml = "P,R,time"
ll_om = split(str_oml, ",") ll_om = split(str_oml, ",")
x0 = State(95.0, 95.0, 0.0, 0.0, 0.0, 0.0) x0 = State(95.0, 95.0, 0.0, 0.0, 0.0, 0.0)
p_true = Parameters(1.0, 1.0, 1.0) p_true = Parameters(0.2, 40.0, 1.0)
u = Control(20.0) u = Control(20.0)
tml = 1:400 tml = 1:400
g_all = create_observation_function([ObserverModel(str_oml, tml)]) g_all = create_observation_function([ObserverModel(str_oml, tml)])
...@@ -29,6 +29,9 @@ println("MarkovProcesses:") ...@@ -29,6 +29,9 @@ println("MarkovProcesses:")
using MarkovProcesses using MarkovProcesses
MarkovProcesses.load_model("ER") MarkovProcesses.load_model("ER")
ER.time_bound = 20.0 ER.time_bound = 20.0
ER.estim_min_states = 7000
set_param!(ER, "k1", 0.2)
set_param!(ER, "k2", 40.0)
@timev MarkovProcesses.simulate(ER) @timev MarkovProcesses.simulate(ER)
println("Default buffer size=10") println("Default buffer size=10")
...@@ -40,6 +43,6 @@ println("Buffer size 100") ...@@ -40,6 +43,6 @@ println("Buffer size 100")
ER.buffer_size = 100 ER.buffer_size = 100
b1_100 = @benchmark for i=1:$(nb_sim) MarkovProcesses.simulate($ER) end b1_100 = @benchmark for i=1:$(nb_sim) MarkovProcesses.simulate($ER) end
b2_100 = @benchmark for i=1:$(nb_sim) MarkovProcesses.simulate(ER) end b2_100 = @benchmark for i=1:$(nb_sim) MarkovProcesses.simulate(ER) end
@show minimum(b1), mean(b1), maximum(b1) @show minimum(b1_100), mean(b1_100), maximum(b1_100)
@show minimum(b2), mean(b2), maximum(b2) @show minimum(b2_100), mean(b2_100), maximum(b2_100)
...@@ -4,10 +4,13 @@ import Base: +, -, * ...@@ -4,10 +4,13 @@ import Base: +, -, *
import Base: copy, getfield, getindex, lastindex, setindex!, getproperty, setproperty! import Base: copy, getfield, getindex, lastindex, setindex!, getproperty, setproperty!
import StaticArrays: SVector import StaticArrays: SVector
import Distributions: Distribution, Product, Uniform, Normal
export Distribution, Product, Uniform, Normal
# Common types and constructors # Common types and constructors
export Observations, AbstractTrajectory, Trajectory, SynchronizedTrajectory export Observations, AbstractTrajectory, Trajectory, SynchronizedTrajectory
export Model, ContinuousTimeModel, SynchronizedModel export Model, ContinuousTimeModel, SynchronizedModel, ModelPrior
export LHA, StateLHA, Edge export LHA, StateLHA, Edge
# Trajectory related methods # Trajectory related methods
...@@ -22,7 +25,7 @@ export load_automaton, get_index, get_value, length_var, isaccepted ...@@ -22,7 +25,7 @@ export load_automaton, get_index, get_value, length_var, isaccepted
# Model related methods # Model related methods
export simulate, set_param!, get_param, set_observed_var! export simulate, set_param!, get_param, set_observed_var!
export set_time_bound!, getproperty export set_time_bound!, getproperty, draw!
export isbounded, isaccepted, check_consistency export isbounded, isaccepted, check_consistency
export load_model, get_module_path export load_model, get_module_path
......
...@@ -22,6 +22,7 @@ mutable struct ContinuousTimeModel <: Model ...@@ -22,6 +22,7 @@ mutable struct ContinuousTimeModel <: Model
isabsorbing::Function isabsorbing::Function
time_bound::Float64 time_bound::Float64
buffer_size::Int buffer_size::Int
estim_min_states::Int
end end
struct Trajectory <: AbstractTrajectory struct Trajectory <: AbstractTrajectory
...@@ -31,6 +32,11 @@ struct Trajectory <: AbstractTrajectory ...@@ -31,6 +32,11 @@ struct Trajectory <: AbstractTrajectory
transitions::Vector{Transition} transitions::Vector{Transition}
end end
struct ModelPrior
m::Model
map_l_param_dist::Dict{Vector{String},Distribution}
end
struct Edge struct Edge
transitions::Vector{Transition} transitions::Vector{Transition}
check_constraints::Function check_constraints::Function
...@@ -74,7 +80,7 @@ end ...@@ -74,7 +80,7 @@ end
function ContinuousTimeModel(d::Int, k::Int, map_var_idx::Dict, map_param_idx::Dict, l_transitions::Vector{String}, function ContinuousTimeModel(d::Int, k::Int, map_var_idx::Dict, map_param_idx::Dict, l_transitions::Vector{String},
p::Vector{Float64}, x0::Vector{Int}, t0::Float64, p::Vector{Float64}, x0::Vector{Int}, t0::Float64,
f!::Function, isabsorbing::Function; f!::Function, isabsorbing::Function;
g::Vector{String} = keys(map_var_idx), time_bound::Float64 = Inf, buffer_size::Int = 10) g::Vector{String} = keys(map_var_idx), time_bound::Float64 = Inf, buffer_size::Int = 10, estim_min_states::Int = 50)
dobs = length(g) dobs = length(g)
_map_obs_var_idx = Dict() _map_obs_var_idx = Dict()
_g_idx = Vector{Int}(undef, dobs) _g_idx = Vector{Int}(undef, dobs)
...@@ -90,7 +96,7 @@ function ContinuousTimeModel(d::Int, k::Int, map_var_idx::Dict, map_param_idx::D ...@@ -90,7 +96,7 @@ function ContinuousTimeModel(d::Int, k::Int, map_var_idx::Dict, map_param_idx::D
@warn "You have possibly redefined a function Model.isabsorbing used in a previously instantiated model." @warn "You have possibly redefined a function Model.isabsorbing used in a previously instantiated model."
end end
return ContinuousTimeModel(d, k, map_var_idx, _map_obs_var_idx, map_param_idx, l_transitions, p, x0, t0, f!, g, _g_idx, isabsorbing, time_bound, buffer_size) return ContinuousTimeModel(d, k, map_var_idx, _map_obs_var_idx, map_param_idx, l_transitions, p, x0, t0, f!, g, _g_idx, isabsorbing, time_bound, buffer_size, estim_min_states)
end end
LHA(A::LHA, map_var::Dict{String,Int}) = LHA(A.l_transitions, A.l_loc, A.Λ, LHA(A::LHA, map_var::Dict{String,Int}) = LHA(A.l_transitions, A.l_loc, A.Λ,
...@@ -99,3 +105,11 @@ LHA(A::LHA, map_var::Dict{String,Int}) = LHA(A.l_transitions, A.l_loc, A.Λ, ...@@ -99,3 +105,11 @@ LHA(A::LHA, map_var::Dict{String,Int}) = LHA(A.l_transitions, A.l_loc, A.Λ,
Base.:*(m::ContinuousTimeModel, A::LHA) = SynchronizedModel(m, A) Base.:*(m::ContinuousTimeModel, A::LHA) = SynchronizedModel(m, A)
Base.:*(A::LHA, m::ContinuousTimeModel) = SynchronizedModel(m, A) Base.:*(A::LHA, m::ContinuousTimeModel) = SynchronizedModel(m, A)
function ModelPrior(m::Model, priors::Tuple{Vector{String},Distribution}...)
map = Dict{Vector{String},Distribution}()
for prior in priors
map[prior[1]] = prior[2]
end
return ModelPrior(m, map)
end
...@@ -4,10 +4,11 @@ load_model(name_model::String) = include(get_module_path() * "/models/" * name_m ...@@ -4,10 +4,11 @@ load_model(name_model::String) = include(get_module_path() * "/models/" * name_m
# Simulation # Simulation
function simulate(m::ContinuousTimeModel) function simulate(m::ContinuousTimeModel)
# trajectory fields # trajectory fields
full_values = Matrix{Int}(undef, 1, m.d) full_values = Vector{Vector{Int}}(undef, m.d)
full_values[1,:] = m.x0 for i = 1:m.d full_values[i] = Int[m.x0[i]] end
for i = 1:m.d sizehint!(full_values[i], m.estim_min_states) end
times = Float64[m.t0] times = Float64[m.t0]
transitions = Union{String,Nothing}[nothing] transitions = Transition[nothing]
# values at time n # values at time n
n = 0 n = 0
xn = view(reshape(m.x0, 1, m.d), 1, :) # View for type stability xn = view(reshape(m.x0, 1, m.d), 1, :) # View for type stability
...@@ -17,39 +18,47 @@ function simulate(m::ContinuousTimeModel) ...@@ -17,39 +18,47 @@ function simulate(m::ContinuousTimeModel)
l_t = zeros(Float64, m.buffer_size) l_t = zeros(Float64, m.buffer_size)
l_tr = Vector{String}(undef, m.buffer_size) l_tr = Vector{String}(undef, m.buffer_size)
isabsorbing::Bool = m.isabsorbing(m.p,xn) isabsorbing::Bool = m.isabsorbing(m.p,xn)
end_idx = -1
# use sizehint! ?
while !isabsorbing && tn <= m.time_bound while !isabsorbing && tn <= m.time_bound
i = 0 for i = 1:m.buffer_size
while i < m.buffer_size && !isabsorbing && tn <= m.time_bound
i += 1
m.f!(mat_x, l_t, l_tr, i, xn, tn, m.p) m.f!(mat_x, l_t, l_tr, i, xn, tn, m.p)
tn = l_t[i] tn = l_t[i]
if tn > m.time_bound if tn > m.time_bound
i -= 1 # 0 is an ok value, 1:0 is allowed i -= 1 # 0 is an ok value, 1:0 is allowed
end_idx = i
break break
end end
xn = view(mat_x, i, :) xn = view(mat_x, i, :)
isabsorbing = m.isabsorbing(m.p,xn) isabsorbing = m.isabsorbing(m.p,xn)
if isabsorbing
end_idx = i
break
end
end end
full_values = vcat(full_values, view(mat_x, 1:i, :)) if end_idx != -1
append!(times, view(l_t, 1:i)) break
append!(transitions, view(l_tr, 1:i)) end
n += i for k = 1:m.d
#isabsorbing = m.isabsorbing(m.p,xn) append!(full_values[k], view(mat_x, :, k))
end
append!(times, l_t)
append!(transitions, l_tr)
n += m.buffer_size
end
for k = 1:m.d
append!(full_values[k], view(mat_x, 1:end_idx, k))
end end
append!(times, view(l_t, 1:end_idx))
append!(transitions, view(l_tr, 1:end_idx))
if isbounded(m) if isbounded(m)
#= for k = 1:m.d
if times[end] > m.time_bound push!(full_values[k], full_values[k][end])
full_values[end,:] = full_values[end-1,:]
times[end] = m.time_bound
transitions[end] = nothing
else
end end
=#
full_values = vcat(full_values, reshape(full_values[end,:], 1, m.d))
push!(times, m.time_bound) push!(times, m.time_bound)
push!(transitions, nothing) push!(transitions, nothing)
end end
values = view(full_values, :, m._g_idx) values = full_values[m._g_idx]
return Trajectory(m, values, times, transitions) return Trajectory(m, values, times, transitions)
end end
...@@ -57,12 +66,13 @@ function simulate(product::SynchronizedModel) ...@@ -57,12 +66,13 @@ function simulate(product::SynchronizedModel)
# trajectory fields # trajectory fields
m = product.m m = product.m
A = product.automaton A = product.automaton
full_values = Matrix{Int}(undef, 1, m.d) full_values = Vector{Vector{Int}}(undef, m.d)
full_values[1,:] = m.x0 for i = 1:m.d full_values[i] = Int[m.x0[i]] end
for i = 1:m.d sizehint!(full_values[i], m.estim_min_states) end
times = Float64[m.t0] times = Float64[m.t0]
transitions = Union{String,Nothing}[nothing] transitions = Union{String,Nothing}[nothing]
reshaped_x0 = view(reshape(m.x0, 1, m.d), 1, :) # View for type stability reshaped_x0 = view(reshape(m.x0, 1, m.d), 1, :) # View for type stability
S0 = init_state(A, reshaped_x0, m.t0) S0 = init_state(A, m.x0, m.t0)
# values at time n # values at time n
n = 0 n = 0
xn = reshaped_x0 xn = reshaped_x0
...@@ -75,7 +85,6 @@ function simulate(product::SynchronizedModel) ...@@ -75,7 +85,6 @@ function simulate(product::SynchronizedModel)
isabsorbing::Bool = m.isabsorbing(m.p,xn) isabsorbing::Bool = m.isabsorbing(m.p,xn)
isacceptedLHA::Bool = isaccepted(Sn) isacceptedLHA::Bool = isaccepted(Sn)
Snplus1 = copy(Sn) Snplus1 = copy(Sn)
Sn_dump = Sn
while !isabsorbing && tn <= m.time_bound && !isacceptedLHA while !isabsorbing && tn <= m.time_bound && !isacceptedLHA
i = 0 i = 0
while i < m.buffer_size && !isabsorbing && tn <= m.time_bound && !isacceptedLHA while i < m.buffer_size && !isabsorbing && tn <= m.time_bound && !isacceptedLHA
...@@ -93,7 +102,9 @@ function simulate(product::SynchronizedModel) ...@@ -93,7 +102,9 @@ function simulate(product::SynchronizedModel)
isabsorbing = m.isabsorbing(m.p,xn) isabsorbing = m.isabsorbing(m.p,xn)
isacceptedLHA = isaccepted(Snplus1) isacceptedLHA = isaccepted(Snplus1)
end end
full_values = vcat(full_values, view(mat_x, 1:i, :)) for k = 1:m.d
append!(full_values[k], view(mat_x, 1:i, k))
end
append!(times, view(l_t, 1:i)) append!(times, view(l_t, 1:i))
append!(transitions, view(l_tr, 1:i)) append!(transitions, view(l_tr, 1:i))
n += i n += i
...@@ -101,11 +112,13 @@ function simulate(product::SynchronizedModel) ...@@ -101,11 +112,13 @@ function simulate(product::SynchronizedModel)
# When the trajectory is accepted, we should not add an end value # When the trajectory is accepted, we should not add an end value
if isbounded(m) && !isaccepted(Sn) if isbounded(m) && !isaccepted(Sn)
@assert times[end] < m.time_bound @assert times[end] < m.time_bound
#full_values = vcat(full_values, reshape(full_values[end,:], 1, m.d)) for k = 1:m.d
#push!(times, m.time_bound) push!(full_values[k], full_values[k][end])
#push!(transitions, nothing) end
push!(times, m.time_bound)
push!(transitions, nothing)
end end
values = view(full_values, :, m._g_idx) values = full_values[m._g_idx]
return SynchronizedTrajectory(Snplus1, product, values, times, transitions) return SynchronizedTrajectory(Snplus1, product, values, times, transitions)
end end
...@@ -136,8 +149,40 @@ function check_consistency(m::ContinuousTimeModel) ...@@ -136,8 +149,40 @@ function check_consistency(m::ContinuousTimeModel)
@assert typeof(m.isabsorbing(m.p, view(reshape(m.x0, 1, m.d), 1, :))) == Bool @assert typeof(m.isabsorbing(m.p, view(reshape(m.x0, 1, m.d), 1, :))) == Bool
return true return true
end end
set_param!(m::ContinuousTimeModel, p::Vector{Float64}) = (m.p = p) set_param!(m::ContinuousTimeModel, p::Vector{Float64}) = (m.p = p)
set_param!(m::ContinuousTimeModel, name_p::String, p_i::Float64) = (m.p[m.map_param_idx[name_p]] = p_i) set_param!(m::ContinuousTimeModel, name_p::String, p_i::Float64) = (m.p[m.map_param_idx[name_p]] = p_i)
function set_param!(m::ContinuousTimeModel, l_name_p::Vector{String}, p::Vector{Float64})
nb_param = length(l_name_p)
for i = 1:nb_param
set_param!(m, l_name_p[i], p[i])
end
end
get_param(m::ContinuousTimeModel) = m.p get_param(m::ContinuousTimeModel) = m.p
getindex(m::ContinuousTimeModel, name_p::String) = m.p[m.map_param_idx[name_p]]
set_time_bound!(m::ContinuousTimeModel, b::Float64) = (m.time_bound = b) set_time_bound!(m::ContinuousTimeModel, b::Float64) = (m.time_bound = b)
set_time_bound!(sm::SynchronizedModel, b::Float64) = set_time_bound!(sm.m, b)
function getproperty(m::ContinuousTimeModel, sym::Symbol)
if sym == :dobs
return length(m.g)
else
return getfield(m, sym)
end
end
get_proba_model(m::ContinuousTimeModel) = m
get_proba_model(sm::SynchronizedModel) = sm.m
# Prior methods
function draw!(Π::ModelPrior)
dict_dist = Π.map_l_param_dist
for l_name in keys(dict_dist)
if length(l_name) == 1
set_param!(get_proba_model(Π.m), l_name[1], rand(dict_dist[l_name]))
else
set_param!(get_proba_model(Π.m), l_name, rand(dict_dist[l_name]))
end
end
end
...@@ -22,5 +22,6 @@ using Test ...@@ -22,5 +22,6 @@ using Test
@test include("unit/side_effects_1.jl") @test include("unit/side_effects_1.jl")
@test include("unit/create_models.jl") @test include("unit/create_models.jl")
@test include("unit/create_automata.jl") @test include("unit/create_automata.jl")
@test include("unit/model_prior.jl")
end end
using MarkovProcesses
load_model("ER")
test_all = true
load_model("ER")
prior1 = ModelPrior(ER, (["k2"], Uniform(2.0, 4.0)))
draw!(prior1)
test_all = test_all && 2.0 <= ER["k2"] <= 4.0
prior2 = ModelPrior(ER, (["k3","k2"], Product(Uniform.([2.5,6.0], [3.5,7.0]))))
draw!(prior2)
test_all = test_all && 2.5 <= ER["k3"] <= 3.5 && 6.0 <= ER["k2"] <= 7.0
prior3 = ModelPrior(ER, (["k3"], Uniform(10.0, 11.0)), (["k2"], Uniform(13.0, 14.0)))
draw!(prior3)
test_all = test_all && 10.0 <= ER["k3"] <= 11.0 && 13.0 <= ER["k2"] <= 14.0
return test_all
...@@ -22,6 +22,11 @@ k3 = 10.0 ...@@ -22,6 +22,11 @@ k3 = 10.0
set_param!(ER, "k3", 10.0) set_param!(ER, "k3", 10.0)
test_all = test_all && (ER.p == [0.5, 4.0, 10.0]) test_all = test_all && (ER.p == [0.5, 4.0, 10.0])
l_k = [20.0, 10.0]
l_name = ["k3", "k2"]
set_param!(ER, l_name, l_k)
test_all = test_all && (ER.p == [0.5, 10.0, 20.0])
new_param_SIR = [0.0013, 0.08] new_param_SIR = [0.0013, 0.08]
set_param!(SIR, new_param_SIR) set_param!(SIR, new_param_SIR)
test_all = test_all && (SIR.p == new_param_SIR) test_all = test_all && (SIR.p == new_param_SIR)
...@@ -34,5 +39,20 @@ ki = 0.011 ...@@ -34,5 +39,20 @@ ki = 0.011
set_param!(SIR, "ki", ki) set_param!(SIR, "ki", ki)
test_all = test_all && (SIR.p == [0.011, 0.06]) test_all = test_all && (SIR.p == [0.011, 0.06])
l_name = ["kr", "ki"]
l_p = [0.03, 0.015]
set_param!(SIR, l_name, l_p)
test_all = test_all && (SIR.p == [0.015, 0.03])
l_name = ["ki", "kr"]
l_p = [0.03, 0.015]
set_param!(SIR, l_name, l_p)
test_all = test_all && (SIR.p == [0.03, 0.015])
l_name = ["kr"]
l_p = [0.02]
set_param!(SIR, l_name, l_p)
test_all = test_all && (SIR.p == [0.03, 0.02])
return test_all return test_all
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment