diff --git a/automata/automaton_F.jl b/automata/automaton_F.jl new file mode 100644 index 0000000000000000000000000000000000000000..38c2c3e3ec5d91958ebb53f7a1292fa58a98ec90 --- /dev/null +++ b/automata/automaton_F.jl @@ -0,0 +1,95 @@ + +function create_automaton_F(m::ContinuousTimeModel, x1::Float64, x2::Float64, t1::Float64, t2::Float64, str_obs::String) + # Locations + l_loc = ["l0", "l1", "l2", "l3"] + + ## Invariant predicates + true_inv_predicate = (A::LHA, S:: StateLHA) -> return true + Λ_F = Dict("l0" => true_inv_predicate, "l1" => true_inv_predicate, + "l2" => true_inv_predicate, "l3" => true_inv_predicate) + + ## Init and final loc + l_loc_init = ["l0"] + l_loc_final = ["l2"] + + #S.n <=> S.l_var[A.map_var_automaton_idx["n"]] + #P <=> xn[map_var_model_idx[l_ctes[str_O]] with str_O = "P". On stock str_O dans l_ctes + + ## Map of automaton variables + map_var_automaton_idx = Dict{VariableAutomaton,Int}("n" => 1, "d" => 2) + + ## Flow of variables + l_flow = Dict{VariableAutomaton,Vector{Float64}}("l0" => [0.0,0.0], + "l1" => [0.0,0.0], + "l2" => [0.0,0.0], + "l3" => [0.0,0.0]) + + ## Edges + map_edges = Dict{Tuple{Location,Location}, Vector{Edge}}() + + # l0 loc : we construct the edges of the form l0 => (..) + # "cc" as check_constraints + tuple = ("l0", "l1") + cc_aut_F_l0l1_1(A::LHA, S::StateLHA) = true + us_aut_F_l0l1_1!(A::LHA, S::StateLHA, x::SubArray{Int,1}) = + (S.loc = "l1"; S["d"] = Inf; S["n"] = get_value(A, x, str_obs)) + edge1 = Edge([nothing], cc_aut_F_l0l1_1, us_aut_F_l0l1_1!) + map_edges[tuple] = [edge1] + + # l1 loc : we construct the edges of the form l1 => (..) + tuple = ("l1", "l2") + cc_aut_F_l1l2_1(A::LHA, S::StateLHA) = + (A.l_ctes["x1"] <= S["n"] <= A.l_ctes["x2"]) && (A.l_ctes["t1"] <= S.time <= A.l_ctes["t2"]) + us_aut_F_l1l2_1!(A::LHA, S::StateLHA, x::SubArray{Int,1}) = (S["d"] = 0; S.loc = "l2") + edge1 = Edge([nothing], cc_aut_F_l1l2_1, us_aut_F_l1l2_1!) + + cc_aut_F_l1l2_2(A::LHA, S::StateLHA) = (S["d"] > 0 && S.time > A.l_ctes["t2"]) + us_aut_F_l1l2_2!(A::LHA, S::StateLHA, x::SubArray{Int,1}) = (S.loc = "l2") + edge2 = Edge([nothing], cc_aut_F_l1l2_2, us_aut_F_l1l2_2!) + + cc_aut_F_l1l2_3(A::LHA, S::StateLHA) = (S["d"] == 0 && S.time >= A.l_ctes["t1"]) + us_aut_F_l1l2_3!(A::LHA, S::StateLHA, x::SubArray{Int,1}) = (S.loc = "l2") + edge3 = Edge([nothing], cc_aut_F_l1l2_3, us_aut_F_l1l2_3!) + + map_edges[tuple] = [edge1, edge2, edge3] + + tuple = ("l1", "l3") + cc_aut_F_l1l3_1(A::LHA, S::StateLHA) = (A.l_ctes["x1"] <= S["n"] <= A.l_ctes["x2"]) + us_aut_F_l1l3_1!(A::LHA, S::StateLHA, x::SubArray{Int,1}) = (S["d"] = 0; S.loc = "l3") + edge1 = Edge([nothing], cc_aut_F_l1l3_1, us_aut_F_l1l3_1!) + + cc_aut_F_l1l3_2(A::LHA, S::StateLHA) = + (A.l_ctes["x1"] > S["n"] || S["n"] > A.l_ctes["x2"]) && (S.time < A.l_ctes["t1"]) + us_aut_F_l1l3_2!(A::LHA, S::StateLHA, x::SubArray{Int,1}) = + (S["d"] = min(sqrt((S.time - A.l_ctes["t1"])^2 + (S["n"] - A.l_ctes["x2"])^2), + sqrt((S.time - A.l_ctes["t1"])^2 + (S["n"] - A.l_ctes["x1"])^2)); S.loc = "l3") + edge2 = Edge([nothing], cc_aut_F_l1l3_2, us_aut_F_l1l3_2!) + + cc_aut_F_l1l3_3(A::LHA, S::StateLHA) = + (A.l_ctes["x1"] > S["n"] || S["n"] > A.l_ctes["x2"]) && (A.l_ctes["t1"] <= S.time <= A.l_ctes["t2"]) + us_aut_F_l1l3_3!(A::LHA, S::StateLHA, x::SubArray{Int,1}) = + (S["d"] = min(S["d"], min(abs(S["n"] - A.l_ctes["x1"]), abs(S["n"] - A.l_ctes["x2"]))); S.loc = "l3") + edge3 = Edge([nothing], cc_aut_F_l1l3_3, us_aut_F_l1l3_3!) + map_edges[tuple] = [edge1, edge2, edge3] + + # l3 loc + tuple = ("l3", "l1") + cc_aut_F_l3l1_1(A::LHA, S::StateLHA) = true + us_aut_F_l3l1_1!(A::LHA, S::StateLHA, x::SubArray{Int,1}) = (S["n"] = get_value(A, x, str_obs); S.loc = "l1") + edge1 = Edge(["ALL"], cc_aut_F_l3l1_1, us_aut_F_l3l1_1!) + tuple = ("l3", "l2") + cc_aut_F_l3l2_1(A::LHA, S::StateLHA) = (S.time >= A.l_ctes["t2"]) + us_aut_F_l3l2_1!(A::LHA, S::StateLHA, x::SubArray{Int,1}) = (S["n"] = get_value(A, x, str_obs); S.loc = "l2") + edge2 = Edge([nothing], cc_aut_F_l3l2_1, us_aut_F_l3l2_1!) + map_edges[tuple] = [edge1, edge2] + + ## Constants + l_ctes = Dict{String,Float64}("x1" => x1, "x2" => x2, "t1" => t1, "t2" => t2) + + A = LHA(m.l_transitions, l_loc, Λ_F, l_loc_init, l_loc_final, + map_var_automaton_idx, l_flow, map_edges, l_ctes, m.map_var_idx) + return A +end + +export create_automaton_F + diff --git a/core/MarkovProcesses.jl b/core/MarkovProcesses.jl index e9d26143b64737cb6bfd92bb7230dffc295c5ba6..dfb23e636f9006dae1ff89f483f3f3068cf29155 100644 --- a/core/MarkovProcesses.jl +++ b/core/MarkovProcesses.jl @@ -1,6 +1,7 @@ module MarkovProcesses -import Base: +, -, getfield, getindex, ImmutableDict +import Base: +, -, * +import Base: copy, getfield, getindex, lastindex, setindex!, getproperty, setproperty! export Model, ContinuousTimeModel, DiscreteTimeModel export simulate, set_param!, get_param, set_observed_var! @@ -10,8 +11,15 @@ include("model.jl") export Observations, AbstractTrajectory, Trajectory export +, -, δ, dist_lp -export get_obs_var, length_states, length_obs_var, is_bounded, times, transitions +export get_obs_var, length_states, length_obs_var, get_state_from_time +export is_bounded, times, transitions +export check_consistency, is_steadystate include("trajectory.jl") +export LHA, StateLHA, Edge +export init_state, next_state!, read_trajectory +export load_automaton, get_index, get_value, length_var +include("lha.jl") + end diff --git a/core/lha.jl b/core/lha.jl new file mode 100644 index 0000000000000000000000000000000000000000..c3a1359f21325003170185931e2a73f370e35d9a --- /dev/null +++ b/core/lha.jl @@ -0,0 +1,161 @@ + +const Location = String +const VariableAutomaton = String + +struct Edge + transitions::Vector{Transition} + check_constraints::Function + update_state!::Function +end + +struct LHA + l_transitions::Vector{Transition} + l_loc::Vector{Location} + Λ::Dict{Location,Function} + l_loc_init::Vector{Location} + l_loc_final::Vector{Location} + map_var_automaton_idx::Dict{VariableAutomaton,Int} # nvar keys : str_var => idx in l_var + l_flow::Dict{Location,Vector{Float64}} # output of length nvar + map_edges::Dict{Tuple{Location,Location},Vector{Edge}} + l_ctes::Dict{String,Float64} + map_var_model_idx::Dict{String,Int} # of dim d (of a model) +end + +LHA(A::LHA, map_var::Dict{String,Int}) = LHA(A.l_transitions, A.l_loc, A.Λ, + A.l_loc_init, A.l_loc_final, A.map_var_automaton_idx, A.l_flow, + A.map_edges, A.l_ctes, map_var) +length_var(A::LHA) = length(A.map_var_automaton_idx) +get_value(A::LHA, x::SubArray{Int,1}, var::String) = x[A.map_var_model_idx[var]] +load_automaton(automaton::String) = include(get_module_path() * "/automata/$(automaton).jl") + +mutable struct StateLHA + A::LHA + loc::Location + l_var::Vector{Float64} + time::Float64 +end + +copy(S::StateLHA) = StateLHA(S.A, S.loc, S.l_var, S.time) +# Not overring getproperty, setproperty to avoid a conversion Symbol => String for the dict key +getindex(S::StateLHA, var::VariableAutomaton) = (S.l_var)[(S.A).map_var_automaton_idx[var]] +setindex!(S::StateLHA, val::Float64, var::VariableAutomaton) = (S.l_var)[(S.A).map_var_automaton_idx[var]] = val +setindex!(S::StateLHA, val::Int, var::VariableAutomaton) = (S.l_var)[(S.A).map_var_automaton_idx[var]] = convert(Float64, val) +function Base.show(io::IO, S::StateLHA) + print(io, "State of LHA\n") + print(io, "- location: $(S.loc)\n") + print(io, "- time: $(S.time)\n") + print(io, "- variables:\n") + for (var, idx) in (S.A).map_var_automaton_idx + print(io, "* $var = $(S.l_var[idx])\n") + end +end + +function init_state(A::LHA, x0::SubArray{Int,1}, t0::Float64) + S0 = StateLHA(A, "", zeros(length_var(A)), t0) + for loc in A.l_loc_init + if A.Λ[loc](A,S0) + S0.loc = loc + break + end + end + return S0 +end + +function next_state!(Snplus1::StateLHA, A::LHA, + xnplus1::SubArray{Int,1}, tnplus1::Float64, tr_nplus1::Transition, + Sn::StateLHA; verbose = false) + for i in eachindex(Snplus1.l_var) + Snplus1.l_var[i] += (A.l_flow[Sn.loc])[i]*(tnplus1 - Sn.time) + end + Snplus1.time = tnplus1 + + # En fait d'apres observation de Cosmos, après qu'on ait lu la transition on devrait stop. + edge_candidates = Edge[] + tuple_candidates = Tuple{Location, Location}[] + first_round = true + detected_event = (tr_nplus1 == nothing) ? true : false + turns = 1 + while first_round || !detected_event || length(edge_candidates) > 0 + edge_candidates = Edge[] + tuple_candidates = Tuple{Location,Location}[] + current_loc = Snplus1.loc + if verbose + @show turns + end + # Save all edges that satisfies transition predicate (synchronous or autonomous) + for loc in A.l_loc + tuple_edges = (current_loc, loc) + if haskey(A.map_edges, tuple_edges) + for edge in A.map_edges[tuple_edges] + if edge.check_constraints(A, Snplus1) + push!(edge_candidates, edge) + push!(tuple_candidates, tuple_edges) + end + end + end + end + # Search the one we must chose + ind_edge = 0 + for (i, edge) in enumerate(edge_candidates) + if edge.transitions[1] == nothing + ind_edge = i + break + end + if first_round || !detected_event + if (length(edge.transitions) == 1 && tr_nplus1 != nothing && edge.transitions[1] == "ALL") || + (tr_nplus1 in edge.transitions) + detected_event = true + ind_edge = i + end + end + end + # Update the state with the chosen one (if it exists) + if ind_edge > 0 + edge_candidates[ind_edge].update_state!(A, Snplus1, xnplus1) + # Should add something like if edges_candidates[ind_edge].transition != nohting break end ?? + end + if verbose + @show first_round, detected_event + @show tnplus1, tr_nplus1, xnplus1 + @show ind_edge + @show edge_candidates + @show tuple_candidates + @show Snplus1 + end + if ind_edge == 0 break end + # For debug + if turns > 10 + println("Turns, Bad behavior of region2 automaton") + @show first_round, detected_event + @show length(edge_candidates) + @show tnplus1, tr_nplus1, xnplus1 + @show edge_candidates + for edge in edge_candidates + @show edge.check_constraints(A, Snplus1) + end + error("Unpredicted behavior automaton F v2") + end + turns += 1 + first_round = false + end +end + +# For debug purposes +function read_trajectory(A::LHA, σ::Trajectory; verbose = false) + A_new = LHA(A, (σ.m)._map_obs_var_idx) + l_t = times(σ) + l_tr = transitions(σ) + Sn = init_state(A_new, σ[1], l_t[1]) + Snplus1 = copy(Sn) + if verbose println("Init: ") end + if verbose @show Sn end + for n in 1:length_states(σ) + next_state!(Snplus1, A_new, σ[n], l_t[n], l_tr[n], Sn; verbose = verbose) + if Snplus1.loc in A_new.l_loc_final + break + end + Sn = Snplus1 + end + return Sn +end + diff --git a/core/model.jl b/core/model.jl index e2b23b07b0b24c4bac76e3449a3cc51f3a47b75d..6b4614814c5ba92a00634483ede1e95337fc5116 100644 --- a/core/model.jl +++ b/core/model.jl @@ -3,14 +3,16 @@ import StaticArrays: SVector abstract type Model end abstract type DiscreteTimeModel <: Model end +const Transition = Union{String,Nothing} +# Model types mutable struct ContinuousTimeModel <: Model d::Int # state space dim k::Int # parameter space dim map_var_idx::Dict{String,Int} # maps str to full state space _map_obs_var_idx::Dict{String,Int} # maps str to observed state space map_param_idx::Dict{String,Int} # maps str in parameter space - l_name_transitions::Vector{String} + l_transitions::Vector{Transition} p::Vector{Float64} x0::Vector{Int} t0::Float64 @@ -22,7 +24,7 @@ mutable struct ContinuousTimeModel <: Model buffer_size::Int end -function ContinuousTimeModel(d::Int, k::Int, map_var_idx::Dict, map_param_idx::Dict, l_name_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, f!::Function, is_absorbing::Function; g::Vector{String} = keys(map_var_idx), time_bound::Float64 = Inf, buffer_size::Int = 10) @@ -41,9 +43,17 @@ function ContinuousTimeModel(d::Int, k::Int, map_var_idx::Dict, map_param_idx::D @warn "You have possibly redefined a function Model.is_absorbing used in a previously instantiated model." end - return ContinuousTimeModel(d, k, map_var_idx, _map_obs_var_idx, map_param_idx, l_name_transitions, p, x0, t0, f!, g, _g_idx, is_absorbing, 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, is_absorbing, time_bound, buffer_size) end +#= +mutable struct SynchronizedModel + m::ContinuousTimeModel + automaton::LHA +end +=# + +# Simulation function simulate(m::ContinuousTimeModel) # trajectory fields full_values = Matrix{Int}(undef, 1, m.d) @@ -89,6 +99,62 @@ function simulate(m::ContinuousTimeModel) return Trajectory(m, values, times, transitions) end +#= +function simulate(product::SynchronizedModel) + # trajectory fields + m = product.m + A = product.automaton + full_values = Matrix{Int}(undef, 1, m.d) + full_values[1,:] = m.x0 + times = Float64[m.t0] + transitions = Union{String,Nothing}[nothing] + reshaped_x0 = view(reshape(m.x0, 1, m.d), 1, :) # View for type stability + S0 = init_state(A, reshaped_x0, t0) + # values at time n + n = 0 + xn = reshaped_x0 + tn = m.t0 + Sn = copy(S0) + # at time n+1 + mat_x = zeros(Int, m.buffer_size, m.d) + l_t = zeros(Float64, m.buffer_size) + l_tr = Vector{String}(undef, m.buffer_size) + is_absorbing::Bool = m.is_absorbing(m.p,xn) + Snplus1 = copy(Sn) + while !is_absorbing && (tn < m.time_bound) + i = 0 + while i < m.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] + tr_n = l_tr[n] + A.next_state!(Snplus1, A, xn, tn, tr_n, Sn) + Sn = Snplus1 + is_absorbing = m.is_absorbing(m.p,xn) + 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) + end + if is_bounded(m) + if times[end] > m.time_bound + full_values[end,:] = full_values[end-1,:] + times[end] = m.time_bound + transitions[end] = nothing + else + full_values = vcat(full_values, reshape(full_values[end,:], 1, m.d)) + push!(times, m.time_bound) + push!(transitions, nothing) + end + end + values = view(full_values, :, m._g_idx) + return Trajectory(m, values, times, transitions) +end +=# + function simulate(m::ContinuousTimeModel, n::Int) obs = ContinuousObservations(undef, n) for i = 1:n diff --git a/core/trajectory.jl b/core/trajectory.jl index 6f8ce4ad82bd4a37f03a74d3ef35e54a6b54ef87..37e969764f16ad6281e3ded37f380b6a5076c510 100644 --- a/core/trajectory.jl +++ b/core/trajectory.jl @@ -6,7 +6,7 @@ struct Trajectory <: AbstractTrajectory m::ContinuousTimeModel values::Matrix{Int} times::Vector{Float64} - transitions::Vector{Union{String,Nothing}} + transitions::Vector{Transition} end # Operations @@ -15,7 +15,7 @@ function -(σ1::AbstractTrajectory,σ2::AbstractTrajectory) end # Top-level Lp distance function """ - `dist_lp(l_σ1, l_σ2; verbose, p, str_stat_list, str_stat_trajectory)` +`dist_lp(l_σ1, l_σ2; verbose, p, str_stat_list, str_stat_trajectory)` Function that computes Lp distance between two set of any dimensional trajectories. ... @@ -35,7 +35,7 @@ function dist_lp(l_σ1::Vector{<:AbstractTrajectory}, l_σ2::Vector{<:AbstractTr end """ - `dist_lp(σ1, σ2; verbose, p, str_stat)` +`dist_lp(σ1, σ2; verbose, p, str_stat)` Function that computes Lp distance between two trajectories of any dimension. It computes Lp distances for each observed variable (contained in `get_obs_var(σ)`). and then apply a statistic on these distances. @@ -57,7 +57,7 @@ function dist_lp(σ1::AbstractTrajectory, σ2::AbstractTrajectory; end """ - `dist_lp(σ1, σ2, var; verbose, p, str_stat)` +`dist_lp(σ1, σ2, var; verbose, p, str_stat)` Function that computes Lp distance between two trajectories of any dimension. It computes Lp distances for each observed variable (contained in `get_obs_var(σ)`). and then apply a statistic on these distances. @@ -131,7 +131,7 @@ function dist_lp_mean(σ1::AbstractTrajectory, σ2::AbstractTrajectory; end # For a list of trajectories function dist_lp_mean(l_σ1::Vector{<:AbstractTrajectory}, l_σ2::Vector{<:AbstractTrajectory}; - verbose::Bool = false, p::Int = 1, str_stat_trajectory::String = "mean") + verbose::Bool = false, p::Int = 1, str_stat_trajectory::String = "mean") res = 0.0 for σ1 in l_σ1 for σ2 in l_σ2 @@ -164,12 +164,12 @@ function _riemann_sum(f::Function, t_begin::Real, t_end::Real, step::Float64) end function check_consistency(σ::AbstractTrajectory) - test_sizes = length(σ.times) == length(σ.transitions) == size(σ.values)[1] - test_obs_var = length_obs_var(σ) == length(σ.m.g) == size(σ.values)[2] - if !test_sizes error("Issue between sizes of values/times/transitions in this trajectory.") end - if !test_obs_var error("Issue between sizes of observed variables in model and values") end + @assert length(σ.times) == length(σ.transitions) == size(σ.values)[1] + @assert length_obs_var(σ) == length(σ.m.g) == size(σ.values)[2] return true end +is_steadystate(σ::AbstractTrajectory) = (σ.m).is_absorbing((σ.m).p, σ[end]) + # Properties of the trajectory length_states(σ::AbstractTrajectory) = length(σ.times) @@ -178,15 +178,29 @@ get_obs_var(σ::AbstractTrajectory) = (σ.m).g is_bounded(σ::AbstractTrajectory) = σ.transitions[end] == nothing # Access to trajectory values -get_var_values(σ::AbstractTrajectory, var::String) = - view(σ.values, :, (σ.m)._map_obs_var_idx[var]) -get_state(σ::AbstractTrajectory, idx::Int) = - view(σ.values, idx, :) -get_value(σ::AbstractTrajectory, var::String, idx::Int) = - σ.values[idx,(σ.m)._map_obs_var_idx[var]] - - -δ(σ::AbstractTrajectory,t::Float64) = true +get_var_values(σ::AbstractTrajectory, var::String) = view(σ.values, :, (σ.m)._map_obs_var_idx[var]) +get_state(σ::AbstractTrajectory, idx::Int) = view(σ.values, idx, :) +get_value(σ::AbstractTrajectory, var::String, idx::Int) = σ.values[idx,(σ.m)._map_obs_var_idx[var]] +# Operation @ +function get_state_from_time(σ::AbstractTrajectory, t::Float64) + @assert t >= 0.0 + l_t = times(σ) + if t == l_t[end] return σ[end] end + if t > l_t[end] + if !is_bounded(σ) + return σ[end] + else + error("This trajectory is bounded and you're accessing out of the bounds") + end + end + for i in eachindex(l_t) + if l_t[i] <= t < l_t[i+1] + return σ[i] + end + end + error("Unexpected behavior") +end +δ(σ::AbstractTrajectory,idx::Int) = times(σ)[i+1] - times(σ)[i] states(σ::AbstractTrajectory) = σ.values times(σ::AbstractTrajectory) = σ.times @@ -198,4 +212,5 @@ getindex(σ::AbstractTrajectory, idx::Int) = get_state(σ, idx) getindex(σ::AbstractTrajectory, var::String, idx::Int) = get_value(σ, var, idx) # Get the path of a variable ["I"] getindex(σ::AbstractTrajectory, var::String) = get_var_values(σ, var) +lastindex(σ::AbstractTrajectory) = length_states(σ) diff --git a/tests/automata/automaton_F.jl b/tests/automata/automaton_F.jl new file mode 100644 index 0000000000000000000000000000000000000000..8b70061e297bb87ed66ce9027926ee051b1ed267 --- /dev/null +++ b/tests/automata/automaton_F.jl @@ -0,0 +1,12 @@ + +using MarkovProcesses + +load_model("SIR") +load_automaton("automaton_F") +SIR.time_bound = 120.0 +x1, x2, t1, t2 = 0.0, Inf, 100.0, 120.0 +A_F = create_automaton_F(SIR, x1, x2, t1, t2, "I") # <: LHA + +#sync_SIR = SIR * A_F +#σ, state_lha = simulate(sync_SIR) + diff --git a/tests/automata/read_trajectory_last_state_F.jl b/tests/automata/read_trajectory_last_state_F.jl new file mode 100644 index 0000000000000000000000000000000000000000..636080d5abe3e04ccbc4ad9b18f1ab115c47cede --- /dev/null +++ b/tests/automata/read_trajectory_last_state_F.jl @@ -0,0 +1,32 @@ + +using MarkovProcesses + +load_model("SIR") +load_automaton("automaton_F") +SIR.time_bound = 120.0 +x1, x2, t1, t2 = 0.0, Inf, 100.0, 120.0 + +A_F = create_automaton_F(SIR, x1, x2, t1, t2, "I") # <: LHA + +function test_last_state(A::LHA, m::ContinuousTimeModel) + σ = simulate(m) + Send = read_trajectory(A, σ) + test = (get_state_from_time(σ, Send.time)[1] == Send["n"]) & (Send["d"] == 0) + #= + if !test + @show Send + @show get_state_from_time(σ, Send.time) + error("tkt") + end=# + return test +end + +test_all = true +nbr_sim = 10000 +for i = 1:nbr_sim + test = test_last_state(A_F, SIR) + global test_all = test_all & test +end + +return test_all + diff --git a/tests/run_all.jl b/tests/run_all.jl index e1433d2a44cd2e7de93f15912c657758868ad269..5ed6f292c64e5b11d3a0008f10150b3ec9ec2cf0 100644 --- a/tests/run_all.jl +++ b/tests/run_all.jl @@ -2,4 +2,5 @@ include("run_unit.jl") include("run_simulation.jl") include("run_dist_lp.jl") +include("run_automata.jl") diff --git a/tests/run_automata.jl b/tests/run_automata.jl new file mode 100644 index 0000000000000000000000000000000000000000..abec4d04c8ce02da9f18e5067be5dc6eceaf93d9 --- /dev/null +++ b/tests/run_automata.jl @@ -0,0 +1,7 @@ + +using Test + +@testset "Automata tests" begin + @test include("automata/read_trajectory_last_state_F.jl") +end + diff --git a/tests/run_bench.jl b/tests/run_bench.jl new file mode 100644 index 0000000000000000000000000000000000000000..5b6a694fa7e58d57e50e3f5d8f0a80e9b78b4d1d --- /dev/null +++ b/tests/run_bench.jl @@ -0,0 +1,16 @@ + +using Test +import MarkovProcesses: get_module_path + +path_bench = get_module_path() * "/bench/" +function include_arg!(path_file::String, arg::String) + global ARGS = [arg] + include(path_bench * "array_memory_order/sim.jl") + return true +end + +@testset "Benchmark" begin + @test include_arg!(path_bench * "array_memory_order/sim.jl", "SIR") + @test include_arg!(path_bench * "pygmalion/sim_sir.jl", "SIR") +end +