From 99ece473efd5e44b1f16f0628be3ec7f1e860dcf Mon Sep 17 00:00:00 2001 From: Mahmoud Bentriou <mahmoud.bentriou@centralesupelec.fr> Date: Wed, 24 Feb 2021 16:08:35 +0100 Subject: [PATCH] Big improvement of network models performance with SVector --- bench/pkg/abstract_array.jl | 30 +++++++++---------- bench/pkg/euclidean_distance_repressilator.jl | 3 +- bench/pkg/sim_repressilator.jl | 18 +++++++++++ core/MarkovProcesses.jl | 3 +- core/network_model.jl | 6 ++-- models/ER.jl | 12 ++++---- models/SIR.jl | 10 +++---- models/SIR_tauleap.jl | 6 ++-- 8 files changed, 53 insertions(+), 35 deletions(-) create mode 100644 bench/pkg/sim_repressilator.jl diff --git a/bench/pkg/abstract_array.jl b/bench/pkg/abstract_array.jl index 2e163ee..13b0879 100644 --- a/bench/pkg/abstract_array.jl +++ b/bench/pkg/abstract_array.jl @@ -3,25 +3,25 @@ using Profile using StaticArrays using BenchmarkTools -println("Cost of tests:") +println("Cost of 20 boolean tests:") f_test(a::Int) = a == 2 @btime for i = 1:20 f_test(3) end -# First container type +# Multiple dispatch abstract type SuperType end -for i = 1:10 +for i = 1:20 include_string(Main, "struct Type$i <: SuperType v::Symbol end") include_string(Main, "f(item::Type$i, a::Int) = a == $(i)") end vec_types = SuperType[] for i = 1:20 - rand_number_type = rand(1:10) + rand_number_type = rand(1:20) @eval item = $(Symbol("Type$(rand_number_type)"))(:test) push!(vec_types, item) end -println("First super type") +println("Multiple dispatch:") function read(vec_types::Vector{SuperType}, a::Int) for item in vec_types f(item, a) @@ -29,19 +29,19 @@ function read(vec_types::Vector{SuperType}, a::Int) end @btime read(vec_types, 3) -# Second container type +# Parametric struct struct AnotherSuperType{T<:Function} v::Symbol f::T end vec_others_types = AnotherSuperType[] for i = 1:20 - rand_number_type = rand(1:10) + rand_number_type = rand(1:20) include_string(Main, "f_other_$(i)(a::Int) = a == $(i)") sym_func = Symbol("f_other_$i") @eval push!(vec_others_types, AnotherSuperType(:test, $(sym_func))) end -println("Second super type") +println("Parametrized struct:") function read(vec_others_types::Vector{AnotherSuperType}, a::Int) for item in vec_others_types item.f(a) @@ -49,12 +49,12 @@ function read(vec_others_types::Vector{AnotherSuperType}, a::Int) end @btime read(vec_others_types, 3) -# With vectors -println("Transitions first:") +# With two vectors +println("Vectors:") vec_tr = Union{Nothing,Symbol}[] vec_func = Function[] for i = 1:20 - rand_number_type = rand(1:10) + rand_number_type = rand(1:20) include_string(Main, "f_vec_$(i)(a::Int) = a == $(i)") sym_func = Symbol("f_vec_$i") push!(vec_tr, :test) @@ -62,17 +62,17 @@ for i = 1:20 end function read(vec_tr::Vector{Union{Nothing,Symbol}}, vec_func::Vector{Function}, a::Int) for i = eachindex(vec_tr) - my_func = vec_func[i] - my_func(a) + vec_func[i](a) end end @btime read(vec_tr, vec_func, 3) +exit() println("Transitions second:") vec_tr = Union{Nothing,Symbol}[] vec_func = Function[] for i = 1:20 - rand_number_type = rand(1:10) + rand_number_type = rand(1:20) name_func = Symbol("f_vec2_$(i)") str_func = "$(name_func)(a::Int) = a == $(rand_number_type)" include_string(Main, str_func) @@ -84,7 +84,7 @@ end # How to store and read efficiently abstract types ? d = Dict{Symbol,Dict{Symbol,Vector{Float64}}}() -for i = 1:10 +for i = 1:20 sym_a = Symbol("a$i") sym_b = Symbol("a$i") d[sym_a] = Dict{Symbol,Vector{Float64}}() diff --git a/bench/pkg/euclidean_distance_repressilator.jl b/bench/pkg/euclidean_distance_repressilator.jl index fd55221..2dacfd7 100644 --- a/bench/pkg/euclidean_distance_repressilator.jl +++ b/bench/pkg/euclidean_distance_repressilator.jl @@ -17,8 +17,7 @@ y_obs = vectorize(simulate(repressilator), :P1, tml_obs) println("Vectorize:") b_vectorize = @benchmark (σ = simulate($(repressilator)); euclidean_distance(σ, :P1, tml_obs, y_obs)) -@btime (σ = simulate($(repressilator))) -@btime (euclidean_distance(σ, :P1, tml_obs, y_obs)) +@btime (σ = simulate($(repressilator)); euclidean_distance(σ, :P1, tml_obs, y_obs)) @show minimum(b_vectorize), mean(b_vectorize), maximum(b_vectorize) println("Automaton with 1 loc") diff --git a/bench/pkg/sim_repressilator.jl b/bench/pkg/sim_repressilator.jl new file mode 100644 index 0000000..56fa166 --- /dev/null +++ b/bench/pkg/sim_repressilator.jl @@ -0,0 +1,18 @@ + +using Statistics +using BenchmarkTools +using MarkovProcesses +import LinearAlgebra: dot +import Distributions: Uniform + +load_automaton("euclidean_distance_automaton") +load_model("repressilator") +tb = 210.0 +tml_obs = 0:10.0:210.0 +set_param!(repressilator, [:α, :β, :n, :α0], [200.0, 2.0, 2.0, 0.0]) +set_time_bound!(repressilator, tb) + +b_sim = @benchmark σ = simulate($(repressilator)) +@btime σ = simulate($(repressilator)) +@show mean(b_sim).time, mean(b_sim).memory + diff --git a/core/MarkovProcesses.jl b/core/MarkovProcesses.jl index e848313..257be50 100644 --- a/core/MarkovProcesses.jl +++ b/core/MarkovProcesses.jl @@ -10,13 +10,14 @@ import Distributed: @everywhere, @distributed import Distributions: Product, Uniform, Normal import Distributions: Distribution, Univariate, Continuous, UnivariateDistribution, MultivariateDistribution, product_distribution -import StaticArrays: SVector +import StaticArrays: SVector, @SVector ## Exports export Distribution, Product, Uniform, Normal # Common types and constructors export Observations, AbstractTrajectory, Trajectory, SynchronizedTrajectory +export SVector, @SVector export Model, ContinuousTimeModel, SynchronizedModel, ParametricModel export VariableModel, ParameterModel, Transition, TransitionSet export LHA, StateLHA, Edge, Location, VariableAutomaton diff --git a/core/network_model.jl b/core/network_model.jl index 455d243..4a9468e 100644 --- a/core/network_model.jl +++ b/core/network_model.jl @@ -154,7 +154,7 @@ macro network_model(expr_network,expr_name...) symbol_func_f! = Symbol("$(basename_func)_f!") str_expr_model_f! = "function $(symbol_func_f!)(xnplus1::Vector{Int}, l_t::Vector{Float64}, l_tr::Vector{Transition}, xn::Vector{Int}, tn::Float64, p::Vector{Float64})\n\t" # Computation of nu and propensity functions in f! - str_l_a = "l_a = (" + str_l_a = "l_a = SVector(" str_test_isabsorbing = "@inbounds(" l_nu = [zeros(Int, dim_state) for i = 1:nbr_reactions] for (i, expr_reaction) in enumerate(list_expr_reactions) @@ -205,8 +205,8 @@ macro network_model(expr_network,expr_name...) str_expr_model_f! *= "return nothing\n\t" str_expr_model_f! *= "end\n\t" # Computation of array of transitions - str_expr_model_f! *= "l_nu = (" * reduce(*, ["nu_$i, " for i = 1:nbr_reactions])[1:(end-2)] * ")\n\t" - str_expr_model_f! *= "l_sym_R = $(Tuple(transitions))\n\t" + str_expr_model_f! *= "l_nu = SVector(" * reduce(*, ["nu_$i, " for i = 1:nbr_reactions])[1:(end-2)] * ")\n\t" + str_expr_model_f! *= "l_sym_R = SVector$(Tuple(transitions))\n\t" # Simulation of the reaction str_expr_model_f! *= "u1 = rand()\n\t" str_expr_model_f! *= "u2 = rand()\n\t" diff --git a/models/ER.jl b/models/ER.jl index bd5d23c..193a4df 100644 --- a/models/ER.jl +++ b/models/ER.jl @@ -12,17 +12,17 @@ t0_ER = 0.0 @inbounds a1 = p[1] * xn[1] * xn[2] @inbounds a2 = p[2] * xn[3] @inbounds a3 = p[3] * xn[3] - l_a = (a1, a2, a3) + l_a = SVector(a1, a2, a3) asum = sum(l_a) if asum == 0.0 copyto!(xnplus1, xn) return nothing end - nu_1 = (-1, -1, 1, 0) - nu_2 = (1, 1, -1, 0) - nu_3 = (1, 0, -1, 1) - l_nu = (nu_1, nu_2, nu_3) - l_str_R = (:R1, :R2, :R3) + nu_1 = SVector(-1, -1, 1, 0) + nu_2 = SVector(1, 1, -1, 0) + nu_3 = SVector(1, 0, -1, 1) + l_nu = SVector(nu_1, nu_2, nu_3) + l_str_R = SVector(:R1, :R2, :R3) u1 = rand() u2 = rand() diff --git a/models/SIR.jl b/models/SIR.jl index 240ab49..7bc5336 100644 --- a/models/SIR.jl +++ b/models/SIR.jl @@ -11,16 +11,16 @@ t0_SIR = 0.0 xn::Vector{Int}, tn::Float64, p::Vector{Float64}) @inbounds a1 = p[1] * xn[1] * xn[2] @inbounds a2 = p[2] * xn[2] - l_a = (a1, a2) + l_a = SVector(a1, a2) asum = sum(l_a) if asum == 0.0 copyto!(xnplus1, xn) return nothing end - nu_1 = (-1, 1, 0) - nu_2 = (0, -1, 1) - l_nu = (nu_1, nu_2) - l_str_R = (:R1,:R2) + nu_1 = SVector(-1, 1, 0) + nu_2 = SVector(0, -1, 1) + l_nu = SVector(nu_1, nu_2) + l_str_R = SVector(:R1,:R2) u1 = rand() u2 = rand() diff --git a/models/SIR_tauleap.jl b/models/SIR_tauleap.jl index 01af738..e6743b5 100644 --- a/models/SIR_tauleap.jl +++ b/models/SIR_tauleap.jl @@ -14,15 +14,15 @@ t0_SIR_tauleap = 0.0 @inbounds tau = p[3] @inbounds a1 = p[1] * xn[1] * xn[2] @inbounds a2 = p[2] * xn[2] - l_a = (a1, a2) + l_a = SVector(a1, a2) asum = sum(l_a) if asum == 0.0 copyto!(xnplus1, xn) return nothing end # column-major order - nu_1 = (-1, 1, 0) - nu_2 = (0, -1, 1) + nu_1 = SVector(-1, 1, 0) + nu_2 = SVector(0, -1, 1) nbr_R1 = (a1 > 0.0) ? rand(Poisson(a1*tau)) : 0.0 nbr_R2 = (a2 > 0.0) ? rand(Poisson(a2*tau)) : 0.0 for i = 1:3 -- GitLab