From f4c41acb822d97b116aeffc9efe5923e9d5e3e72 Mon Sep 17 00:00:00 2001 From: Mahmoud Bentriou <mahmoud.bentriou@centralesupelec.fr> Date: Tue, 1 Dec 2020 18:04:17 +0100 Subject: [PATCH] Test of distance G automaton passes! The two Cosmos tests checks the statistical correctness of estimated distance value for R1,R2,R3,R5 experiments. Also, they test that all trajectories are accepted. A bunch of errors were fixed in automata files (Cosmos .lha and julia ./automata files) and simulation function that introduced statistical bias, i.e. approximated values that were closed but not in the confidence interval. The general structure of simulation and was reworked in order to suits well te behavior of Cosmos. --- automata/automaton_F.jl | 57 ++++++++---- automata/automaton_G.jl | 94 +++++++++----------- core/lha.jl | 122 +++++++++++++++++++------- core/model.jl | 53 +++++++---- core/plots.jl | 3 +- tests/cosmos/distance_F/ER_1D.jl | 6 +- tests/cosmos/distance_F/dist_F_ER.lha | 23 +++-- tests/cosmos/distance_G/ER_R5.jl | 12 ++- tests/cosmos/distance_G/dist_G_ER.lha | 2 +- tests/run_cosmos.jl | 1 + 10 files changed, 239 insertions(+), 134 deletions(-) diff --git a/automata/automaton_F.jl b/automata/automaton_F.jl index b464a7a..1918388 100644 --- a/automata/automaton_F.jl +++ b/automata/automaton_F.jl @@ -35,43 +35,62 @@ function create_automaton_F(m::ContinuousTimeModel, x1::Float64, x2::Float64, t1 tuple = ("l0", "l1") cc_aut_F_l0l1_1(A::LHA, S::StateLHA) = true us_aut_F_l0l1_1!(A::LHA, S::StateLHA, x::Vector{Int}) = - (S.loc = "l1"; S["d"] = Inf; S["n"] = get_value(A, x, str_obs)) + (S.loc = "l1"; + S["d"] = Inf; + S["n"] = get_value(A, x, str_obs); + S["isabs"] = m.isabsorbing(m.p,x)) 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::Vector{Int}) = (S["d"] = 0; S.loc = "l2") + (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::Vector{Int}) = + (S.loc = "l2"; + S["d"] = 0) 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"] || istrue(S["isabs"]))) - us_aut_F_l1l2_2!(A::LHA, S::StateLHA, x::Vector{Int}) = (S.loc = "l2") + cc_aut_F_l1l2_2(A::LHA, S::StateLHA) = + S["d"] > 0 && + (S.time > A.l_ctes["t2"] || istrue(S["isabs"])) + us_aut_F_l1l2_2!(A::LHA, S::StateLHA, x::Vector{Int}) = + (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::Vector{Int}) = (S.loc = "l2") + 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::Vector{Int}) = + (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::Vector{Int}) = (S["d"] = 0; S.loc = "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::Vector{Int}) = + (S.loc = "l3"; + S["d"] = 0;) 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"]) + (S["n"] < A.l_ctes["x1"] || S["n"] > A.l_ctes["x2"]) && + (S.time <= A.l_ctes["t1"]) us_aut_F_l1l3_2!(A::LHA, S::StateLHA, x::Vector{Int}) = - (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") + (S.loc = "l3"; + 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))) 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"]) + (S["n"] < A.l_ctes["x1"] || 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::Vector{Int}) = - (S["d"] = min(S["d"], min(abs(S["n"] - A.l_ctes["x1"]), abs(S["n"] - A.l_ctes["x2"]))); S.loc = "l3") + (S.loc = "l3"; + S["d"] = min(S["d"], min(abs(S["n"] - A.l_ctes["x1"]), abs(S["n"] - A.l_ctes["x2"])))) edge3 = Edge([nothing], cc_aut_F_l1l3_3, us_aut_F_l1l3_3!) map_edges[tuple] = [edge1, edge2, edge3] @@ -79,11 +98,15 @@ function create_automaton_F(m::ContinuousTimeModel, x1::Float64, x2::Float64, t1 tuple = ("l3", "l1") cc_aut_F_l3l1_1(A::LHA, S::StateLHA) = true us_aut_F_l3l1_1!(A::LHA, S::StateLHA, x::Vector{Int}) = - (S["n"] = get_value(A, x, str_obs); S.loc = "l1"; S["isabs"] = m.isabsorbing(m.p,x)) + (S.loc = "l1"; + S["n"] = get_value(A, x, str_obs); + S["isabs"] = m.isabsorbing(m.p,x)) 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::Vector{Int}) = (S["n"] = get_value(A, x, str_obs); S.loc = "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::Vector{Int}) = + (S.loc = "l2") edge2 = Edge([nothing], cc_aut_F_l3l2_1, us_aut_F_l3l2_1!) map_edges[tuple] = [edge1, edge2] diff --git a/automata/automaton_G.jl b/automata/automaton_G.jl index 9c982c9..c221098 100644 --- a/automata/automaton_G.jl +++ b/automata/automaton_G.jl @@ -15,7 +15,7 @@ function create_automaton_G(m::ContinuousTimeModel, x1::Float64, x2::Float64, t1 l_loc_final = ["l2"] ## Map of automaton variables - map_var_automaton_idx = Dict{VariableAutomaton,Int}("t'" => 1, "in" => 2, + map_var_automaton_idx = Dict{VariableAutomaton,Int}("tprime" => 1, "in" => 2, "n" => 3, "d" => 4, "isabs" => 5) ## Flow of variables @@ -34,15 +34,19 @@ function create_automaton_G(m::ContinuousTimeModel, x1::Float64, x2::Float64, t1 tuple = ("l0", "l1") cc_aut_G_l0l1_1(A::LHA, S::StateLHA) = true us_aut_G_l0l1_1!(A::LHA, S::StateLHA, x::Vector{Int}) = - (S.loc = "l1"; S["d"] = 0; S["n"] = get_value(A, x, str_obs); S["in"] = true; S["isabs"] = m.isabsorbing(m.p,x)) + (S.loc = "l1"; + S["d"] = 0; + S["n"] = get_value(A, x, str_obs); + S["in"] = true; + S["isabs"] = m.isabsorbing(m.p,x)) edge1 = Edge([nothing], cc_aut_G_l0l1_1, us_aut_G_l0l1_1!) map_edges[tuple] = [edge1] # l1 loc tuple = ("l1", "l3") cc_aut_G_l1l3_1(A::LHA, S::StateLHA) = - (S.time < A.l_ctes["t1"] && - (S["n"] < A.l_ctes["x1"] || S["n"] > A.l_ctes["x2"])) + S.time <= A.l_ctes["t1"] && + S["n"] < A.l_ctes["x1"] || S["n"] > A.l_ctes["x2"] us_aut_G_l1l3_1!(A::LHA, S::StateLHA, x::Vector{Int}) = (S.loc = "l3"; S["d"] = min(abs(A.l_ctes["x1"] - S["n"]), abs(A.l_ctes["x2"] - S["n"])); @@ -56,7 +60,7 @@ function create_automaton_G(m::ContinuousTimeModel, x1::Float64, x2::Float64, t1 us_aut_G_l1l3_3!(A::LHA, S::StateLHA, x::Vector{Int}) = (S.loc = "l3"; S["d"] = S["d"] * (S.time - A.l_ctes["t1"]); - S["t'"] = 0.0) + S["tprime"] = 0.0) edge3 = Edge([nothing], cc_aut_G_l1l3_3, us_aut_G_l1l3_3!) cc_aut_G_l1l3_2(A::LHA, S::StateLHA) = @@ -74,7 +78,7 @@ function create_automaton_G(m::ContinuousTimeModel, x1::Float64, x2::Float64, t1 (A.l_ctes["x1"] <= S["n"] <= A.l_ctes["x2"]) us_aut_G_l1l3_4!(A::LHA, S::StateLHA, x::Vector{Int}) = (S.loc = "l3"; - S["t'"] = 0.0) + S["tprime"] = 0.0) edge4 = Edge([nothing], cc_aut_G_l1l3_4, us_aut_G_l1l3_4!) map_edges[tuple] = [edge1, edge2, edge3, edge4] @@ -111,7 +115,23 @@ function create_automaton_G(m::ContinuousTimeModel, x1::Float64, x2::Float64, t1 (S.loc = "l2"; S["d"] = S["d"] * (A.l_ctes["t2"] - A.l_ctes["t1"])) edge2 = Edge([nothing], cc_aut_G_l1l2_2, us_aut_G_l1l2_2!) - map_edges[tuple] = [edge1, edge2] + cc_aut_G_l1l2_3(A::LHA, S::StateLHA) = + istrue(S["isabs"]) && + S.time <= A.l_ctes["t1"] + us_aut_G_l1l2_3!(A::LHA, S::StateLHA, x::Vector{Int}) = + (S.loc = "l2"; + S["d"] = S["d"] * (A.l_ctes["t2"] - A.l_ctes["t1"])) + edge3 = Edge([nothing], cc_aut_G_l1l2_3, us_aut_G_l1l2_3!) + cc_aut_G_l1l2_4(A::LHA, S::StateLHA) = + istrue(S["isabs"]) && + (A.l_ctes["t1"] <= S.time <= A.l_ctes["t2"]) + us_aut_G_l1l2_4!(A::LHA, S::StateLHA, x::Vector{Int}) = + (S.loc = "l2"; + S["d"] += (A.l_ctes["t2"] - S.time) * + min(abs(A.l_ctes["x1"] - S["n"]), abs(A.l_ctes["x1"] - S["n"]))) + edge4 = Edge([nothing], cc_aut_G_l1l2_4, us_aut_G_l1l2_4!) + + map_edges[tuple] = [edge1, edge2, edge3, edge4] # l3 loc tuple = ("l3", "l1") @@ -124,44 +144,29 @@ function create_automaton_G(m::ContinuousTimeModel, x1::Float64, x2::Float64, t1 map_edges[tuple] = [edge1] tuple = ("l3", "l2") - cc_aut_G_l3l2_1(A::LHA, S::StateLHA) = - istrue(S["in"]) && - (S.time >= A.l_ctes["t2"] || istrue(S["isabs"])) - us_aut_G_l3l2_1!(A::LHA, S::StateLHA, x::Vector{Int}) = - (S.loc = "l2") - edge1 = Edge([nothing], cc_aut_G_l3l2_1, us_aut_G_l3l2_1!) cc_aut_G_l3l2_2(A::LHA, S::StateLHA) = - !istrue(S["in"]) && - (S.time >= A.l_ctes["t2"] || istrue(S["isabs"])) + istrue(S["in"]) && + S.time >= A.l_ctes["t2"] us_aut_G_l3l2_2!(A::LHA, S::StateLHA, x::Vector{Int}) = (S.loc = "l2"; S["d"] = S["d"] * (A.l_ctes["t2"] - A.l_ctes["t1"])) edge2 = Edge([nothing], cc_aut_G_l3l2_2, us_aut_G_l3l2_2!) - cc_aut_G_l3l2_3(A::LHA, S::StateLHA) = - istrue(S["isabs"]) && - S.time <= A.l_ctes["t1"] - us_aut_G_l3l2_3!(A::LHA, S::StateLHA, x::Vector{Int}) = - (S.loc = "l2"; - S["d"] = S["d"] * (A.l_ctes["t2"] - A.l_ctes["t1"])) - edge3 = Edge([nothing], cc_aut_G_l3l2_3, us_aut_G_l3l2_3!) - cc_aut_G_l3l2_4(A::LHA, S::StateLHA) = - istrue(S["isabs"]) && - S.time >= A.l_ctes["t1"] - us_aut_G_l3l2_4!(A::LHA, S::StateLHA, x::Vector{Int}) = - (S.loc = "l2"; - S["d"] += (A.l_ctes["t2"] - A.l_ctes["t1"]) * - min(abs(S["n"] - A.l_ctes["x1"]), abs(S["n"] - A.l_ctes["x2"]))) - edge4 = Edge([nothing], cc_aut_G_l3l2_4, us_aut_G_l3l2_4!) + cc_aut_G_l3l2_1(A::LHA, S::StateLHA) = + !istrue(S["in"]) && + S.time >= A.l_ctes["t2"] + us_aut_G_l3l2_1!(A::LHA, S::StateLHA, x::Vector{Int}) = + (S.loc = "l2") + edge1 = Edge([nothing], cc_aut_G_l3l2_1, us_aut_G_l3l2_1!) - map_edges[tuple] = [edge1, edge2, edge3, edge4] + map_edges[tuple] = [edge1, edge2] # l4 loc tuple = ("l4", "l1") cc_aut_G_l4l1_1(A::LHA, S::StateLHA) = true us_aut_G_l4l1_1!(A::LHA, S::StateLHA, x::Vector{Int}) = (S.loc = "l1"; - S["d"] += S["t'"] * min(abs(A.l_ctes["x1"] - S["n"]), abs(A.l_ctes["x2"] - S["n"])); - S["t'"] = 0.0; + S["d"] += S["tprime"] * min(abs(A.l_ctes["x1"] - S["n"]), abs(A.l_ctes["x2"] - S["n"])); + S["tprime"] = 0.0; S["n"] = get_value(A, x, str_obs); S["in"] = true; S["isabs"] = m.isabsorbing(m.p,x)) @@ -170,29 +175,14 @@ function create_automaton_G(m::ContinuousTimeModel, x1::Float64, x2::Float64, t1 tuple = ("l4", "l2") cc_aut_G_l4l2_1(A::LHA, S::StateLHA) = - (S.time >= A.l_ctes["t2"] || istrue(S["isabs"])) + (S.time >= A.l_ctes["t2"]) us_aut_G_l4l2_1!(A::LHA, S::StateLHA, x::Vector{Int}) = (S.loc = "l2"; - S["d"] += S["t'"] * min(abs(A.l_ctes["x1"] - S["n"]), abs(A.l_ctes["x2"] - S["n"])); - S["t'"] = 0.0) + S["d"] += S["tprime"] * min(abs(A.l_ctes["x1"] - S["n"]), abs(A.l_ctes["x2"] - S["n"])); + S["tprime"] = 0.0) edge1 = Edge([nothing], cc_aut_G_l4l2_1, us_aut_G_l4l2_1!) - cc_aut_G_l4l2_2(A::LHA, S::StateLHA) = - istrue(S["isabs"]) && - S.time <= A.l_ctes["t1"] - us_aut_G_l4l2_2!(A::LHA, S::StateLHA, x::Vector{Int}) = - (S.loc = "l2"; - S["d"] = S["d"] * (A.l_ctes["t2"] - A.l_ctes["t1"])) - edge2 = Edge([nothing], cc_aut_G_l4l2_2, us_aut_G_l4l2_2!) - cc_aut_G_l4l2_3(A::LHA, S::StateLHA) = - istrue(S["isabs"]) && - S.time >= A.l_ctes["t1"] - us_aut_G_l4l2_3!(A::LHA, S::StateLHA, x::Vector{Int}) = - (S.loc = "l2"; - S["d"] += (A.l_ctes["t2"] - A.l_ctes["t1"]) * - min(abs(S["n"] - A.l_ctes["x1"]), abs(S["n"] - A.l_ctes["x2"]))) - edge3 = Edge([nothing], cc_aut_G_l4l2_3, us_aut_G_l4l2_3!) - map_edges[tuple] = [edge1, edge2, edge3] + map_edges[tuple] = [edge1] ## Constants l_ctes = Dict{String,Float64}("x1" => x1, "x2" => x2, "t1" => t1, "t2" => t2) diff --git a/core/lha.jl b/core/lha.jl index fcc3fce..af93550 100644 --- a/core/lha.jl +++ b/core/lha.jl @@ -43,34 +43,39 @@ function init_state(A::LHA, x0::Vector{Int}, t0::Float64) end function _find_edge_candidates!(edge_candidates::Vector{Edge}, current_loc::Location, - A::LHA, Snplus1::StateLHA) - + A::LHA, Snplus1::StateLHA, only_asynchronous::Bool) 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) + if edge.transitions[1] == nothing + pushfirst!(edge_candidates, edge) + end + if !only_asynchronous && edge.transitions[1] != nothing + push!(edge_candidates, edge) + end end end end end end -function _get_edge_index(edge_candidates::Vector{Edge}, first_round::Bool, +function _get_edge_index(edge_candidates::Vector{Edge}, detected_event::Bool, tr_nplus1::Transition) ind_edge = 0 bool_event = detected_event for i in eachindex(edge_candidates) edge = edge_candidates[i] + # Asynchronous detection if edge.transitions[1] == nothing return (i, bool_event) end - if first_round || !detected_event - if (length(edge.transitions) == 1 && tr_nplus1 != nothing && edge.transitions[1] == "ALL") || - (tr_nplus1 in edge.transitions) - ind_edge = i - bool_event = true + # Synchronous detection + if !detected_event && tr_nplus1 != nothing + if (length(edge.transitions) == 1 && edge.transitions[1] == "ALL") || + (tr_nplus1 in edge.transitions) + return (i, true) end end end @@ -80,41 +85,45 @@ end function next_state!(Snplus1::StateLHA, A::LHA, xnplus1::Vector{Int}, tnplus1::Float64, tr_nplus1::Transition, Sn::StateLHA; verbose::Bool = 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[] first_round::Bool = true detected_event::Bool = (tr_nplus1 == nothing) ? true : false - turns = 1 - while first_round || !detected_event || length(edge_candidates) > 0 + turns = 0 + + if verbose + println("#####") + @show xnplus1, tnplus1, tr_nplus1 + @show Sn + @show Snplus1 + end + + # In terms of values not reference, Snplus1 == Sn + # First, we check the asynchronous transitions + while first_round || length(edge_candidates) > 0 + turns += 1 edge_candidates = empty!(edge_candidates) current_loc = Snplus1.loc - if verbose @show turns end - # Save all edges that satisfies transition predicate (synchronous or autonomous) - _find_edge_candidates!(edge_candidates, current_loc, A, Snplus1) - # Search the one we must chose - ind_edge, detected_event = _get_edge_index(edge_candidates, first_round, detected_event, tr_nplus1) + # Save all edges that satisfies transition predicate (asynchronous ones) + _find_edge_candidates!(edge_candidates, current_loc, A, Snplus1, true) + # Search the one we must chose, here the event is nothing because + # we're not processing yet the next event + ind_edge, detected_event = _get_edge_index(edge_candidates, detected_event, nothing) # 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 (ind_edge == 0) - #if (ind_edge == 0 || detected_event) - break end + first_round = false if verbose - @show first_round detected_event - @show tnplus1 tr_nplus1 xnplus1 - @show ind_edge + @show turns @show edge_candidates - @show tuple_candidates + @show ind_edge, detected_event + println("After update") @show Snplus1 end + if (ind_edge == 0) + break + end # For debug if turns > 100 println("Number of turns in next_state! is suspicious") @@ -127,8 +136,61 @@ function next_state!(Snplus1::StateLHA, A::LHA, end error("Unpredicted behavior automaton") end + end + if verbose + @show Snplus1 + println("Time flies with the flow...") + end + # Now time flies according to the flow + for i in eachindex(Snplus1.l_var) + coeff_deriv = (A.l_flow[Snplus1.loc])[i] + if coeff_deriv > 0 + Snplus1.l_var[i] += coeff_deriv*(tnplus1 - Snplus1.time) + end + end + Snplus1.time = tnplus1 + if verbose + @show Snplus1 + end + # Now firing an edge according to the event + first_round = true + while first_round || length(edge_candidates) > 0 turns += 1 + edge_candidates = empty!(edge_candidates) + current_loc = Snplus1.loc + # Save all edges that satisfies transition predicate (synchronous ones) + _find_edge_candidates!(edge_candidates, current_loc, A, Snplus1, false) + # Search the one we must chose + ind_edge, detected_event = _get_edge_index(edge_candidates, detected_event, tr_nplus1) + # Update the state with the chosen one (if it exists) + if verbose + @show turns + @show edge_candidates + @show ind_edge, detected_event + end + if ind_edge > 0 + edge_candidates[ind_edge].update_state!(A, Snplus1, xnplus1) + end first_round = false + if verbose + println("After update") + @show Snplus1 + end + if (ind_edge == 0 || detected_event) + break + end + # For debug + if turns > 100 + println("Number of turns in next_state! is suspicious") + @show 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") + end end end diff --git a/core/model.jl b/core/model.jl index da8faf3..c8404b7 100644 --- a/core/model.jl +++ b/core/model.jl @@ -125,7 +125,8 @@ function simulate(m::ContinuousTimeModel; p::Union{Nothing,AbstractVector{Float6 return Trajectory(m, values, times, transitions) end -function simulate(product::SynchronizedModel; p::Union{Nothing,AbstractVector{Float64}} = nothing) +function simulate(product::SynchronizedModel; p::Union{Nothing,AbstractVector{Float64}} = nothing, + verbose::Bool = false) m = product.m A = product.automaton p_sim = m.p @@ -149,6 +150,11 @@ function simulate(product::SynchronizedModel; p::Union{Nothing,AbstractVector{Fl Sn = copy(S0) isabsorbing::Bool = m.isabsorbing(p_sim,xn) isacceptedLHA::Bool = isaccepted(Sn) + # Alloc of vectors where we stock n+1 values + vec_x = zeros(Int, m.d) + l_t = Float64[0.0] + l_tr = Transition[nothing] + Snplus1 = copy(Sn) # If x0 is absorbing if isabsorbing || isacceptedLHA _resize_trajectory!(full_values, times, transitions, 1) @@ -156,13 +162,12 @@ function simulate(product::SynchronizedModel; p::Union{Nothing,AbstractVector{Fl if isbounded(m) _finish_bounded_trajectory!(values, times, transitions, m.time_bound) end + if isabsorbing && !isacceptedLHA + next_state!(Snplus1, A, xn, m.time_bound, nothing, Sn; verbose = verbose) + copyto!(Sn, Snplus1) + end return SynchronizedTrajectory(Sn, product, values, times, transitions) end - # Alloc of vectors where we stock n+1 values - vec_x = zeros(Int, m.d) - l_t = Float64[0.0] - l_tr = Transition[nothing] - Snplus1 = copy(Sn) # First we fill the allocated array for i = 2:m.estim_min_states m.f!(vec_x, l_t, l_tr, xn, tn, p_sim) @@ -173,7 +178,7 @@ function simulate(product::SynchronizedModel; p::Union{Nothing,AbstractVector{Fl n += 1 copyto!(xn, vec_x) tr_n = l_tr[1] - next_state!(Snplus1, A, xn, tn, tr_n, Sn) + next_state!(Snplus1, A, xn, tn, tr_n, Sn; verbose = verbose) _update_values!(full_values, times, transitions, xn, tn, tr_n, i) copyto!(Sn, Snplus1) isabsorbing = m.isabsorbing(p_sim,xn) @@ -189,6 +194,10 @@ function simulate(product::SynchronizedModel; p::Union{Nothing,AbstractVector{Fl if isbounded(m) _finish_bounded_trajectory!(values, times, transitions, m.time_bound) end + if isabsorbing && !isacceptedLHA + next_state!(Snplus1, A, xn, m.time_bound, nothing, Sn; verbose = verbose) + copyto!(Sn, Snplus1) + end return SynchronizedTrajectory(Sn, product, values, times, transitions) end # Otherwise, buffering system @@ -207,7 +216,7 @@ function simulate(product::SynchronizedModel; p::Union{Nothing,AbstractVector{Fl end copyto!(xn, vec_x) tr_n = l_tr[1] - next_state!(Snplus1, A, xn, tn, tr_n, Sn) + next_state!(Snplus1, A, xn, tn, tr_n, Sn; verbose = verbose) _update_values!(full_values, times, transitions, xn, tn, tr_n, m.estim_min_states+size_tmp+i) copyto!(Sn, Snplus1) @@ -230,6 +239,10 @@ function simulate(product::SynchronizedModel; p::Union{Nothing,AbstractVector{Fl # the trajectory is bounded _finish_bounded_trajectory!(values, times, transitions, m.time_bound) end + if isabsorbing && !isacceptedLHA + next_state!(Snplus1, A, xn, m.time_bound, nothing, Sn; verbose = verbose) + copyto!(Sn, Snplus1) + end return SynchronizedTrajectory(Sn, product, values, times, transitions) end @@ -249,20 +262,20 @@ function volatile_simulate(product::SynchronizedModel; Sn = copy(S0) isabsorbing::Bool = m.isabsorbing(p_sim,xn) isacceptedLHA::Bool = isaccepted(Sn) - # If x0 is absorbing - if isabsorbing || isacceptedLHA - return Sn - end # Alloc of vectors where we stock n+1 values vec_x = zeros(Int, m.d) l_t = Float64[0.0] l_tr = Transition[nothing] Snplus1 = copy(Sn) - while !isabsorbing && tn <= m.time_bound && !isacceptedLHA - if verbose - @show vec_x - @show Sn + # If x0 is absorbing + if isabsorbing || isacceptedLHA + if !isacceptedLHA + next_state!(Snplus1, A, xn, m.time_bound, nothing, Sn; verbose = verbose) + copyto!(Sn, Snplus1) end + return Sn + end + while !isabsorbing && tn <= m.time_bound && !isacceptedLHA m.f!(vec_x, l_t, l_tr, xn, tn, p_sim) tn = l_t[1] if tn > m.time_bound @@ -271,12 +284,16 @@ function volatile_simulate(product::SynchronizedModel; end copyto!(xn, vec_x) tr_n = l_tr[1] - next_state!(Snplus1, A, xn, tn, tr_n, Sn) + next_state!(Snplus1, A, xn, tn, tr_n, Sn; verbose = verbose) copyto!(Sn, Snplus1) isabsorbing = m.isabsorbing(p_sim,xn) isacceptedLHA = isaccepted(Snplus1) n += 1 end + if isabsorbing && !isacceptedLHA + next_state!(Snplus1, A, xn, m.time_bound, nothing, Sn; verbose = verbose) + copyto!(Sn, Snplus1) + end return Sn end @@ -313,7 +330,7 @@ function mean_value_lha(sm::SynchronizedModel, str_var::String, nbr_sim::Int) return sum_val / nbr_sim end -function distribute_prob_accept_lha(sm::SynchronizedModel, str_var::String, nbr_sim::Int) +function distribute_prob_accept_lha(sm::SynchronizedModel, nbr_sim::Int) sum_val = @distributed (+) for i = 1:nbr_sim Int(isaccepted(volatile_simulate(sm))) end return sum_val / nbr_sim end diff --git a/core/plots.jl b/core/plots.jl index 9e2ac46..898267c 100644 --- a/core/plots.jl +++ b/core/plots.jl @@ -52,8 +52,7 @@ end function plot!(A::LHA) x1, x2, t1, t2 = A.l_ctes["x1"], A.l_ctes["x2"], A.l_ctes["t1"], A.l_ctes["t2"] - rectangle(w, h, x, y) = Shape(x .+ [0,w,w,0], y .+ [0,0,h,h]) - plot!(rectangle(t2, x2, t1, x1), opacity = 0.5) + plot!(Shape([(t1,x1), (t1,x2), (t2,x2), (t2,x1), (t1,x1)]), opacity = 0.5) end export plot, plot! diff --git a/tests/cosmos/distance_F/ER_1D.jl b/tests/cosmos/distance_F/ER_1D.jl index 80c8796..3b9176f 100644 --- a/tests/cosmos/distance_F/ER_1D.jl +++ b/tests/cosmos/distance_F/ER_1D.jl @@ -42,6 +42,7 @@ for exp in l_exp --const k_3=$(k3),x1=$x1,x2=$x2,t1=$t1,t2=$t2 --level $(level) --width $(width) --verbose 0` + #run(command) run(pipeline(command, stderr=devnull)) dict_values = cosmos_get_values("Result_dist_F_$(str_model).res") l_dist_cosmos[i] = dict_values["Estimated value"] @@ -52,8 +53,11 @@ for exp in l_exp set_param!(ER, "k3", convert(Float64, k3)) sync_ER = ER*A_F l_dist_pkg[i] = distribute_mean_value_lha(sync_ER, "d", nb_sim) + nb_accepts_pkg = distribute_prob_accept_lha(sync_ER, nb_sim) + #@info "About accepts" nb_sim nb_accepted nb_accepts_pkg test = isapprox(l_dist_cosmos[i], l_dist_pkg[i]; atol = width*1.01) - global test_all = test_all && test + test2 = nb_accepts_pkg == (nb_sim / nb_accepted) + global test_all = test_all && test && test2 if !test @show l_dist_pkg[i], l_dist_cosmos[i] @show exp diff --git a/tests/cosmos/distance_F/dist_F_ER.lha b/tests/cosmos/distance_F/dist_F_ER.lha index baa9f54..47cd3fb 100644 --- a/tests/cosmos/distance_F/dist_F_ER.lha +++ b/tests/cosmos/distance_F/dist_F_ER.lha @@ -1,4 +1,4 @@ -NbVariables = 3; +NbVariables = 4; NbLocations = 4; const int x1 = 50; @@ -7,7 +7,7 @@ const int x2 = 75; const double t1 = 0.025; const double t2 = 0.05; -VariablesList = {t,d,n}; +VariablesList = {t,d,n,test_abs}; LocationsList = {l0, l1, l2, l3}; @@ -24,17 +24,22 @@ Locations={ }; Edges={ -((l0,l1), #, t>=0, {n=P}); +((l0,l1), #, t>=0, {n=P,test_abs=k_1*(E*S)+k_2*ES}); + +((l1,l2),#, n>=x1 & n<=x2 & t>=t1 & t<=t2 ,{d=0}); +((l1,l2),#, t>=t2 , #); +((l1,l2),#, test_abs=0 , #); +((l1,l2),#, d=0 & t>=t1, #); + +((l1,l3), #, n>=x1 & n<=x2, {d=0}); ((l1,l3), #, t<=t1 & n<=x1-1, {d=min(((t-t1)^2+(n-x2)^2)^0.5,((t-t1)^2+(n-x1)^2)^0.5)}); ((l1,l3), #, t<=t1 & n>=x2+1, {d=min(((t-t1)^2+(n-x2)^2)^0.5,((t-t1)^2+(n-x1)^2)^0.5)}); -((l1,l3), #, n>=x1 & n<=x2, {d=0}); -((l1,l3), #, n<=x1-1 & t >= t1 & t<=t2, {d=min(d ,min( ((n-x1)^2)^0.5, ((n-x2)^2)^0.5 ) )}); +((l1,l3), #, n<=x1-1 & t >= t1 & t<=t2, {d=min(d,min(((n-x1)^2)^0.5,((n-x2)^2)^0.5))}); ((l1,l3), #, n>=x2+1 & t >= t1 & t<=t2, {d=min(d,min( ((n-x1)^2)^0.5, ((n-x2)^2)^0.5 ) ) }); -((l3,l1), ALL, t>=0, {n=P}); + +((l3,l1), ALL, t>=0, {n=P,test_abs=k_1*(E*S)+k_2*ES}); ((l3,l2), #, t>=t2 ,#); -((l1,l2),#, n>=x1 & n<=x2 & t>=t1 & t<=t2 ,{d=0}); -((l1,l2),#, t>=t2 , #); -((l1,l2),#, d=0 & t>=t1, #); }; + diff --git a/tests/cosmos/distance_G/ER_R5.jl b/tests/cosmos/distance_G/ER_R5.jl index b211a29..c62185c 100644 --- a/tests/cosmos/distance_G/ER_R5.jl +++ b/tests/cosmos/distance_G/ER_R5.jl @@ -1,6 +1,7 @@ @everywhere begin using MarkovProcesses + import Distributed: nworkers absolute_path = get_module_path() * "/tests/cosmos/" # Values x1, x2 t1, t2 str_model = "ER" @@ -32,7 +33,7 @@ for i = 1:nb_k1 k1 = l_k1[i] k2 = l_k2[j] command = `Cosmos $(absolute_path * "models/" * str_model * ".gspn") - $(absolute_path * "distance_G/dist_G_" * str_model * ".lha") --njob $(ENV["JULIA_NUM_THREADS"]) + $(absolute_path * "distance_G/dist_G_" * str_model * ".lha") --njob $(nworkers()) --const k_1=$(k1),k_2=$(k2),x1=$x1,x2=$x2,t1=$t1,t2=$t2 --level $(level) --width $(width) --verbose 0` @@ -47,16 +48,19 @@ for i = 1:nb_k1 set_param!(ER, "k2", convert(Float64, k2)) sync_ER = ER*A_G mat_dist_pkg[i,j] = distribute_mean_value_lha(sync_ER, "d", nb_sim) + nb_accepts_pkg = distribute_prob_accept_lha(sync_ER, nb_sim) + #@info "About accepts" nb_sim nb_accepted nb_accepts_pkg test = isapprox(mat_dist_cosmos[i,j], mat_dist_pkg[i,j]; atol = width*1.01) + test2 = nb_accepts_pkg == (nb_sim / nb_accepted) if !test @info "Distances too different" (k1,k2) mat_dist_pkg[i,j] mat_dist_cosmos[i,j] end - global test_all = test_all && test + global test_all = test_all && test && test2 end end -@info mat_dist_pkg -@info mat_dist_cosmos +@info "Distances R5 pkg" mat_dist_pkg +@info "Distances R5 Cosmos" mat_dist_cosmos rm("Result_dist_G_$(str_model).res") rm("Result.res") diff --git a/tests/cosmos/distance_G/dist_G_ER.lha b/tests/cosmos/distance_G/dist_G_ER.lha index 72eeb5b..8b45dcc 100644 --- a/tests/cosmos/distance_G/dist_G_ER.lha +++ b/tests/cosmos/distance_G/dist_G_ER.lha @@ -47,7 +47,7 @@ Edges={ ((l1,l2), #, in=1 & t>=t2, #); ((l1,l2), #, in=0 & t>=t2, {d=d*(t2-t1)}); ((l1,l2), #, test_abs=0 & t<=t1, {d=d*(t2-t1)}); -((l1,l2), #, test_abs=0 & t>=t1, {d=d+(t2-t1)*min(((n-x1)^2)^0.5,((n-x2)^2)^0.5)}); +((l1,l2), #, test_abs=0 & t>=t1 & t<=t2, {d=d+(t2-t)*min(((n-x1)^2)^0.5,((n-x2)^2)^0.5)}); ((l3,l1), ALL, t>=0, {n=E,test_abs=k_1*(E*S)+k_2*ES}); diff --git a/tests/run_cosmos.jl b/tests/run_cosmos.jl index 096a7f5..bc2ad79 100644 --- a/tests/run_cosmos.jl +++ b/tests/run_cosmos.jl @@ -3,5 +3,6 @@ using Test @testset "Cosmos tests" begin @test include("cosmos/distance_F/ER_1D.jl") + @test include("cosmos/distance_G/ER_R5.jl") end -- GitLab