diff --git a/core/_tests_simulate.jl b/core/_tests_simulate.jl new file mode 100644 index 0000000000000000000000000000000000000000..0f55f06e852ea5bd27bd5f5a86668cd9b0a06e71 --- /dev/null +++ b/core/_tests_simulate.jl @@ -0,0 +1,158 @@ + +# File for benchmarking simulation and memory access of the package. + +_get_values_col(σ::AbstractTrajectory, var::String) = +σ.values[(σ.m)._map_obs_var_idx[var],:] +_get_values_row(σ::AbstractTrajectory, var::String) = +σ.values[:,(σ.m)._map_obs_var_idx[var]] + + +function _simulate_col(m::ContinuousTimeModel) + # trajectory fields + full_values = zeros(m.d, 0) + times = zeros(0) + transitions = Vector{Union{String,Nothing}}(undef,0) + # values at time n + n = 0 + xn = m.x0 + tn = m.t0 + tr = [""] + # at time n+1 + xnplus1 = zeros(Int, m.d) + tnplus1 = zeros(Float64, 1) + is_absorbing = (m.is_absorbing(m.p,xn))::Bool + while !is_absorbing && (tn <= m.time_bound) + m.f!(xnplus1, tnplus1, tr, xn, tn, m.p) + full_values = hcat(full_values, xnplus1) + push!(times, tnplus1[1]) + push!(transitions, tr[1]) + xn, tn = xnplus1, tnplus1[1] + n += 1 + is_absorbing = m.is_absorbing(m.p,xn)::Bool + end + values = @view full_values[m._g_idx,:] + if is_bounded(m) + if times[end] > m.time_bound + values[:, end] = values[:,end-1] + times[end] = m.time_bound + transitions[end] = nothing + end + end + return Trajectory(m, values, times, transitions) +end + +function _simulate_row(m::ContinuousTimeModel) + # trajectory fields + full_values = zeros(m.d, 0) + times = zeros(0) + transitions = Vector{Union{String,Nothing}}(undef,0) + # values at time n + n = 0 + xn = m.x0 + tn = m.t0 + tr = [""] + # at time n+1 + xnplus1 = zeros(Int, m.d) + tnplus1 = zeros(Float64, 1) + is_absorbing = (m.is_absorbing(m.p,xn))::Bool + while !is_absorbing && (tn <= m.time_bound) + m.f!(xnplus1, tnplus1, tr, xn, tn, m.p) + full_values = vcat(full_values, xnplus1) + push!(times, tnplus1[1]) + push!(transitions, tr[1]) + xn, tn = xnplus1, tnplus1[1] + n += 1 + is_absorbing = m.is_absorbing(m.p,xn)::Bool + end + values = @view full_values[m._g_idx,:] + if is_bounded(m) + if times[end] > m.time_bound + values[:, end] = values[:,end-1] + times[end] = m.time_bound + transitions[end] = nothing + end + end + return Trajectory(m, values, times, transitions) +end + + +function _simulate_col_buffer(m::ContinuousTimeModel; buffer_size::Int = 5) + # trajectory fields + full_values = zeros(m.d, 0) + times = zeros(0) + transitions = Vector{Union{String,Nothing}}(undef,0) + # values at time n + n = 0 + xn = m.x0 + tn = m.t0 + # at time n+1 + mat_x = zeros(Int, m.d, buffer_size) + l_t = zeros(Float64, buffer_size) + l_tr = Vector{String}(undef, buffer_size) + is_absorbing = m.is_absorbing(m.p,xn)::Bool + while !is_absorbing && (tn <= m.time_bound) + i = 0 + while i < buffer_size && !is_absorbing && (tn <= m.time_bound) + i += 1 + m.f!(mat_x, l_t, l_tr, i, xn, tn, m.p) + xn = @view mat_x[:,i] + tn = l_t[i] + is_absorbing = m.is_absorbing(m.p,xn)::Bool + end + full_values = hcat(full_values, @view mat_x[:,1:i]) + append!(times, @view l_t[1:i]) + append!(transitions, @view l_tr[1:i]) + n += i + is_absorbing = m.is_absorbing(m.p,xn)::Bool + end + values = @view full_values[m._g_idx,:] + if is_bounded(m) + if times[end] > m.time_bound + values[:, end] = values[:,end-1] + times[end] = m.time_bound + transitions[end] = nothing + end + end + return Trajectory(m, values, times, transitions) +end + +function _simulate_row_buffer(m::ContinuousTimeModel; buffer_size::Int = 5) + # trajectory fields + full_values = zeros(0, m.d) + times = zeros(0) + transitions = Vector{Union{String,Nothing}}(undef,0) + # values at time n + n = 0 + xn = m.x0 + tn = m.t0 + # at time n+1 + mat_x = zeros(Int, buffer_size, m.d) + l_t = zeros(Float64, buffer_size) + l_tr = Vector{String}(undef, buffer_size) + is_absorbing = m.is_absorbing(m.p,xn)::Bool + while !is_absorbing && (tn <= m.time_bound) + i = 0 + while i < buffer_size && !is_absorbing && (tn <= m.time_bound) + i += 1 + m.f!(mat_x, l_t, l_tr, i, xn, tn, m.p) + xn = @view mat_x[:,i] + tn = l_t[i] + is_absorbing = m.is_absorbing(m.p,xn)::Bool + end + full_values = vcat(full_values, @view mat_x[1:i,:]) + append!(times, @view l_t[1:i]) + append!(transitions, @view l_tr[1:i]) + n += i + is_absorbing = m.is_absorbing(m.p,xn)::Bool + end + values = @view full_values[:,m._g_idx] + if is_bounded(m) + if times[end] > m.time_bound + values[end,:] = values[end-1,:] + times[end] = m.time_bound + transitions[end] = nothing + end + end + return Trajectory(m, values, times, transitions) +end + diff --git a/models/_bench_perf_test/SIR_col.jl b/models/_bench_perf_test/SIR_col.jl new file mode 100644 index 0000000000000000000000000000000000000000..00cf2e48e53862d49bb00f4310e1cffe142151dc --- /dev/null +++ b/models/_bench_perf_test/SIR_col.jl @@ -0,0 +1,49 @@ + +import StaticArrays: SVector, SMatrix, @SMatrix + +d=3 +k=2 +dict_var = Dict("S" => 1, "I" => 2, "R" => 3) +dict_p = Dict("ki" => 1, "kr" => 2) +l_tr = ["R1","R2"] +p = [0.0012, 0.05] +x0 = [95, 5, 0] +t0 = 0.0 +function f!(xnplus1::Vector{Int}, tnplus1::Vector{Float64}, tr::Vector{String}, + xn::Vector{Int}, tn::Float64, p::Vector{Float64}) + a1 = p[1] * xn[1] * xn[2] + a2 = p[2] * xn[2] + l_a = SVector(a1, a2) + asum = sum(l_a) + # column-major order + l_nu = @SMatrix [-1 0; + 1 -1; + 0 1] + + u1, u2 = rand(), rand() + tau = - log(u1) / asum + b_inf = 0.0 + b_sup = a1 + reaction = 0 + for i = 1:2 + if b_inf < asum*u2 < b_sup + reaction = i + break + end + b_inf += l_a[i] + b_sup += l_a[i+1] + end + + nu = @view l_nu[:,reaction] # macro for avoiding a copy + xnplus1[1] = xn[1]+nu[1] + xnplus1[2] = xn[2]+nu[2] + xnplus1[3] = xn[3]+nu[3] + tnplus1[1] = tn + tau + tr[1] = "R$(reaction)" +end +is_absorbing_sir(p::Vector{Float64}, xn::Vector{Int}) = (p[1]*xn[1]*xn[2] + p[2]*xn[2]) === 0.0 +g = ["I"] + +SIR_col = CTMC(d,k,dict_var,dict_p,l_tr,p,x0,t0,f!,is_absorbing_sir; g=g) +export SIR_col + diff --git a/models/_bench_perf_test/SIR_col_buffer.jl b/models/_bench_perf_test/SIR_col_buffer.jl new file mode 100644 index 0000000000000000000000000000000000000000..d37828bdbb2eee8145513b1d2217afe11749294d --- /dev/null +++ b/models/_bench_perf_test/SIR_col_buffer.jl @@ -0,0 +1,49 @@ + +import StaticArrays: SVector, SMatrix, @SMatrix + +d=3 +k=2 +dict_var = Dict("S" => 1, "I" => 2, "R" => 3) +dict_p = Dict("ki" => 1, "kr" => 2) +l_tr = ["R1","R2"] +p = [0.0012, 0.05] +x0 = [95, 5, 0] +t0 = 0.0 +function f!(mat_x::Matrix{Int}, l_t::Vector{Float64}, l_tr::Vector{String}, idx::Int, + xn::AbstractVector{Int}, tn::Float64, p::Vector{Float64}) + a1 = p[1] * xn[1] * xn[2] + a2 = p[2] * xn[2] + l_a = SVector(a1, a2) + asum = sum(l_a) + # column-major order + l_nu = @SMatrix [-1 0; + 1 -1; + 0 1] + + u1, u2 = rand(), rand() + tau = - log(u1) / asum + b_inf = 0.0 + b_sup = a1 + reaction = 0 + for i = 1:2 + if b_inf < asum*u2 < b_sup + reaction = i + break + end + b_inf += l_a[i] + b_sup += l_a[i+1] + end + + nu = @view l_nu[:,reaction] # macro for avoiding a copy + for i = 1:3 + mat_x[i,idx] = xn[i]+nu[i] + end + l_t[idx] = tn + tau + l_tr[idx] = "R$(reaction)" +end +is_absorbing_sir(p::Vector{Float64}, xn::AbstractVector{Int}) = (p[1]*xn[1]*xn[2] + p[2]*xn[2]) === 0.0 +g = ["I"] + +SIR_col_buffer = CTMC(d,k,dict_var,dict_p,l_tr,p,x0,t0,f!,is_absorbing_sir; g=g) +export SIR_col_buffer + diff --git a/models/_bench_perf_test/SIR_row_buffer.jl b/models/_bench_perf_test/SIR_row_buffer.jl new file mode 100644 index 0000000000000000000000000000000000000000..366b68b9d120fc8368d32bacdd810af87b8ea3d8 --- /dev/null +++ b/models/_bench_perf_test/SIR_row_buffer.jl @@ -0,0 +1,49 @@ + +import StaticArrays: SVector, SMatrix, @SMatrix + +d=3 +k=2 +dict_var = Dict("S" => 1, "I" => 2, "R" => 3) +dict_p = Dict("ki" => 1, "kr" => 2) +l_tr = ["R1","R2"] +p = [0.0012, 0.05] +x0 = [95, 5, 0] +t0 = 0.0 +function f!(mat_x::Matrix{Int}, l_t::Vector{Float64}, l_tr::Vector{String}, idx::Int, + xn::AbstractVector{Int}, tn::Float64, p::Vector{Float64}) + a1 = p[1] * xn[1] * xn[2] + a2 = p[2] * xn[2] + l_a = SVector(a1, a2) + asum = sum(l_a) + # column-major order + l_nu = @SMatrix [-1 0; + 1 -1; + 0 1] + + u1, u2 = rand(), rand() + tau = - log(u1) / asum + b_inf = 0.0 + b_sup = a1 + reaction = 0 + for i = 1:2 + if b_inf < asum*u2 < b_sup + reaction = i + break + end + b_inf += l_a[i] + b_sup += l_a[i+1] + end + + nu = @view l_nu[:,reaction] # macro for avoiding a copy + for i = 1:3 + mat_x[idx,i] = xn[i]+nu[i] + end + l_t[idx] = tn + tau + l_tr[idx] = "R$(reaction)" +end +is_absorbing_sir(p::Vector{Float64}, xn::AbstractVector{Int}) = (p[1]*xn[1]*xn[2] + p[2]*xn[2]) === 0.0 +g = ["I"] + +SIR_row_buffer = CTMC(d,k,dict_var,dict_p,l_tr,p,x0,t0,f!,is_absorbing_sir; g=g) +export SIR_row_buffer + diff --git a/tests/run_all.jl b/tests/run_all.jl new file mode 100644 index 0000000000000000000000000000000000000000..d8c11f700af560185a8f28890fe4a1e262b4b8d9 --- /dev/null +++ b/tests/run_all.jl @@ -0,0 +1,4 @@ + +include("run_unit.jl") +include("run_simulation.jl") + diff --git a/tests/run_simulation.jl b/tests/run_simulation.jl new file mode 100644 index 0000000000000000000000000000000000000000..224820fe1b65b18a6d63c2dddd4fa5b7bc44fe03 --- /dev/null +++ b/tests/run_simulation.jl @@ -0,0 +1,14 @@ + +using Test +import MarkovProcesses: get_module_path + +str_dir_pics = get_module_path() * "/tests/simulation/res_pics" +if !isdir(str_dir_pics) mkdir(str_dir_pics) end + +@testset "Simulation tests" begin + @test include("simulation/sim_sir.jl") + @test include("simulation/sim_sir_bounded.jl") + @test include("simulation/sim_sir_col_buffer_bounded.jl") + @test include("simulation/sim_er.jl") +end + diff --git a/tests/simulation/sim_er.jl b/tests/simulation/sim_er.jl index f46aaacbdf2bf477e026638f4834b02eb118387a..09d4575b3867d5c5121448031d15717e3a14ed05 100644 --- a/tests/simulation/sim_er.jl +++ b/tests/simulation/sim_er.jl @@ -7,6 +7,8 @@ load_model("ER") σ = simulate(ER) plt.figure() plt.step(σ["times"], σ["P"], "ro--", marker="x", where="post", linewidth=1.0) -plt.savefig("sim_er.png") +plt.savefig(get_module_path() * "/tests/simulation/res_pics/sim_er.png", dpi=480) plt.close() +return true + diff --git a/tests/simulation/sim_sir.jl b/tests/simulation/sim_sir.jl index dca855fa53c4dc48d0fb2ab7cef2871407bd9e49..2a1f00fa21f22f798834fbfd7b4f8edc98ca358b 100644 --- a/tests/simulation/sim_sir.jl +++ b/tests/simulation/sim_sir.jl @@ -7,6 +7,8 @@ load_model("SIR") σ = simulate(SIR) plt.figure() plt.step(σ["times"], σ["I"], "ro--", marker="x", where="post", linewidth=1.0) -plt.savefig("sim_sir.png") +plt.savefig(get_module_path() * "/tests/simulation/res_pics/sim_sir.png") plt.close() +return true + diff --git a/tests/simulation/sim_sir_bounded.jl b/tests/simulation/sim_sir_bounded.jl index bbca0535d2090101c912ff99167c1d499a7e4f99..95d64343b1769a9d6bf7d2b9cde10d7f913dfacc 100644 --- a/tests/simulation/sim_sir_bounded.jl +++ b/tests/simulation/sim_sir_bounded.jl @@ -8,6 +8,8 @@ SIR.time_bound = 100.0 σ = simulate(SIR) plt.figure() plt.step(σ["times"], σ["I"], "ro--", marker="x", where="post", linewidth=1.0) -plt.savefig("sim_sir_bounded.png") +plt.savefig(get_module_path() * "/tests/simulation/res_pics/sim_sir_bounded.png") plt.close() +return true + diff --git a/tests/simulation/sim_sir_col_buffer_bounded.jl b/tests/simulation/sim_sir_col_buffer_bounded.jl new file mode 100644 index 0000000000000000000000000000000000000000..94335f9a0ab35e28bc81d90d2c602c9ad900b0fa --- /dev/null +++ b/tests/simulation/sim_sir_col_buffer_bounded.jl @@ -0,0 +1,16 @@ + +using MarkovProcesses +include(get_module_path() * "/core/_tests_simulate.jl") +using PyPlot + +load_model("_bench_perf_test/SIR_col_buffer") +SIR_col_buffer.time_bound = 100.0 + +σ = _simulate_col_buffer(SIR_col_buffer) +plt.figure() +plt.step(σ["times"], σ["I"], "ro--", marker="x", where="post", linewidth=1.0) +plt.savefig(get_module_path() * "/tests/simulation/res_pics/sim_sir_col_buffer_bounded.png") +plt.close() + +return true +