diff --git a/automata/euclidean_distance_automaton.jl b/automata/euclidean_distance_automaton.jl new file mode 100644 index 0000000000000000000000000000000000000000..703b2224da28a4036728c815bca322140939ad88 --- /dev/null +++ b/automata/euclidean_distance_automaton.jl @@ -0,0 +1,108 @@ + +# l0 loc +# l0 => l1 +@everywhere cc_eucl_dist_aut_l0l1_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = true + +# l1 loc +# l1 => l1 +@everywhere cc_eucl_dist_aut_l1l1_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:t] >= constants[Symbol("tml_$(S[:idx])")] +@everywhere us_eucl_dist_aut_l1l1_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S[:d] += (S[:n] - constants[Symbol("y_$(S[:idx])")])^2; + S[:idx] += 1.0) + +# l1 => l2 +@everywhere cc_eucl_dist_aut_l1l2_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:idx] >= constants[:nbr_obs] + 1 +@everywhere us_eucl_dist_aut_l1l2_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :l2; + S[:d] = sqrt(S[:d])) + +@everywhere cc_eucl_dist_aut_l1l1_2(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = true + +function create_euclidean_distance_automaton(m::ContinuousTimeModel, timeline::Vector{Float64}, observations::Vector{Float64}, sym_obs::VariableModel) + @assert sym_obs in m.g "$(sym_obs) is not observed." + @assert length(timeline) == length(observations) + nbr_observations = length(observations) + + # Locations + locations = [:l0, :l1, :l2] + + ## Invariant predicates + true_inv_predicate(x::Vector{Int}) = true + Λ_F = Dict(:l0 => true_inv_predicate, :l1 => true_inv_predicate, + :l2 => true_inv_predicate) + + ## Init and final loc + locations_init = [:l0] + locations_final = [:l2] + + map_var_automaton_idx = Dict{VariableAutomaton,Int}(:t => 1, :n => 2, + :d => 3, :idx => 4) + nbr_first_vars = 4 + for i = 1:nbr_observations + map_var_automaton_idx[Symbol("tml_$(convert(Float64, i))")] = nbr_first_vars + i + end + for i = 1:nbr_observations + map_var_automaton_idx[Symbol("y_$(convert(Float64, i))")] = nbr_first_vars + nbr_observations + i + end + + vector_flow = zeros(nbr_first_vars + 2*nbr_observations) + vector_flow[1] = 1.0 + flow = Dict{Location,Vector{Float64}}(:l0 => vector_flow, + :l1 => vector_flow, + :l2 => vector_flow) + + ## Edges + map_edges = Dict{Location, Dict{Location, Vector{Edge}}}() + for loc in locations + map_edges[loc] = Dict{Location, Vector{Edge}}() + end + + idx_obs_var = getfield(m, :map_var_idx)[sym_obs] + nbr_rand = rand(1:1000) + basename_func = "$(replace(m.name, ' '=>'_'))_$(nbr_rand)" + basename_func = replace(basename_func, '-'=>'_') + + # l0 loc + # l0 => l1 + sym_func_us_l0l1_1 = Symbol("us_eucl_dist_$(basename_func)_l0l1_1!") + str_us_l0l1_1 = " + @everywhere $(sym_func_us_l0l1_1)(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = \n + (S.loc = :l1; \n + S[:n] = x[$(idx_obs_var)];\n + S[:d] = 0.0;\n + S[:idx] = 1.0)" + eval(Meta.parse(str_us_l0l1_1)) + edge1 = Edge([nothing], getfield(Main, :cc_eucl_dist_aut_l0l1_1), getfield(Main, sym_func_us_l0l1_1)) + map_edges[:l0][:l1] = [edge1] + + # l1 loc + # l1 => l1 + sym_func_us_l1l2_2 = Symbol("us_eucl_dist_$(basename_func)_l1l2_2!") + str_us_l1l2_2 = " + @everywhere $(sym_func_us_l1l2_2)(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) =\n + (S[:n] = x[$(idx_obs_var)])" + eval(Meta.parse(str_us_l1l2_2)) + edge1 = Edge([nothing], getfield(Main, :cc_eucl_dist_aut_l1l1_1), getfield(Main, :us_eucl_dist_aut_l1l1_1!)) + edge2 = Edge([:ALL], getfield(Main, :cc_eucl_dist_aut_l1l1_2), getfield(Main, sym_func_us_l1l2_2)) + map_edges[:l1][:l1] = [edge1, edge2] + + # l1 => l2 + edge1 = Edge([nothing], getfield(Main, :cc_eucl_dist_aut_l1l2_1), getfield(Main, :us_eucl_dist_aut_l1l2_1!)) + map_edges[:l1][:l2] = [edge1] + + ## Constants + constants = Dict{Symbol,Float64}(:nbr_obs => nbr_observations) + for i = 1:nbr_observations + constants[Symbol("tml_$(convert(Float64, i))")] = timeline[i] + constants[Symbol("y_$(convert(Float64, i))")] = observations[i] + end + + A = LHA("Euclidean distance", m.transitions, locations, Λ_F, locations_init, locations_final, + map_var_automaton_idx, flow, map_edges, constants, m.map_var_idx) + return A +end + +export create_euclidean_distance_automaton + diff --git a/automata/period_automaton.jl b/automata/period_automaton.jl new file mode 100644 index 0000000000000000000000000000000000000000..fe6d7f430e3d1089adb3cd2297f11a58f7b11c49 --- /dev/null +++ b/automata/period_automaton.jl @@ -0,0 +1,258 @@ + +## Edge functions + +# l0 loc +# * l0 => l0 +@everywhere cc_aut_per_l0l0_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +true +@everywhere us_aut_per_l0l0_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(nothing) + +# * l0 => l0prime +@everywhere cc_aut_per_l0l0prime_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:t] >= constants[:initT] +@everywhere us_aut_per_l0l0prime_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :l0prime) + +# * l0 => low +@everywhere cc_aut_per_l0low_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:t] >= constants[:initT] +@everywhere us_aut_per_l0low_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :low; + S[:t] = 0.0; + S[:top] = 0.0; + S[:n] = -1) + +# l0prime +# * l0prime => l0prime +@everywhere cc_aut_per_l0primel0prime_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +true +@everywhere us_aut_per_l0primel0prime_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(nothing) + +# * l0prime => low +@everywhere cc_aut_per_l0primelow_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +true +@everywhere us_aut_per_l0primelow_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :low; + S[:t] = 0.0; + S[:top] = 0.0; + S[:n] = -1) + +# low +# * low => low +@everywhere cc_aut_per_lowlow_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:n] < constants[:N] +@everywhere us_aut_per_lowlow_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(nothing) + +# * low => mid +@everywhere cc_aut_per_lowmid_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:n] < constants[:N] +@everywhere us_aut_per_lowmid_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :mid) + +# * low => final +@everywhere cc_aut_per_lowfinal_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:n] == constants[:N] +@everywhere us_aut_per_lowfinal_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :final) + +# mid +# * mid => mid +@everywhere cc_aut_per_midmid_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:n] < constants[:N] +@everywhere us_aut_per_midmid_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(nothing) + +# * mid => low +@everywhere cc_aut_per_midlow_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:n] < constants[:N] && +S[:top] == 0.0 +@everywhere us_aut_per_midlow_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :low) + +@everywhere cc_aut_per_midlow_2(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:n] == -1.0 && +S[:top] == 1.0 +@everywhere us_aut_per_midlow_2!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :low; + S[:n] += 1; + S[:t] = 0.0; + S[:top] = 0.0) + +@everywhere cc_aut_per_midlow_3(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(0 <= S[:n] <= 1) && +S[:top] == 1.0 +@everywhere us_aut_per_midlow_3!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :low; + S[:n] += 1; + S[:top] = 0.0; + S[:mean_tp] = (S[:mean_tp] * (S[:n]-1) + S[:tp]) / S[:n]; + S[:tp] = 0.0) + +@everywhere cc_aut_per_midlow_4(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(2 <= S[:n] < constants[:N]) && +S[:top] == 1.0 +@everywhere us_aut_per_midlow_4!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :low; + S[:n] += 1; + S[:top] = 0.0; + S[:mean_tp] = (S[:mean_tp] * (S[:n]-1) + S[:tp]) / S[:n]; + S[:var_tp] = (S[:var_tp] * (S[:n]-1) + (S[:mean_tp]-S[:tp])^2) / S[:n]; + S[:tp] = 0.0) + +# * mid => high +@everywhere cc_aut_per_midhigh_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:n] < constants[:N] +@everywhere us_aut_per_midhigh_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :high; + S[:top] = 1.0) + +# * mid => final +@everywhere cc_aut_per_midfinal_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:n] == constants[:N] +@everywhere us_aut_per_midfinal_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :final) + +# high +# * high => high +@everywhere cc_aut_per_highhigh_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:n] < constants[:N] +@everywhere us_aut_per_highhigh_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(nothing) + +# * high => mid +@everywhere cc_aut_per_highmid_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:n] < constants[:N] +@everywhere us_aut_per_highmid_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :mid) + +# * high => final +@everywhere cc_aut_per_highfinal_1(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +S[:n] == constants[:N] +@everywhere us_aut_per_highfinal_1!(S::StateLHA, constants::Dict{Symbol,Float64}, x::Vector{Int}, p::Vector{Float64}) = +(S.loc = :final) + +function create_period_automaton(m::ContinuousTimeModel, L::Float64, H::Float64, N::Int, sym_obs::VariableModel; + initT::Float64 = 0.0) + @assert sym_obs in m.g "$(sym_obs) is not observed." + N = convert(Float64, N) + nbr_rand = rand(1:1000) + basename_func = "$(replace(m.name, ' '=>'_'))_$(nbr_rand)" + basename_func = replace(basename_func, '-'=>'_') + + ## Locations + locations = [:l0, :l0prime, :low, :mid, :high, :final] + + ## Invariant predicates + idx_sym_obs = getfield(m, :map_var_idx)[sym_obs] + sym_name_L = Symbol("val_L_aut_per_$(basename_func)") + sym_name_H = Symbol("val_H_aut_per_$(basename_func)") + + @everywhere true_predicate(x::Vector{Int}) = true + @everywhere low_predicate(x::Vector{Int}) = x[$(Meta.quot(idx_sym_obs))] <= $L + @everywhere not_low_predicate(x::Vector{Int}) = !low_predicate(x) + @everywhere mid_predicate(x::Vector{Int}) = $L < x[$(Meta.quot(idx_sym_obs))] < $H + @everywhere high_predicate(x::Vector{Int}) = x[$(Meta.quot(idx_sym_obs))] >= $H + #= + eval(Meta.parse("@everywhere true_predicate(x::Vector{Int}) = true")) + eval(Meta.parse("@everywhere low_predicate(x::Vector{Int}) = x[$(Meta.quot(idx_sym_obs))] <= $L")) + eval(Meta.parse("@everywhere not_low_predicate(x::Vector{Int}) = !low_predicate(x)")) + eval(Meta.parse("@everywhere mid_predicate(x::Vector{Int}) = L < x[$(Meta.quot(idx_sym_obs))] < $H")) + eval(Meta.parse("@everywhere high_predicate(x::Vector{Int}) = x[$(Meta.quot(idx_sym_obs))] >= $H")) + =# + + Λ_F = Dict(:l0 => getfield(Main, :true_predicate), :l0prime => getfield(Main, :not_low_predicate), + :low => getfield(Main, :low_predicate), :mid => getfield(Main, :mid_predicate), + :high => getfield(Main, :high_predicate), :final => getfield(Main, :true_predicate)) + + ## Init and final loc + locations_init = [:l0] + locations_final = [:final] + + ## Map of automaton variables + map_var_automaton_idx = Dict{VariableAutomaton,Int}(:t => 1, :n => 2, :top => 3, :tp => 4, + :mean_tp => 5, :var_tp => 6) + + flow = Dict{Location,Vector{Float64}}(:l0 => [1.0,0.0,0.0,0.0,0.0,0.0], + :l0prime => [1.0,0.0,0.0,0.0,0.0,0.0], + :low => [1.0,0.0,0.0,1.0,0.0,0.0], + :mid => [1.0,0.0,0.0,1.0,0.0,0.0], + :high => [1.0,0.0,0.0,1.0,0.0,0.0], + :final => [1.0,0.0,0.0,0.0,0.0,0.0]) + + ## Edges + map_edges = Dict{Location, Dict{Location, Vector{Edge}}}() + for loc in locations + map_edges[loc] = Dict{Location, Vector{Edge}}() + end + + # l0 loc + # * l0 => l0 + edge_1 = Edge([:ALL], getfield(Main, :cc_aut_per_l0l0_1), getfield(Main, :us_aut_per_l0l0_1!)) + map_edges[:l0][:l0] = [edge_1] + # * l0 => l0prime + edge_1 = Edge([nothing], getfield(Main, :cc_aut_per_l0l0prime_1), getfield(Main, :us_aut_per_l0l0prime_1!)) + map_edges[:l0][:l0prime] = [edge_1] + # * l0 => low + edge_1 = Edge([nothing], getfield(Main, :cc_aut_per_l0low_1), getfield(Main, :us_aut_per_l0low_1!)) + map_edges[:l0][:low] = [edge_1] + + # l0prime + # * l0prime => l0prime + edge_1 = Edge([:ALL], getfield(Main, :cc_aut_per_l0primel0prime_1), getfield(Main, :us_aut_per_l0primel0prime_1!)) + map_edges[:l0prime][:l0prime] = [edge_1] + # * l0prime => low + edge_1 = Edge([nothing], getfield(Main, :cc_aut_per_l0primelow_1), getfield(Main, :us_aut_per_l0primelow_1!)) + map_edges[:l0prime][:low] = [edge_1] + + # low + # * low => low + edge_1 = Edge([:ALL], getfield(Main, :cc_aut_per_lowlow_1), getfield(Main, :us_aut_per_lowlow_1!)) + map_edges[:low][:low] = [edge_1] + # * low => mid + edge_1 = Edge([:ALL], getfield(Main, :cc_aut_per_lowmid_1), getfield(Main, :us_aut_per_lowmid_1!)) + map_edges[:low][:mid] = [edge_1] + # * low => final + edge_1 = Edge([nothing], getfield(Main, :cc_aut_per_lowfinal_1), getfield(Main, :us_aut_per_lowfinal_1!)) + map_edges[:low][:final] = [edge_1] + + # mid + # * mid => mid + edge_1 = Edge([:ALL], getfield(Main, :cc_aut_per_midmid_1), getfield(Main, :us_aut_per_midmid_1!)) + map_edges[:mid][:mid] = [edge_1] + # * mid => low + edge_1 = Edge([:ALL], getfield(Main, :cc_aut_per_midlow_1), getfield(Main, :us_aut_per_midlow_1!)) + edge_2 = Edge([:ALL], getfield(Main, :cc_aut_per_midlow_2), getfield(Main, :us_aut_per_midlow_2!)) + edge_3 = Edge([:ALL], getfield(Main, :cc_aut_per_midlow_3), getfield(Main, :us_aut_per_midlow_3!)) + edge_4 = Edge([:ALL], getfield(Main, :cc_aut_per_midlow_4), getfield(Main, :us_aut_per_midlow_4!)) + map_edges[:mid][:low] = [edge_1, edge_2, edge_3, edge_4] + # * mid => high + edge_1 = Edge([:ALL], getfield(Main, :cc_aut_per_midhigh_1), getfield(Main, :us_aut_per_midhigh_1!)) + map_edges[:mid][:high] = [edge_1] + # * mid => final + edge_1 = Edge([nothing], getfield(Main, :cc_aut_per_midfinal_1), getfield(Main, :us_aut_per_midfinal_1!)) + map_edges[:mid][:final] = [edge_1] + + # high + # * high => high + edge_1 = Edge([:ALL], getfield(Main, :cc_aut_per_highhigh_1), getfield(Main, :us_aut_per_highhigh_1!)) + map_edges[:high][:high] = [edge_1] + # * high => mid + edge_1 = Edge([:ALL], getfield(Main, :cc_aut_per_highmid_1), getfield(Main, :us_aut_per_highmid_1!)) + map_edges[:high][:mid] = [edge_1] + # * high => final + edge_1 = Edge([nothing], getfield(Main, :cc_aut_per_highfinal_1), getfield(Main, :us_aut_per_highfinal_1!)) + map_edges[:high][:final] = [edge_1] + + ## Constants + constants = Dict{Symbol,Float64}(:N => N, :L => L, :H => H, :initT => initT) + + A = LHA("Period", m.transitions, locations, Λ_F, locations_init, locations_final, + map_var_automaton_idx, flow, map_edges, constants, m.map_var_idx) + return A +end + +export create_period_automaton + diff --git a/examples/scripts/doping_3way_oscillator.jl b/examples/scripts/doping_3way_oscillator.jl new file mode 100644 index 0000000000000000000000000000000000000000..cbfba14af7fad35a5e19e77e5207969620e3c996 --- /dev/null +++ b/examples/scripts/doping_3way_oscillator.jl @@ -0,0 +1,16 @@ + +using MarkovProcesses +load_plots() + +load_model("doping_3way_oscillator") +load_automaton("period_automaton") +A_per = create_period_automaton(doping_3way_oscillator, 300.0, 360.0, 5, :A) + +sync_doping = doping_3way_oscillator * A_per +set_time_bound!(sync_doping, 0.1) +set_x0!(doping_3way_oscillator, [:A, :B, :C, :DA, :DB, :DC], [333, 333, 333, 10, 10, 10]) +σ = simulate(sync_doping) +plot(σ; A = A_per, filename = "traj_full.png") +plot(σ, :A; A = A_per, filename = "traj_A.png") +plot_periodic_trajectory(A_per, σ, :A, filename = "traj_automaton.png") +