Commit dc5689b5 authored by Bentriou Mahmoud's avatar Bentriou Mahmoud

Finally I managed to improve the performance of function access of LHA.

The solution is to use FunctionWrappers.jl which provides a high
interface for C function pointers.

All tests passed.
parent 99ece473
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# Creation of the automaton types
@everywhere @eval abstract type EdgeEuclideanDistanceAutomaton <: Edge end
#@everywhere @eval abstract type EdgeEuclideanDistanceAutomaton <: Edge end
@everywhere struct EdgeEuclideanDistanceAutomaton <: Edge
transitions::TransitionSet
check_constraints::CheckConstraintsFunction
update_state!::UpdateStateFunction
end
@everywhere @eval $(MarkovProcesses.generate_code_lha_type_def(:EuclideanDistanceAutomaton, :EdgeEuclideanDistanceAutomaton))
function create_euclidean_distance_automaton(m::ContinuousTimeModel, timeline::AbstractVector{Float64}, observations::AbstractVector{Float64}, sym_obs::VariableModel)
......@@ -43,14 +48,20 @@ function create_euclidean_distance_automaton(m::ContinuousTimeModel, timeline::A
basename_func = "$(model_name)_$(id)"
edge_name(from_loc::Location, to_loc::Location, edge_number::Int) =
Symbol("Edge_$(lha_name)_$(basename_func)_$(from_loc)$(to_loc)_$(edge_number)")
function check_constraints(from_loc::Location, to_loc::Location, edge_number::Int)
return Symbol("check_constraints_$(edge_type)_$(from_loc)$(to_loc)_$(edge_number)_$(model_name)_$(id)")
end
function update_state!(from_loc::Location, to_loc::Location, edge_number::Int)
return Symbol("update_state_$(edge_type)_$(from_loc)$(to_loc)_$(edge_number)_$(model_name)_$(id)!")
end
## check_constraints & update_state!
@everywhere @eval begin
meta_funcs = quote
# l0 loc
# l0 => l1
struct $(edge_name(:l0, :l1, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
$(check_constraints)(edge::$(edge_name(:l0, :l1, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
$(update_state!)(edge::$(edge_name(:l0, :l1, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
#struct $(edge_name(:l0, :l1, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
@everywhere $(check_constraints(:l0, :l1, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
@everywhere $(update_state!(:l0, :l1, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
(S_values[$(to_idx(:n))] = x[$(idx_obs_var)];
S_values[$(to_idx(:d))] = 0.0;
S_values[$(to_idx(:idx))] = 1.0;
......@@ -59,32 +70,33 @@ function create_euclidean_distance_automaton(m::ContinuousTimeModel, timeline::A
# l1 loc
# l1 => l1
# Defined below
struct $(edge_name(:l1, :l1, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
$(check_constraints)(edge::$(edge_name(:l1, :l1, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
#struct $(edge_name(:l1, :l1, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
@everywhere $(check_constraints(:l1, :l1, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
(tml = $(Tuple(timeline));
tml_idx = tml[convert(Int, S_values[$(to_idx(:idx))])];
S_values[$(to_idx(:t))] >= tml_idx)
$(update_state!)(edge::$(edge_name(:l1, :l1, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
@everywhere $(update_state!(:l1, :l1, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
(y_obs = $(Tuple(observations));
y_obs_idx = y_obs[convert(Int, S_values[$(to_idx(:idx))])];
S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))]+(S_values[$(to_idx(:n))]-y_obs_idx)^2;
S_values[$(to_idx(:idx))] = S_values[$(to_idx(:idx))]+1.0;
:l1)
struct $(edge_name(:l1, :l1, 2)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
$(check_constraints)(edge::$(edge_name(:l1, :l1, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
$(update_state!)(edge::$(edge_name(:l1, :l1, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
#struct $(edge_name(:l1, :l1, 2)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
@everywhere $(check_constraints(:l1, :l1, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
@everywhere $(update_state!(:l1, :l1, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
(S_values[$(to_idx(:n))] = x[$(idx_obs_var)];
:l1)
# l1 => l2
struct $(edge_name(:l1, :l2, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
$(check_constraints)(edge::$(edge_name(:l1, :l2, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
#struct $(edge_name(:l1, :l2, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
@everywhere $(check_constraints(:l1, :l2, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
S_values[$(to_idx(:idx))] >= ($nbr_observations + 1)
$(update_state!)(edge::$(edge_name(:l1, :l2, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
@everywhere $(update_state!(:l1, :l2, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) =
(S_values[$(to_idx(:d))] = sqrt(S_values[$(to_idx(:d))]);
:l2)
end
eval(meta_funcs)
@eval begin
map_edges = Dict{Location,Dict{Location,Vector{$(edge_type)}}}()
......@@ -95,20 +107,24 @@ function create_euclidean_distance_automaton(m::ContinuousTimeModel, timeline::A
## Edges
# l0 loc
# l0 => l1
edge1 = $(edge_name(:l0, :l1, 1))(nothing)
edge1 = EdgeEuclideanDistanceAutomaton(nothing, $(check_constraints(:l0, :l1, 1)), $(update_state!(:l0, :l1, 1)))
map_edges[:l0][:l1] = [edge1]
# l1 loc
# l1 => l1
edge1 = $(edge_name(:l1, :l1, 1))(nothing)
edge2 = $(edge_name(:l1, :l1, 2))([:ALL])
edge1 = EdgeEuclideanDistanceAutomaton(nothing, $(check_constraints(:l1, :l1, 1)), $(update_state!(:l1, :l1, 1)))
edge2 = EdgeEuclideanDistanceAutomaton([:ALL], $(check_constraints(:l1, :l1, 2)), $(update_state!(:l1, :l1, 2)))
map_edges[:l1][:l1] = [edge1, edge2]
# l1 => l2
edge1 = $(edge_name(:l1, :l2, 1))(nothing)
edge1 = EdgeEuclideanDistanceAutomaton(nothing, $(check_constraints(:l1, :l2, 1)), $(update_state!(:l1, :l2, 1)))
map_edges[:l1][:l2] = [edge1]
end
map_edges_transitions = Dict{Symbol, Dict{Symbol,Vector{TransitionSet}}}()
map_edges_check_constraints = Dict{Symbol, Dict{Symbol,Vector{CheckConstraintsFunction}}}()
map_edges_update_state = Dict{Symbol, Dict{Symbol,Vector{UpdateStateFunction}}}()
## Constants
constants = Dict{Symbol,Float64}(:nbr_obs => nbr_observations)
for i = 1:nbr_observations
......@@ -118,11 +134,13 @@ function create_euclidean_distance_automaton(m::ContinuousTimeModel, timeline::A
# Updating types and simulation methods
@everywhere @eval $(MarkovProcesses.generate_code_synchronized_model_type_def(model_name, lha_name))
@everywhere @eval $(MarkovProcesses.generate_code_next_state(lha_name, edge_type, check_constraints, update_state!))
@everywhere @eval $(MarkovProcesses.generate_code_next_state(lha_name, edge_type))
@everywhere @eval $(MarkovProcesses.generate_code_synchronized_simulation(model_name, lha_name, edge_type, m.f!, m.isabsorbing))
A = EuclideanDistanceAutomaton(m.transitions, locations, Λ_F, locations_init, locations_final,
map_var_automaton_idx, flow, map_edges, constants, m.map_var_idx)
map_var_automaton_idx, flow,
map_edges, map_edges_transitions, map_edges_check_constraints, map_edges_update_state,
constants, m.map_var_idx)
return A
end
......
This diff is collapsed.
This diff is collapsed.
using BenchmarkTools
using MarkovProcesses
@everywhere using MarkovProcesses
using Profile
load_model("ER")
......
......@@ -10,17 +10,19 @@ import Distributed: @everywhere, @distributed
import Distributions: Product, Uniform, Normal
import Distributions: Distribution, Univariate, Continuous, UnivariateDistribution,
MultivariateDistribution, product_distribution
import FunctionWrappers: FunctionWrapper
import StaticArrays: SVector, @SVector
## Exports
export Distribution, Product, Uniform, Normal
# Common types and constructors
export Observations, AbstractTrajectory, Trajectory, SynchronizedTrajectory
export SVector, @SVector
export Observations, AbstractTrajectory, Trajectory, SynchronizedTrajectory
export Model, ContinuousTimeModel, SynchronizedModel, ParametricModel
export VariableModel, ParameterModel, Transition, TransitionSet
export LHA, StateLHA, Edge, Location, VariableAutomaton
export InvariantPredicateFunction, CheckConstraintsFunction, UpdateStateFunction
# Trajectory related methods
export +, -, δ, dist_lp, euclidean_distance
......
......@@ -11,8 +11,12 @@ abstract type Edge end
const VariableModel = Symbol
const ParameterModel = Symbol
const Transition = Union{Symbol,Nothing}
const TransitionSet = Union{Vector{Symbol},Nothing}
const Location = Symbol
const VariableAutomaton = Symbol
const InvariantPredicateFunction = FunctionWrapper{Bool,Tuple{Vector{Int}}}
const CheckConstraintsFunction = FunctionWrapper{Bool,Tuple{Float64,Vector{Float64},Vector{Int},Vector{Float64}}}
const UpdateStateFunction = FunctionWrapper{Symbol,Tuple{Float64,Vector{Float64},Vector{Int},Vector{Float64}}}
function generate_code_model_type_def(model_name::Symbol)
return quote
......@@ -49,12 +53,15 @@ function generate_code_lha_type_def(lha_name::Symbol, edge_type::Symbol)
struct $(lha_name) <: LHA
transitions::Vector{Transition}
locations::Vector{Location}
Λ::Dict{Location,Function}
Λ::Dict{Location,InvariantPredicateFunction}
locations_init::Vector{Location}
locations_final::Vector{Location}
map_var_automaton_idx::Dict{VariableAutomaton,Int} # nvar keys : str_var => idx in values
flow::Dict{Location,Vector{Float64}} # output of length nvar
map_edges::Dict{Location, Dict{Location,Vector{$(edge_type)}}}
map_edges_transitions::Dict{Location, Dict{Location,Vector{TransitionSet}}}
map_edges_check_constraints::Dict{Location, Dict{Location,Vector{CheckConstraintsFunction}}}
map_edges_update_state::Dict{Location, Dict{Location,Vector{UpdateStateFunction}}}
constants::Dict{Symbol,Float64}
map_var_model_idx::Dict{VariableModel,Int} # of dim d (of a model)
end
......@@ -129,7 +136,9 @@ end
LHA(A::LHA, map_var::Dict{VariableModel,Int}) =
getfield(Main, Symbol(typeof(A)))(A.transitions, A.locations, A.Λ, A.locations_init, A.locations_final,
A.map_var_automaton_idx, A.flow, A.map_edges, A.constants, map_var)
A.map_var_automaton_idx, A.flow, A.map_edges,
A.map_edges_transitions, A.map_edges_check_constraints, A.map_edges_update_state,
A.constants, map_var)
function ParametricModel(am::Model, priors::Tuple{ParameterModel,UnivariateDistribution}...)
m = get_proba_model(am)
......
This diff is collapsed.
using Distributed
using MarkovProcesses
begin_procs = nprocs()
if begin_procs == 1
addprocs(2)
end
path_module = get_module_path() * "/core"
using Distributed
addprocs(2)
module_path = get_module_path()
@everywhere module_path = $module_path
@everywhere push!(LOAD_PATH, "$(module_path)/core")
@everywhere using MarkovProcesses
#=
@everywhere begin
path_module = $(path_module)
push!(LOAD_PATH, path_module)
......@@ -14,6 +14,9 @@ path_module = get_module_path() * "/core"
load_model("ER")
load_automaton("automaton_F")
end
=#
load_model("ER")
load_automaton("automaton_F")
A_F_R1 = create_automaton_F(ER, 50.0, 75.0, 0.025, 0.05, :P)
sync_ER = A_F_R1*ER
pm_sync_ER = ParametricModel(sync_ER, (:k3, Uniform(0.0, 100.0)))
......@@ -21,9 +24,7 @@ nbr_pa = 404
r = automaton_abc(pm_sync_ER; nbr_particles = nbr_pa)
if begin_procs == 1
rmprocs(workers())
end
rmprocs(2)
test = size(r.mat_p_end)[1] == pm_sync_ER.df &&
size(r.mat_p_end)[2] == nbr_pa &&
......
......@@ -3,7 +3,7 @@ using Test
@testset "ABC SMC and automaton-ABC tests" begin
@test include("automaton_abc/R1.jl")
#test_distributed_R1 = include("automaton_abc/distributed_R1.jl")
@test include("automaton_abc/distributed_R1.jl")
#@test test_distributed_R1
end
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