From 961bab0634cc8e75cbabdd941afdd802dedfb5cd Mon Sep 17 00:00:00 2001
From: Mahmoud Bentriou <mahmoud.bentriou@centralesupelec.fr>
Date: Wed, 24 Feb 2021 11:31:47 +0100
Subject: [PATCH] I've implemented another way of dispatching check_constraints
 and update_state functions but performance gets worst. With
 bench/pkg/abstract_arrays.jl i've highligthed each time a function is in a
 collection performance gets worst.

---
 automata/automaton_G_and_F.jl          | 263 ++++++++++++++-----------
 bench/pkg/abstract_array.jl            | 103 ++++++++++
 bench/pkg/check_constraints_sync_R6.jl | 222 +++++++++++++++++++++
 core/MarkovProcesses.jl                |   2 +-
 core/common.jl                         |   4 +
 core/lha.jl                            | 243 ++++++++++++++++++++++-
 core/model.jl                          |  28 +--
 7 files changed, 726 insertions(+), 139 deletions(-)
 create mode 100644 bench/pkg/abstract_array.jl
 create mode 100644 bench/pkg/check_constraints_sync_R6.jl

diff --git a/automata/automaton_G_and_F.jl b/automata/automaton_G_and_F.jl
index ba05cab..b1e65c3 100644
--- a/automata/automaton_G_and_F.jl
+++ b/automata/automaton_G_and_F.jl
@@ -1,7 +1,11 @@
 
 # Creation of the automaton types
 #@everywhere @eval abstract type EdgeAutomatonGandF <: Edge end
-@everywhere struct EdgeAutomatonGandF{T} <: Edge transitions::Union{Nothing,Vector{Symbol}} end
+@everywhere struct EdgeAutomatonGandF <: Edge 
+    transitions::TransitionSet 
+    check_constraints::Function
+    update_state!::Function
+end
 @everywhere @eval $(MarkovProcesses.generate_code_lha_type_def(:AutomatonGandF, :EdgeAutomatonGandF))
 
 function create_automaton_G_and_F(m::ContinuousTimeModel, x1::Float64, x2::Float64, t1::Float64, t2::Float64, sym_obs_G::VariableModel,
@@ -59,23 +63,26 @@ function create_automaton_G_and_F(m::ContinuousTimeModel, x1::Float64, x2::Float
 
     id = MarkovProcesses.newid()
     #Symbol("Edge_$(lha_name)_$(basename_func)_$(from_loc)$(to_loc)_$(edge_number)")
-    function generate_edge_type(from_loc::Location, to_loc::Location, edge_number::Int)
-        tag_type = Symbol("$(from_loc)$(to_loc)_$(edge_number)_$(model_name)_$(id)")
-        @eval type = EdgeAutomatonGandF{$(Meta.quot(tag_type))}
-        return @eval($type)
+    function edge_name(from_loc::Location, to_loc::Location, edge_number::Int)
+        return Symbol("$(edge_type)_$(from_loc)$(to_loc)_$(edge_number)_$(model_name)_$(id)")
+    end
+    function check_constraints(from_loc::Location, to_loc::Location, edge_number::Int)
+        return Symbol("check_constraints_$(edge_type)_$(from_loc)$(to_loc)_$(edge_number)_$(model_name)_$(id)")
+    end
+    function update_state!(from_loc::Location, to_loc::Location, edge_number::Int)
+        return Symbol("update_state_$(edge_type)_$(from_loc)$(to_loc)_$(edge_number)_$(model_name)_$(id)!")
     end
 
     ## check_constraints & update_state!
     @everywhere @eval begin
-    #return quote
         istrue(val::Float64) = convert(Bool, val)
         ## Edges check constraint and update state functions
 
         # l0G loc
         # l0G => l1G
-        #struct $(generate_edge_type(:l0G, :l1G, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l0G, :l1G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
-        $(update_state!)(edge::$(generate_edge_type(:l0G, :l1G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l0G, :l1G, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l0G, :l1G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
+        $(update_state!(:l0G, :l1G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = 0;
          S_values[$(to_idx(:n))] = x[$(idx_obs_var_G)];
          S_values[$(to_idx(:in))] = true;
@@ -84,125 +91,125 @@ function create_automaton_G_and_F(m::ContinuousTimeModel, x1::Float64, x2::Float
 
         # l1G loc
         # l1G => l3G
-        #struct $(generate_edge_type(:l1G, :l3G, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1G, :l3G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1G, :l3G, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1G, :l3G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         S_time <= $t1 && 
         S_values[$(to_idx(:n))] < $x1 || S_values[$(to_idx(:n))] > $x2
-        $(update_state!)(edge::$(generate_edge_type(:l1G, :l3G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1G, :l3G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = min(abs($x1 - S_values[$(to_idx(:n))]), abs($x2 - S_values[$(to_idx(:n))]));
          S_values[$(to_idx(:in))] = false;
          :l3G)
 
-        #struct $(generate_edge_type(:l1G, :l3G, 2)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1G, :l3G, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1G, :l3G, 2)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1G, :l3G, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_time <= $t1) && 
         ($x1 <= S_values[$(to_idx(:n))] <= $x2)
-        $(update_state!)(edge::$(generate_edge_type(:l1G, :l3G, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1G, :l3G, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = 0;
          S_values[$(to_idx(:in))] = false;
          :l3G)
 
-        #struct $(generate_edge_type(:l1G, :l3G, 3)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1G, :l3G, 3)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1G, :l3G, 3)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1G, :l3G, 3))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         !istrue(S_values[$(to_idx(:in))]) && 
         ($t1 <= S_time <= $t2) && 
         ($x1 <= S_values[$(to_idx(:n))] <= $x2)
-        $(update_state!)(edge::$(generate_edge_type(:l1G, :l3G, 3)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1G, :l3G, 3))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))] * (S_time - $t1);
          S_values[$(to_idx(:tprime))] = 0.0;
          :l3G)
 
-        #struct $(generate_edge_type(:l1G, :l3G, 4)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1G, :l3G, 4)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1G, :l3G, 4)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1G, :l3G, 4))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         istrue(S_values[$(to_idx(:in))]) && 
         ($t1 <= S_time <= $t2) && 
         ($x1 <= S_values[$(to_idx(:n))] <= $x2)
-        $(update_state!)(edge::$(generate_edge_type(:l1G, :l3G, 4)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1G, :l3G, 4))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:tprime))] = 0.0;
          :l3G)
 
         # l1G => l4G
-        #struct $(generate_edge_type(:l1G, :l4G, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1G, :l4G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1G, :l4G, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1G, :l4G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         !istrue(S_values[$(to_idx(:in))]) && 
         ($t1 <= S_time <= $t2) && 
         (S_values[$(to_idx(:n))] < $x1 || S_values[$(to_idx(:n))] > $x2)
-        $(update_state!)(edge::$(generate_edge_type(:l1G, :l4G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1G, :l4G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))] + S_values[$(to_idx(:d))] * (S_time - $t1);
          :l4G)
 
-        #struct $(generate_edge_type(:l1G, :l4G, 2)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1G, :l4G, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1G, :l4G, 2)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1G, :l4G, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         istrue(S_values[$(to_idx(:in))]) && 
         ($t1 <= S_time <= $t2) && 
         (S_values[$(to_idx(:n))] < $x1 || S_values[$(to_idx(:n))] > $x2)
-        $(update_state!)(edge::$(generate_edge_type(:l1G, :l4G, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1G, :l4G, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (:l4G)
 
         # l1G => l2G
         #=
-        #struct $(generate_edge_type(:l1G, :l2G, 3)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1G, :l2G, 3)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1G, :l2G, 3)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1G, :l2G, 3))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         istrue(S_values[$(to_idx(:isabs))]) && 
         S_time <= $t1
-        $(update_state!)(edge::$(generate_edge_type(:l1G, :l2G, 3)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1G, :l2G, 3))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = ($t2 - $t1) * min(abs($x1 - S_values[$(to_idx(:n))]), abs($x2 - S_values[$(to_idx(:n))]));
         :l2G)
 
-        #struct $(generate_edge_type(:l1G, :l2G, 4)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1G, :l2G, 4)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1G, :l2G, 4)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1G, :l2G, 4))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         istrue(S_values[$(to_idx(:isabs))]) && 
         ($t1 <= S_time <= $t2)
-        $(update_state!)(edge::$(generate_edge_type(:l1G, :l2G, 4)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1G, :l2G, 4))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))] + ($t2 - S_time) * min(abs($x1 - S_values[$(to_idx(:n))]), abs($x2 - S_values[$(to_idx(:n))]));
         :l2G)
 
-        #struct $(generate_edge_type(:l1G, :l2G, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1G, :l2G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1G, :l2G, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1G, :l2G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         istrue(S_values[$(to_idx(:in))]) && 
         S_time >= $t2
-        $(update_state!)(edge::$(generate_edge_type(:l1G, :l2G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1G, :l2G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (:l2G)
 
-        #struct $(generate_edge_type(:l1G, :l2G, 2)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1G, :l2G, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1G, :l2G, 2)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1G, :l2G, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         !istrue(S_values[$(to_idx(:in))]) && 
         S_time >= $t2
-        $(update_state!)(edge::$(generate_edge_type(:l1G, :l2G, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1G, :l2G, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))] * ($t2 - $t1);
         :l2G)
         =#
 
         # l3G loc
         # l3G => l1G
-        #struct $(generate_edge_type(:l3G, :l1G, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l3G, :l1G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
-        $(update_state!)(edge::$(generate_edge_type(:l3G, :l1G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l3G, :l1G, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l3G, :l1G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
+        $(update_state!(:l3G, :l1G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:n))] = x[$(idx_obs_var_G)];
          S_values[$(to_idx(:isabs))] = $(m.isabsorbing)(p, x);
          :l1G)
 
         # l3G => l2G
-        #struct $(generate_edge_type(:l3G, :l2G, 2)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l3G, :l2G, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l3G, :l2G, 2)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l3G, :l2G, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         istrue(S_values[$(to_idx(:in))]) && 
         (S_time >= $t2 || istrue(S_values[$(to_idx(:isabs))]))
-        $(update_state!)(edge::$(generate_edge_type(:l3G, :l2G, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l3G, :l2G, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))] * ($t2 - $t1);
          :l2G)
 
-        #struct $(generate_edge_type(:l3G, :l2G, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l3G, :l2G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l3G, :l2G, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l3G, :l2G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         !istrue(S_values[$(to_idx(:in))]) && 
         (S_time >= $t2 || istrue(S_values[$(to_idx(:isabs))]))
-        $(update_state!)(edge::$(generate_edge_type(:l3G, :l2G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l3G, :l2G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (:l2G)
 
         # l4G loc
         # l4G => l1G
-        #struct $(generate_edge_type(:l4G, :l1G, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l4G, :l1G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
-        $(update_state!)(edge::$(generate_edge_type(:l4G, :l1G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l4G, :l1G, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l4G, :l1G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
+        $(update_state!(:l4G, :l1G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))] + S_values[$(to_idx(:tprime))] * min(abs($x1 - S_values[$(to_idx(:n))]), abs($x2 - S_values[$(to_idx(:n))]));
          S_values[$(to_idx(:tprime))] = 0.0;
          S_values[$(to_idx(:n))] = x[$(idx_obs_var_G)];
@@ -211,25 +218,25 @@ function create_automaton_G_and_F(m::ContinuousTimeModel, x1::Float64, x2::Float
          :l1G)
 
         # l4G => l2G
-        #struct $(generate_edge_type(:l4G, :l2G, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l4G, :l2G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l4G, :l2G, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l4G, :l2G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (istrue(S_values[$(to_idx(:isabs))]))
-        $(update_state!)(edge::$(generate_edge_type(:l4G, :l2G, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l4G, :l2G, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))] +  ($t2 - S_time) * min(abs($x1 - S_values[$(to_idx(:n))]), abs($x2 - S_values[$(to_idx(:n))]));
          :l2G)
 
-        #struct $(generate_edge_type(:l4G, :l2G, 2)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l4G, :l2G, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l4G, :l2G, 2)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l4G, :l2G, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_time >= $t2)
-        $(update_state!)(edge::$(generate_edge_type(:l4G, :l2G, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l4G, :l2G, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))] +  S_values[$(to_idx(:tprime))] * min(abs($x1 - S_values[$(to_idx(:n))]), abs($x2 - S_values[$(to_idx(:n))]));
          :l2G)
 
 
         # Connection between the two automata: l2G => l1F
-        #struct $(generate_edge_type(:l2G, :l1F, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l2G, :l1F, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
-        $(update_state!)(edge::$(generate_edge_type(:l2G, :l1F, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l2G, :l1F, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l2G, :l1F, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
+        $(update_state!(:l2G, :l1F, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:n))] = x[$(idx_obs_var_F)];
          S_values[$(to_idx(:dprime))] = Inf;
          S_values[$(to_idx(:isabs))] = $(m.isabsorbing)(p, x);
@@ -237,77 +244,77 @@ function create_automaton_G_and_F(m::ContinuousTimeModel, x1::Float64, x2::Float
 
         # l1F loc : we con#struct  the edges of the form l1F => (..)
         # l1F => l2F
-        #struct $(generate_edge_type(:l1F, :l2F, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1F, :l2F, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1F, :l2F, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1F, :l2F, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         S_time >= $t3 &&
         S_values[$(to_idx(:dprime))] == 0 
-        $(update_state!)(edge::$(generate_edge_type(:l1F, :l2F, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1F, :l2F, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (#S_values[$(to_idx(:dprime))] = 0;
          :l2F)
 
-        #struct $(generate_edge_type(:l1F, :l2F, 2)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1F, :l2F, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1F, :l2F, 2)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1F, :l2F, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_time >= $t4) && 
         (S_values[$(to_idx(:n))] < $x3 || S_values[$(to_idx(:n))] > $x4)
-        $(update_state!)(edge::$(generate_edge_type(:l1F, :l2F, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1F, :l2F, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (#S_values[$(to_idx(:dprime))] = min(abs(S_values[$(to_idx(:n))] - $x3), abs(S_values[$(to_idx(:n))] - $x4));
          S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))] + S_values[$(to_idx(:dprime))];
          :l2F)
         #=
-        #struct $(generate_edge_type(:l1F, :l2F, 3)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1F, :l2F, 3)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1F, :l2F, 3)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1F, :l2F, 3))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         istrue(S_values[$(to_idx(:isabs))]) && S_time <= $t4
-        $(update_state!)(edge::$(generate_edge_type(:l1F, :l2F, 3)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1F, :l2F, 3))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))] + S_values[$(to_idx(:dprime))];
         :l2F)
 
-        #struct $(generate_edge_type(:l1F, :l2F, 4)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1F, :l2F, 4)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1F, :l2F, 4)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1F, :l2F, 4))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         S_time >= $t3 &&
         S_values[$(to_idx(:dprime))] == 0 
-        $(update_state!)(edge::$(generate_edge_type(:l1F, :l2F, 4)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1F, :l2F, 4))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (:l2F)
         =#
 
         # l1F => l3F
-        #struct $(generate_edge_type(:l1F, :l3F, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1F, :l3F, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1F, :l3F, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1F, :l3F, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_time <= $t3) &&
         (S_values[$(to_idx(:n))] < $x3 || S_values[$(to_idx(:n))] > $x4)
-        $(update_state!)(edge::$(generate_edge_type(:l1F, :l3F, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1F, :l3F, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:dprime))] = min(sqrt((S_time - $t3)^2 + (S_values[$(to_idx(:n))] - $x4)^2), 
                                             sqrt((S_time - $t3)^2 + (S_values[$(to_idx(:n))] - $x3)^2));
          :l3F)
 
-        #struct $(generate_edge_type(:l1F, :l3F, 2)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1F, :l3F, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1F, :l3F, 2)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1F, :l3F, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         ($x3 <= S_values[$(to_idx(:n))] <= $x4)
-        $(update_state!)(edge::$(generate_edge_type(:l1F, :l3F, 2)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1F, :l3F, 2))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:dprime))] = 0;
          :l3F)
 
-        #struct $(generate_edge_type(:l1F, :l3F, 3)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l1F, :l3F, 3)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l1F, :l3F, 3)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l1F, :l3F, 3))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_time >= $t3) &&
         (S_values[$(to_idx(:n))] < $x3 || S_values[$(to_idx(:n))] > $x4)
-        $(update_state!)(edge::$(generate_edge_type(:l1F, :l3F, 3)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l1F, :l3F, 3))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:dprime))] = min(S_values[$(to_idx(:dprime))], min(abs(S_values[$(to_idx(:n))] - $x3), abs(S_values[$(to_idx(:n))] - $x4)));
          :l3F)
 
         # l3F loc
         # l3F => l1F
-        #struct $(generate_edge_type(:l3F, :l1F, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l3F, :l1F, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
-        $(update_state!)(edge::$(generate_edge_type(:l3F, :l1F, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l3F, :l1F, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l3F, :l1F, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = true
+        $(update_state!(:l3F, :l1F, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:n))] = x[$(idx_obs_var_F)];
          S_values[$(to_idx(:isabs))] = $(m.isabsorbing)(p, x);
          :l1F)
 
         # l3F => l2F
-        #struct $(generate_edge_type(:l3F, :l2F, 1)) <: $(edge_type) transitions::Union{Nothing,Vector{Symbol}} end
-        $(check_constraints)(edge::$(generate_edge_type(:l3F, :l2F, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        #struct $(edge_name(:l3F, :l2F, 1)) <: $(edge_type) transitions::TransitionSet end
+        $(check_constraints(:l3F, :l2F, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_time >= $t4 || istrue(S_values[$(to_idx(:isabs))]))
-        $(update_state!)(edge::$(generate_edge_type(:l3F, :l2F, 1)), S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
+        $(update_state!(:l3F, :l2F, 1))(S_time::Float64, S_values::Vector{Float64}, x::Vector{Int}, p::Vector{Float64}) = 
         (S_values[$(to_idx(:d))] = S_values[$(to_idx(:d))] + S_values[$(to_idx(:dprime))];
          :l2F)
     end
@@ -320,91 +327,113 @@ function create_automaton_G_and_F(m::ContinuousTimeModel, x1::Float64, x2::Float
 
         # l0G loc
         # l0G => l1G
-        edge1 = $(generate_edge_type(:l0G, :l1G, 1))(nothing)
+        edge1 = EdgeAutomatonGandF(nothing, $(check_constraints(:l0G, :l1G, 1)), $(update_state!(:l0G, :l1G, 1)))
         map_edges[:l0G][:l1G] = [edge1]
 
         # l1G => l3G
-        edge1 = $(generate_edge_type(:l1G, :l3G, 1))(nothing)
-        edge2 = $(generate_edge_type(:l1G, :l3G, 2))(nothing)
-        edge3 = $(generate_edge_type(:l1G, :l3G, 3))(nothing)
-        edge4 = $(generate_edge_type(:l1G, :l3G, 4))(nothing)
+        edge1 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1G, :l3G, 1)), $(update_state!(:l1G, :l3G, 1)))
+        edge2 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1G, :l3G, 2)), $(update_state!(:l1G, :l3G, 2)))
+        edge3 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1G, :l3G, 3)), $(update_state!(:l1G, :l3G, 3)))
+        edge4 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1G, :l3G, 4)), $(update_state!(:l1G, :l3G, 4)))
         map_edges[:l1G][:l3G] = [edge1, edge2, edge3, edge4]
 
         # l1G => l4G
-        edge1 = $(generate_edge_type(:l1G, :l4G, 1))(nothing)
-        edge2 = $(generate_edge_type(:l1G, :l4G, 2))(nothing)
+        edge1 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1G, :l4G, 1)), $(update_state!(:l1G, :l4G, 1)))
+        edge2 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1G, :l4G, 2)), $(update_state!(:l1G, :l4G, 2)))
         map_edges[:l1G][:l4G] = [edge1, edge2]
 
         # l1G => l2G
         #=
-        edge1 = $(generate_edge_type(:l1G, :l2G, 1))(nothing)
-        edge2 = $(generate_edge_type(:l1G, :l2G, 2))(nothing)
-        edge3 = $(generate_edge_type(:l1G, :l2G, 3))(nothing)
-        edge4 = $(generate_edge_type(:l1G, :l2G, 4))(nothing)
+        edge1 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1G, :l2G, 1)), $(update_state!(:l1G, :l2G, 1)))
+        edge2 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1G, :l2G, 2)), $(update_state!(:l1G, :l2G, 2)))
+        edge3 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1G, :l2G, 3)), $(update_state!(:l1G, :l2G, 3)))
+        edge4 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1G, :l2G, 4)), $(update_state!(:l1G, :l2G, 4)))
         map_edges[:l1G][:l2G] = [edge3, edge4, edge1, edge2]
         =#
 
         # l3G loc
         # l3G => l1G
-        edge1 = $(generate_edge_type(:l3G, :l1G, 1))([:ALL])
+        edge1 = EdgeAutomatonGandF([:ALL], $(check_constraints(:l3G, :l1G, 1)), $(update_state!(:l3G, :l1G, 1)))
         map_edges[:l3G][:l1G] = [edge1]
 
         # l3G => l2G
-        edge1 = $(generate_edge_type(:l3G, :l2G, 1))(nothing)
-        edge2 = $(generate_edge_type(:l3G, :l2G, 2))(nothing)
+        edge1 = EdgeAutomatonGandF(nothing, $(check_constraints(:l3G, :l2G, 1)), $(update_state!(:l3G, :l2G, 1)))
+        edge2 = EdgeAutomatonGandF(nothing, $(check_constraints(:l3G, :l2G, 2)), $(update_state!(:l3G, :l2G, 2)))
         map_edges[:l3G][:l2G] = [edge1, edge2]
 
         # l4 loc
         # l4G => l1G
-        edge1 = $(generate_edge_type(:l4G, :l1G, 1))([:ALL])
+        edge1 = EdgeAutomatonGandF([:ALL], $(check_constraints(:l4G, :l1G, 1)), $(update_state!(:l4G, :l1G, 1)))
         map_edges[:l4G][:l1G] = [edge1]
 
         # l4G => l2G
-        edge1 = $(generate_edge_type(:l4G, :l2G, 1))(nothing)
-        edge2 = $(generate_edge_type(:l4G, :l2G, 2))(nothing)
+        edge1 = EdgeAutomatonGandF(nothing, $(check_constraints(:l4G, :l2G, 1)), $(update_state!(:l4G, :l2G, 1)))
+        edge2 = EdgeAutomatonGandF(nothing, $(check_constraints(:l4G, :l2G, 2)), $(update_state!(:l4G, :l2G, 2)))
         map_edges[:l4G][:l2G] = [edge1,edge2]
 
         # l2G loc
         # l2G => l1F : Transition from autF to autG
-        edge1 = $(generate_edge_type(:l2G, :l1F, 1))(nothing)
+        edge1 = EdgeAutomatonGandF(nothing, $(check_constraints(:l2G, :l1F, 1)), $(update_state!(:l2G, :l1F, 1)))
         map_edges[:l2G][:l1F] = [edge1]
 
         # l1F loc
         # l1F => l3F
-        edge1 = $(generate_edge_type(:l1F, :l2F, 1))(nothing)
-        edge2 = $(generate_edge_type(:l1F, :l2F, 2))(nothing)
+        edge1 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1F, :l2F, 1)), $(update_state!(:l1F, :l2F, 1)))
+        edge2 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1F, :l2F, 2)), $(update_state!(:l1F, :l2F, 2)))
         map_edges[:l1F][:l2F] = [edge1, edge2]
-        #edge3 = $(generate_edge_type(:l1F, :l2F, 3))(nothing)
-        #edge4 = $(generate_edge_type(:l1F, :l2F, 4))(nothing)
+        #edge3 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1F, :l2F, 3)), $(update_state!(:l1F, :l2F, 3)))
+        #edge4 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1F, :l2F, 4)), $(update_state!(:l1F, :l2F, 4)))
         #map_edges[:l1F][:l2F] = [edge1, edge4, edge3, edge2]
 
         # l1F => l3F
-        edge1 = $(generate_edge_type(:l1F, :l3F, 1))(nothing)
-        edge2 = $(generate_edge_type(:l1F, :l3F, 2))(nothing)
-        edge3 = $(generate_edge_type(:l1F, :l3F, 3))(nothing)
+        edge1 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1F, :l3F, 1)), $(update_state!(:l1F, :l3F, 1)))
+        edge2 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1F, :l3F, 2)), $(update_state!(:l1F, :l3F, 2)))
+        edge3 = EdgeAutomatonGandF(nothing, $(check_constraints(:l1F, :l3F, 3)), $(update_state!(:l1F, :l3F, 3)))
         map_edges[:l1F][:l3F] = [edge1, edge2, edge3]
 
         # l3F loc
         # l3F => l1F
-        edge1 = $(generate_edge_type(:l3F, :l1F, 1))([:ALL])
+        edge1 = EdgeAutomatonGandF([:ALL], $(check_constraints(:l3F, :l1F, 1)), $(update_state!(:l3F, :l1F, 1)))
         map_edges[:l3F][:l1F] = [edge1]
 
         # l3F => l2F
-        edge1 = $(generate_edge_type(:l3F, :l2F, 1))(nothing)    
+        edge1 = EdgeAutomatonGandF(nothing, $(check_constraints(:l3F, :l2F, 1)), $(update_state!(:l3F, :l2F, 1)))    
         map_edges[:l3F][:l2F] = [edge1]
     end
 
+    ## Create data separately
+    map_edges_transitions = Dict{Symbol, Dict{Symbol,Vector{TransitionSet}}}()
+    map_edges_check_constraints = Dict{Symbol, Dict{Symbol,Vector{Function}}}()
+    map_edges_update_state = Dict{Symbol, Dict{Symbol,Vector{Function}}}()
+    for from_loc in keys(map_edges)
+        map_edges_transitions[from_loc] = Dict{Symbol,Vector{TransitionSet}}()
+        map_edges_check_constraints[from_loc] = Dict{Symbol,Vector{Function}}()
+        map_edges_update_state[from_loc] = Dict{Symbol,Vector{Function}}()
+        for to_loc in keys(map_edges[from_loc])
+            map_edges_transitions[from_loc][to_loc] = TransitionSet[]
+            map_edges_check_constraints[from_loc][to_loc] = Function[]
+            map_edges_update_state[from_loc][to_loc] = Function[]
+            for edge in map_edges[from_loc][to_loc]
+                push!(map_edges_transitions[from_loc][to_loc], edge.transitions)
+                push!(map_edges_check_constraints[from_loc][to_loc], edge.check_constraints)
+                push!(map_edges_update_state[from_loc][to_loc], edge.update_state!)
+            end
+        end
+    end
+
     ## Constants
     constants = Dict{Symbol,Float64}(:x1 => x1,  :x2 => x2, :t1 => t1, :t2 => t2,
                                      :x3 => x3,  :x4 => x4, :t3 => t3, :t4 => t4)
 
-    # Updating types and simulation methods
+    # Updating types and simulation method
     @everywhere @eval $(MarkovProcesses.generate_code_synchronized_model_type_def(model_name, lha_name))
-    @everywhere @eval $(MarkovProcesses.generate_code_next_state(lha_name, edge_type, check_constraints, update_state!))
+    @everywhere @eval $(MarkovProcesses.new_generate_code_next_state(lha_name, edge_type))
     @everywhere @eval $(MarkovProcesses.generate_code_synchronized_simulation(model_name, lha_name, edge_type, m.f!, m.isabsorbing))
 
     A = AutomatonGandF(m.transitions, locations, Λ_F, locations_init, locations_final, 
-                       map_var_automaton_idx, flow, map_edges, constants, m.map_var_idx)
+                       map_var_automaton_idx, flow, map_edges, 
+                       map_edges_transitions, map_edges_check_constraints, map_edges_update_state,
+                       constants, m.map_var_idx)
     return A
 end
 
diff --git a/bench/pkg/abstract_array.jl b/bench/pkg/abstract_array.jl
new file mode 100644
index 0000000..2e163ee
--- /dev/null
+++ b/bench/pkg/abstract_array.jl
@@ -0,0 +1,103 @@
+
+using Profile
+using StaticArrays
+using BenchmarkTools
+
+println("Cost of tests:")
+f_test(a::Int) = a == 2
+@btime for i = 1:20
+    f_test(3)
+end
+
+# First container type
+abstract type SuperType end
+for i = 1:10
+    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)
+    @eval item = $(Symbol("Type$(rand_number_type)"))(:test)
+    push!(vec_types, item)
+end
+println("First super type")
+function read(vec_types::Vector{SuperType}, a::Int) 
+    for item in vec_types
+        f(item, a)
+    end
+end
+@btime read(vec_types, 3)
+
+# Second container type
+struct AnotherSuperType{T<:Function}
+    v::Symbol 
+    f::T
+end
+vec_others_types = AnotherSuperType[]
+for i = 1:20
+    rand_number_type = rand(1:10)
+    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")
+function read(vec_others_types::Vector{AnotherSuperType}, a::Int)
+    for item in vec_others_types
+        item.f(a)
+    end
+end
+@btime read(vec_others_types, 3)
+
+# With vectors
+println("Transitions first:")
+vec_tr = Union{Nothing,Symbol}[]
+vec_func = Function[]
+for i = 1:20
+    rand_number_type = rand(1:10)
+    include_string(Main, "f_vec_$(i)(a::Int) = a == $(i)")
+    sym_func = Symbol("f_vec_$i")
+    push!(vec_tr, :test)
+    @eval push!(vec_func, $(sym_func))
+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) 
+    end
+end
+@btime read(vec_tr, vec_func, 3)
+
+println("Transitions second:")
+vec_tr = Union{Nothing,Symbol}[]
+vec_func = Function[]
+for i = 1:20
+    rand_number_type = rand(1:10)
+    name_func = Symbol("f_vec2_$(i)")
+    str_func = "$(name_func)(a::Int) = a == $(rand_number_type)"
+    include_string(Main, str_func)
+    push!(vec_tr, :test)
+    @eval push!(vec_func, $(name_func))
+end
+@btime read(vec_tr, vec_func, 3)
+
+
+# How to store and read efficiently abstract types ?
+d = Dict{Symbol,Dict{Symbol,Vector{Float64}}}()
+for i = 1:10
+    sym_a = Symbol("a$i")
+    sym_b = Symbol("a$i")
+    d[sym_a] = Dict{Symbol,Vector{Float64}}()
+    d[sym_a][sym_b] = zeros(4)
+end
+function f(dict::Dict)
+    for key in keys(dict)
+        for key2 in keys(dict[key])
+            for i = eachindex(dict[key][key2])
+                dict[key][key2][i]
+            end
+        end
+    end
+end
+@btime f(d)
+
diff --git a/bench/pkg/check_constraints_sync_R6.jl b/bench/pkg/check_constraints_sync_R6.jl
new file mode 100644
index 0000000..2f1976e
--- /dev/null
+++ b/bench/pkg/check_constraints_sync_R6.jl
@@ -0,0 +1,222 @@
+
+using StaticArrays
+using BenchmarkTools
+using MarkovProcesses
+using Profile
+
+load_model("ER")
+observe_all!(ER)
+set_param!(ER, [:k1, :k2], [0.2, 40.0])
+set_time_bound!(ER, 0.9)
+
+load_automaton("automaton_G_and_F")
+x1, x2, t1, t2 = 50.0, 100.0, 0.0, 0.8
+x3, x4, t3, t4 = 30.0, 100.0, 0.8, 0.9
+A_G_F = create_automaton_G_and_F(ER, x1, x2, t1, t2, :E,
+                                 x3, x4, t3, t4, :P)
+sync_ER = ER * A_G_F
+
+S = init_state(A_G_F, ER.x0, ER.t0)
+time = 0.1
+values = S.values
+x, p = ER.x0, ER.p
+for loc_from in keys(A_G_F.map_edges)
+    for loc_to in keys(A_G_F.map_edges[loc_from])
+        println("$loc_from => $loc_to")
+        for i = eachindex(A_G_F.map_edges[loc_from][loc_to])
+            println("edge $i:")
+            global global_edge = A_G_F.map_edges[loc_from][loc_to][i]
+            #@btime check_constraints_AutomatonGandF(global_edge, time, $(copy(values)), x, p)
+            #b = @benchmark check_constraints_AutomatonGandF(global_edge, time, $(copy(values)), x, p)
+            #@show mean(b).time, mean(b).memory
+        end
+    end
+end
+
+function my_find_edge_candidates!(edge_candidates::Vector{EdgeAutomatonGandF},
+                                  edges_from_current_loc::Dict{Location,Vector{EdgeAutomatonGandF}},
+                                  Λ::Dict{Location,Function},
+                                  S_time::Float64, S_values::Vector{Float64},
+                                  x::Vector{Int}, p::Vector{Float64},
+                                  only_asynchronous::Bool)
+    nbr_candidates = 0
+    for target_loc in keys(edges_from_current_loc)
+        if !Λ[target_loc](x) continue end
+        for i = eachindex(edges_from_current_loc[target_loc])
+            edge = edges_from_current_loc[target_loc][i]
+            test_cc = check_constraints_AutomatonGandF(edge, S_time, S_values, x, p)
+            if test_cc
+                if edge.transitions == nothing
+                    _push_edge!(edge_candidates, edge, nbr_candidates)
+                    nbr_candidates += 1
+                    return nbr_candidates
+                else
+                    if !only_asynchronous
+                        _push_edge!(edge_candidates, edge, nbr_candidates)
+                        nbr_candidates += 1
+                    end
+                end
+            end
+        end
+    end
+    return nbr_candidates
+end
+
+function svector_find_edge_candidates!(edge_candidates::Vector{EdgeAutomatonGandF},
+                                  edges_from_current_loc::Dict,
+                                  Λ::Dict{Location,Function},
+                                  S_time::Float64, S_values::Vector{Float64},
+                                  x::Vector{Int}, p::Vector{Float64},
+                                  only_asynchronous::Bool)
+    nbr_candidates = 0
+    for target_loc in keys(edges_from_current_loc)
+        if !Λ[target_loc](x) continue end
+        for edge in edges_from_current_loc[target_loc]
+            test_cc = check_constraints_AutomatonGandF(edge, S_time, S_values, x, p)
+            if test_cc
+                if edge.transitions == nothing
+                    _push_edge!(edge_candidates, edge, nbr_candidates)
+                    nbr_candidates += 1
+                    return nbr_candidates
+                else
+                    if !only_asynchronous
+                        _push_edge!(edge_candidates, edge, nbr_candidates)
+                        nbr_candidates += 1
+                    end
+                end
+            end
+        end
+    end
+    return nbr_candidates
+end
+
+
+edge_candidates = Vector{EdgeAutomatonGandF}(undef, 2)
+edges_from_current_loc = getfield(A_G_F, :map_edges)[:l1G]
+Λ = A_G_F.Λ
+
+function transform_dict_tuple(dict::Dict{Symbol,Dict{Symbol,Vector{EdgeAutomatonGandF}}})
+    new_dict = Dict()
+    for from_loc in keys(dict)
+        for to_loc in keys(dict[from_loc])
+            new_dict[from_loc] = (to_loc, dict[from_loc][to_loc])
+        end
+    end
+    return new_dict
+end
+function transform_dict_static(dict::Dict{Symbol,Dict{Symbol,Vector{EdgeAutomatonGandF}}})
+    new_dict = Dict{Symbol,Dict{Symbol,SVector}}()
+    for from_loc in keys(dict)
+        new_dict[from_loc] = Dict{Symbol,SVector}()
+        for to_loc in keys(dict[from_loc])
+            d = dict[from_loc][to_loc]
+            new_dict[from_loc][to_loc] = SVector{length(d)}(d) 
+        end
+    end
+    return new_dict
+end
+new_map_edges = transform_dict_tuple(A_G_F.map_edges)
+new_edges_from_current_loc = new_map_edges[:l1G]
+vec_edges = new_map_edges[:l1G][2]
+#concrete_vec_edges = Vector{typeof(vec_edges[1])}(vec_edges)
+svector_map_edges = transform_dict_static(A_G_F.map_edges)
+svector_edges_from_current_loc = svector_map_edges[:l1G]
+static_vec_edges = SVector{length(vec_edges)}(vec_edges)
+tuple_edges = Tuple(vec_edges)
+
+println("Test of the current implementation")
+@btime begin
+    for target_loc in keys(edges_from_current_loc)
+        for edge in edges_from_current_loc[target_loc]
+            test_cc = check_constraints_AutomatonGandF(edge, time, values, x, p)
+        end
+    end
+end
+println("Test with pairs")
+@btime begin
+    for pair_target_loc_edges in edges_from_current_loc
+        for edge in pair_target_loc_edges.second
+            test_cc = check_constraints_AutomatonGandF(edge, time, values, x, p)
+        end
+    end
+end
+println("New map")
+@btime begin
+    for target_loc_edges in new_edges_from_current_loc
+        for edge in new_edges_from_current_loc[2]
+            test_cc = check_constraints_AutomatonGandF(edge, time, values, x, p)
+        end
+    end
+end
+println("Read of a edge vector 1 (collection iteration)")
+@btime begin
+    for edge in vec_edges
+        test_cc = check_constraints_AutomatonGandF(edge, time, values, x, p)
+    end
+end
+println("Read of a edge vector 2 (eachindex)")
+@btime begin
+    for i = eachindex(vec_edges)
+        test_cc = check_constraints_AutomatonGandF(vec_edges[i], time, values, x, p)
+    end
+end
+println("Read of a edge vector 3 (steprange)")
+@btime begin
+    for i = 1:length(vec_edges)
+        test_cc = check_constraints_AutomatonGandF(vec_edges[i], time, values, x, p)
+    end
+end
+println("Read of a edge vector 4 (steprange 2)")
+nb_edges = length(vec_edges)
+@btime begin
+    for i = 1:nb_edges
+        test_cc = check_constraints_AutomatonGandF(vec_edges[i], time, values, x, p)
+    end
+end
+println("Read of an edge vector 5 (static vectors)")
+@btime begin
+    for i = eachindex(static_vec_edges)
+        test_cc = check_constraints_AutomatonGandF(static_vec_edges[i], time, values, x, p)
+    end
+end
+println("Read of an edge vector 6 (tuples)")
+@show typeof(tuple_edges)
+@btime begin
+    for i = eachindex(tuple_edges)
+        test_cc = check_constraints_AutomatonGandF(tuple_edges[i], time, values, x, p)
+    end
+end
+#=
+println("Read of an edge vector 7 (concrete type)")
+@show typeof(vec_edges)
+@show typeof(concrete_vec_edges)
+@btime begin
+    for edge in concrete_vec_edges
+        #test_cc = check_constraints_AutomatonGandF(edge, time, values, x, p)
+    end
+end
+=#
+println("Read of an edge vector 8 (concrete type v2)")
+@show vec_edges
+concrete_2_vec_edges = Vector{Union{Nothing,Vector{Symbol}}}([e.transitions for e in vec_edges])
+@btime begin
+    for i = eachindex(concrete_2_vec_edges)
+        concrete_2_vec_edges[i]
+        #test_cc = check_constraints_AutomatonGandF(edge, time, values, x, p)
+    end
+end
+
+b_find = @benchmark _find_edge_candidates!(edge_candidates, edges_from_current_loc, Λ, time, values, x, p, false)
+@show mean(b_find).time, mean(b_find).memory
+
+b_svector_find = @benchmark svector_find_edge_candidates!(edge_candidates, svector_edges_from_current_loc, Λ, time, values, x, p, false)
+@show mean(b_svector_find).time, mean(b_svector_find).memory
+
+Profile.clear_malloc_data()
+b_myfind = @benchmark my_find_edge_candidates!(edge_candidates, edges_from_current_loc, Λ, time, values, x, p, false)
+@show mean(b_myfind).time, mean(b_myfind).memory
+
+#=
+The problem is that in each step of these benchmarks, an abstract type is involved
+=#
+
diff --git a/core/MarkovProcesses.jl b/core/MarkovProcesses.jl
index 65f1a58..e848313 100644
--- a/core/MarkovProcesses.jl
+++ b/core/MarkovProcesses.jl
@@ -18,7 +18,7 @@ export Distribution, Product, Uniform, Normal
 # Common types and constructors
 export Observations, AbstractTrajectory, Trajectory, SynchronizedTrajectory
 export Model, ContinuousTimeModel, SynchronizedModel, ParametricModel
-export VariableModel, ParameterModel, Transition
+export VariableModel, ParameterModel, Transition, TransitionSet
 export LHA, StateLHA, Edge, Location, VariableAutomaton
 
 # Trajectory related methods
diff --git a/core/common.jl b/core/common.jl
index 4a501df..c22a583 100644
--- a/core/common.jl
+++ b/core/common.jl
@@ -11,6 +11,7 @@ abstract type Edge end
 const VariableModel = Symbol
 const ParameterModel = Symbol
 const Transition = Union{Symbol,Nothing}
+const TransitionSet = Union{Vector{Symbol},Nothing}
 const Location = Symbol
 const VariableAutomaton = Symbol
 
@@ -55,6 +56,9 @@ function generate_code_lha_type_def(lha_name::Symbol, edge_type::Symbol)
             map_var_automaton_idx::Dict{VariableAutomaton,Int} # nvar keys : str_var => idx in values
             flow::Dict{Location,Vector{Float64}} # output of length nvar
             map_edges::Dict{Location, Dict{Location,Vector{$(edge_type)}}}
+            map_edges_transitions::Dict{Location, Dict{Location,Vector{TransitionSet}}}
+            map_edges_check_constraints::Dict{Location, Dict{Location,Vector{Function}}}
+            map_edges_update_state::Dict{Location, Dict{Location,Vector{Function}}}
             constants::Dict{Symbol,Float64}
             map_var_model_idx::Dict{VariableModel,Int} # of dim d (of a model)
         end
diff --git a/core/lha.jl b/core/lha.jl
index 8f5fcc5..30fd1ec 100644
--- a/core/lha.jl
+++ b/core/lha.jl
@@ -90,8 +90,234 @@ function init_state(A::LHA, x0::Vector{Int}, t0::Float64)
     return S0
 end
 
-function generate_code_next_state(lha_name::Symbol, edge_type::Symbol, 
-                                  check_constraints::Symbol, update_state!::Symbol)
+function generate_code_next_state_with_dicts_lha(lha_name::Symbol, edge_type::Symbol)
+    
+    return quote 
+        # A push! method implementend by myself because of preallocation of edge_candidates
+        function _push_edge!(edge_id_candidates::Vector{Int}, target_loc_candidates::Vector{Symbol}, 
+                             edge_id::Int, target_loc::Symbol, nbr_candidates::Int)
+            if nbr_candidates < length(edge_id_candidates)
+                 edge_id_candidates[nbr_candidates+1] = edge_id
+                 target_loc_candidates[nbr_candidates+1] = target_loc
+            else
+                push!(edge_id_candidates, edge_id)
+                push!(target_loc_candidates, target_loc)
+            end
+        end
+
+        function _find_edge_candidates!(edge_id_candidates::Vector{Int}, target_loc_candidates::Vector{Symbol},
+                                        dict_transitions_from_current_loc::Dict{Location,Vector{TransitionSet}},
+                                        dict_check_constraints_from_current_loc::Dict{Location,Vector{Function}},
+                                        Λ::Dict{Location,Function},
+                                        S_time::Float64, S_values::Vector{Float64},
+                                        x::Vector{Int}, p::Vector{Float64},
+                                        only_asynchronous::Bool)
+            nbr_candidates = 0
+            for target_loc in keys(dict_transitions_from_current_loc)
+                if !Λ[target_loc](x) continue end
+                for i = eachindex(dict_transitions_from_current_loc[target_loc])
+                    check_constraints_edge = dict_check_constraints_from_current_loc[target_loc][i]
+                    if check_constraints_edge(S_time, S_values, x, p)
+                        transitions = dict_transitions_from_current_loc[target_loc][i]
+                        if transitions == nothing
+                            _push_edge!(edge_id_candidates, target_loc_candidates, i, target_loc, nbr_candidates)
+                            nbr_candidates += 1
+                            return nbr_candidates
+                        else
+                            if !only_asynchronous
+                                _push_edge!(edge_id_candidates, target_loc_candidates, i, target_loc, nbr_candidates)
+                                nbr_candidates += 1
+                            end
+                        end
+                    end
+                end
+            end
+            return nbr_candidates
+        end
+
+        function _get_edge_index(edge_id_candidates::Vector{Int}, target_loc_candidates::Vector{Symbol}, nbr_candidates::Int,
+                                 dict_transitions_from_current_loc::Dict{Location,Vector{TransitionSet}},
+                                 detected_event::Bool, tr_nplus1::Transition)
+            ind_edge = 0
+            bool_event = detected_event
+            for i = 1:nbr_candidates
+                target_loc = target_loc_candidates[i]
+                edge_id = edge_id_candidates[i]
+                transitions = dict_transitions_from_current_loc[target_loc][edge_id]
+                # Asynchronous edge detection: we fire it
+                if transitions == nothing
+                    return (i, detected_event)
+                end
+                # Synchronous detection
+                if !detected_event && tr_nplus1 != nothing
+                    if (transitions[1] == :ALL) || (tr_nplus1 in transitions)
+                        ind_edge = i
+                        bool_event = true
+                    end
+                end
+            end
+            return (ind_edge, bool_event)
+        end
+
+        function next_state!(A::$(lha_name),
+                             ptr_loc_state::Vector{Symbol}, values_state::Vector{Float64}, ptr_time_state::Vector{Float64},
+                             xnplus1::Vector{Int}, tnplus1::Float64, tr_nplus1::Transition, 
+                             xn::Vector{Int}, p::Vector{Float64},
+                             edge_id_candidates::Vector{Int}, target_loc_candidates::Vector{Symbol}; verbose::Bool = false)
+            # En fait d'apres observation de Cosmos, après qu'on ait lu la transition on devrait stop.
+            detected_event::Bool = false
+            turns = 0
+            Λ = getfield(A, :Λ)
+            flow = getfield(A, :flow)
+            map_edges = A.map_edges
+            map_edges_transitions = A.map_edges_transitions
+            map_edges_check_constraints = A.map_edges_check_constraints
+            map_edges_update_state = A.map_edges_update_state
+            if verbose 
+                println("##### Begin next_state!")
+                @show xnplus1, tnplus1, tr_nplus1
+            end
+            # First, we check the asynchronous transitions
+            while true
+                turns += 1
+                if verbose @show turns end
+                #edge_candidates = empty!(edge_candidates) 
+                dict_transitions_from_current_loc = map_edges_transitions[ptr_loc_state[1]]
+                dict_check_constraints_from_current_loc = map_edges_check_constraints[ptr_loc_state[1]]
+                # Save all edges that satisfies transition predicate (asynchronous ones)
+                nbr_candidates = _find_edge_candidates!(edge_id_candidates, target_loc_candidates, 
+                                                        dict_transitions_from_current_loc, dict_check_constraints_from_current_loc,
+                                                        Λ, ptr_time_state[1], values_state, xn, p, 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_id_candidates, target_loc_candidates, nbr_candidates, 
+                                                           dict_transitions_from_current_loc,
+                                                           detected_event, nothing)
+                # Update the state with the chosen one (if it exists)
+                # Should be xn here
+                #first_round = false
+                if ind_edge > 0
+                    edge_target_loc = target_loc_candidates[ind_edge]
+                    edge_id = edge_id_candidates[ind_edge]
+                    firing_update_state! = map_edges_update_state[ptr_loc_state[1]][edge_target_loc][edge_id]
+                    ptr_loc_state[1] = firing_update_state!(ptr_time_state[1], values_state, xn, p)
+                else
+                    if verbose 
+                        println("No edge fired:")
+                        @show ind_edge, detected_event, nbr_candidates
+                    end
+                    break 
+                end
+                if verbose
+                    println("Edge fired:")
+                    @show edge_id_candidates, target_loc_candidates
+                    @show ind_edge, detected_event, nbr_candidates
+                    @show ptr_loc_state[1]
+                    @show ptr_time_state[1]
+                    @show values_state
+                    if turns == 500
+                        @warn "We've reached 500 turns"
+                    end
+                end
+                # For debug
+                #=
+                if turns > 100
+                println("Number of turns in next_state! is suspicious")
+                @show first_round, detected_event
+                @show length(edge_candidates)
+                @show tnplus1, tr_nplus1, xnplus1
+                @show edge_candidates
+                error("Unpredicted behavior automaton")
+                end
+                =#
+            end
+            if verbose 
+                println("Time flies with the flow...")
+            end
+            # Now time flies according to the flow
+            for i in eachindex(values_state)
+                 coeff_deriv = flow[ptr_loc_state[1]][i]
+                if coeff_deriv > 0
+                      values_state[i] += coeff_deriv*(tnplus1 - ptr_time_state[1])
+                end
+            end
+            ptr_time_state[1] = tnplus1
+            if verbose 
+                @show ptr_loc_state[1]
+                @show ptr_time_state[1]
+                @show values_state
+            end
+            # Now firing an edge according to the event 
+            while true
+                turns += 1
+                if verbose @show turns end
+                edges_from_current_loc = map_edges[ptr_loc_state[1]]
+                dict_transitions_from_current_loc = map_edges_transitions[ptr_loc_state[1]]
+                dict_check_constraints_from_current_loc = map_edges_check_constraints[ptr_loc_state[1]]
+                # Save all edges that satisfies transition predicate (synchronous ones)
+                nbr_candidates = _find_edge_candidates!(edge_id_candidates, target_loc_candidates,
+                                                        dict_transitions_from_current_loc, dict_check_constraints_from_current_loc,
+                                                        Λ, ptr_time_state[1], values_state, xnplus1, p, false)
+                # Search the one we must chose
+                ind_edge, detected_event = _get_edge_index(edge_id_candidates, target_loc_candidates, nbr_candidates, 
+                                                           dict_transitions_from_current_loc,
+                                                           detected_event, tr_nplus1)
+                # Update the state with the chosen one (if it exists)
+                if ind_edge > 0
+                    edge_target_loc = target_loc_candidates[ind_edge]
+                    edge_id = edge_id_candidates[ind_edge]
+                    firing_update_state! = map_edges_update_state[ptr_loc_state[1]][edge_target_loc][edge_id]
+                    ptr_loc_state[1] = firing_update_state!(ptr_time_state[1], values_state, xnplus1, p)
+                end
+                if ind_edge == 0 || detected_event
+                    if verbose 
+                        if detected_event    
+                            println("Synchronized with $(tr_nplus1)") 
+                            @show edge_id_candidates, target_loc_candidates
+                            @show ind_edge, detected_event, nbr_candidates
+                            @show detected_event
+                            @show ptr_loc_state[1]
+                            @show ptr_time_state[1]
+                            @show values_state
+                        else
+                            println("No edge fired")
+                        end
+                    end
+                    break 
+                end
+                if verbose
+                    @show edge_id_candidates, target_loc_candidates
+                    @show ind_edge, detected_event, nbr_candidates
+                    @show detected_event
+                    @show ptr_loc_state[1]
+                    @show ptr_time_state[1]
+                    @show values_state
+                    if turns == 500
+                        @warn "We've reached 500 turns"
+                    end
+                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
+                error("Unpredicted behavior automaton")
+                end
+                =#
+            end
+            if verbose 
+                println("##### End next_state!") 
+            end
+        end
+    end
+end
+
+############################################################################################################
+
+function generate_code_next_state(lha_name::Symbol, edge_type::Symbol)
     
     return quote 
         # A push! method implementend by myself because of preallocation of edge_candidates
@@ -113,8 +339,8 @@ function generate_code_next_state(lha_name::Symbol, edge_type::Symbol,
             for target_loc in keys(edges_from_current_loc)
                 if !Λ[target_loc](x) continue end
                 for edge in edges_from_current_loc[target_loc]
-                    if $(check_constraints)(edge, S_time, S_values, x, p)
-                        if getfield(edge, :transitions) == nothing
+                    if edge.check_constraints(S_time, S_values, x, p)
+                        if edge.transitions == nothing
                             _push_edge!(edge_candidates, edge, nbr_candidates)
                             nbr_candidates += 1
                             return nbr_candidates
@@ -137,13 +363,12 @@ function generate_code_next_state(lha_name::Symbol, edge_type::Symbol,
             for i = 1:nbr_candidates
                 edge = edge_candidates[i]
                 # Asynchronous edge detection: we fire it
-                if getfield(edge, :transitions) == nothing
+                if edge.transitions == nothing
                     return (i, detected_event)
                 end
                 # Synchronous detection
                 if !detected_event && tr_nplus1 != nothing
-                    if (getfield(edge, :transitions)[1] == :ALL) || 
-                        (tr_nplus1 in getfield(edge, :transitions))
+                    if (edge.transitions[1] == :ALL) || (tr_nplus1 in edge.transitions)
                         ind_edge = i
                         bool_event = true
                     end
@@ -184,7 +409,7 @@ function generate_code_next_state(lha_name::Symbol, edge_type::Symbol,
                 #first_round = false
                 if ind_edge > 0
                     firing_edge = edge_candidates[ind_edge]
-                    ptr_loc_state[1] = $(update_state!)(firing_edge, ptr_time_state[1], values_state, xn, p)
+                    ptr_loc_state[1] = firing_edge.update_state!(ptr_time_state[1], values_state, xn, p)
                 else
                     if verbose println("No edge fired") end
                     break 
@@ -240,7 +465,7 @@ function generate_code_next_state(lha_name::Symbol, edge_type::Symbol,
                 # Update the state with the chosen one (if it exists)
                 if ind_edge > 0
                     firing_edge = edge_candidates[ind_edge]
-                    ptr_loc_state[1] = $(update_state!)(firing_edge, ptr_time_state[1], values_state, xnplus1, p)
+                    ptr_loc_state[1] = firing_edge.update_state!(ptr_time_state[1], values_state, xnplus1, p)
                 end
                 if ind_edge == 0 || detected_event
                     if verbose 
diff --git a/core/model.jl b/core/model.jl
index ef32b37..9be33af 100644
--- a/core/model.jl
+++ b/core/model.jl
@@ -145,7 +145,9 @@ function generate_code_synchronized_simulation(model_name::Symbol, lha_name::Sym
             time_bound = getfield(m, :time_bound)
             buffer_size = getfield(m, :buffer_size)
             estim_min_states = getfield(m, :estim_min_states)
-            edge_candidates = Vector{$(edge_type)}(undef, 2)
+            #edge_candidates = Vector{$(edge_type)}(undef, 2)
+            edge_id_candidates = zeros(Int, 2)
+            target_loc_candidates = Vector{Symbol}(undef, 2)
             # First alloc
             full_values = Vector{Vector{Int}}(undef, getfield(m, :dim_state))
             for i = eachindex(full_values) full_values[i] = zeros(Int, estim_min_states) end
@@ -164,7 +166,7 @@ function generate_code_synchronized_simulation(model_name::Symbol, lha_name::Sym
             xn = copy(x0)
             tn = copy(t0) 
             next_state!(A, ptr_loc_state, values_state, ptr_time_state, 
-                        x0, t0, nothing, x0, p_sim, edge_candidates; verbose = verbose)
+                        x0, t0, nothing, x0, p_sim, edge_id_candidates, target_loc_candidates; verbose = verbose)
             isabsorbing::Bool = $(isabsorbing)(p_sim,xn)
             isacceptedLHA::Bool = isaccepted(ptr_loc_state[1], A)
             # Alloc of vectors where we stock n+1 values
@@ -180,7 +182,7 @@ function generate_code_synchronized_simulation(model_name::Symbol, lha_name::Sym
                 end
                 if isabsorbing && !isacceptedLHA
                     next_state!(A, ptr_loc_state, values_state, ptr_time_state, 
-                                xn, time_bound, nothing, xn, p_sim, edge_candidates; verbose = verbose)
+                                xn, time_bound, nothing, xn, p_sim, edge_id_candidates, target_loc_candidates; verbose = verbose)
                 end
                 setfield!(S, :loc, ptr_loc_state[1])
                 setfield!(S, :time, ptr_time_state[1])
@@ -195,7 +197,7 @@ function generate_code_synchronized_simulation(model_name::Symbol, lha_name::Sym
                     break
                 end
                 n += 1
-                next_state!(A, ptr_loc_state, values_state, ptr_time_state, vec_x, l_t[1], l_tr[1], xn, p_sim, edge_candidates; verbose = verbose)
+                next_state!(A, ptr_loc_state, values_state, ptr_time_state, vec_x, l_t[1], l_tr[1], xn, p_sim, edge_id_candidates, target_loc_candidates; verbose = verbose)
                 copyto!(xn, vec_x)
                 tn = l_t[1]
                 tr_n = l_tr[1]
@@ -214,7 +216,7 @@ function generate_code_synchronized_simulation(model_name::Symbol, lha_name::Sym
                 end
                 if isabsorbing && !isacceptedLHA
                     next_state!(A, ptr_loc_state, values_state, ptr_time_state, 
-                                xn, time_bound, nothing, xn, p_sim, edge_candidates; verbose = verbose)
+                                xn, time_bound, nothing, xn, p_sim, edge_id_candidates, target_loc_candidates; verbose = verbose)
                 end
                 setfield!(S, :loc, ptr_loc_state[1])
                 setfield!(S, :time, ptr_time_state[1])
@@ -239,7 +241,7 @@ function generate_code_synchronized_simulation(model_name::Symbol, lha_name::Sym
                         i -= 1
                         break
                     end
-                    next_state!(A, ptr_loc_state, values_state, ptr_time_state, vec_x, l_t[1], l_tr[1], xn, p_sim, edge_candidates; verbose = verbose)
+                    next_state!(A, ptr_loc_state, values_state, ptr_time_state, vec_x, l_t[1], l_tr[1], xn, p_sim, edge_id_candidates, target_loc_candidates; verbose = verbose)
                     copyto!(xn, vec_x)
                     tn = l_t[1]
                     tr_n = l_tr[1]
@@ -265,7 +267,7 @@ function generate_code_synchronized_simulation(model_name::Symbol, lha_name::Sym
             end
             if isabsorbing && !isacceptedLHA
                 next_state!(A, ptr_loc_state, values_state, ptr_time_state, 
-                            xn, time_bound, nothing, xn, p_sim, edge_candidates; verbose = verbose)
+                            xn, time_bound, nothing, xn, p_sim, edge_id_candidates, target_loc_candidates; verbose = verbose)
             end
             setfield!(S, :loc, ptr_loc_state[1])
             setfield!(S, :time, ptr_time_state[1])
@@ -280,13 +282,15 @@ function generate_code_synchronized_simulation(model_name::Symbol, lha_name::Sym
             ptr_loc_state = [S.loc]
             values_state = S.values
             ptr_time_state = [S.time]
-            edge_candidates = Vector{$(edge_type)}(undef, 2)
+            #edge_candidates = Vector{$(edge_type)}(undef, 2)
+            edge_id_candidates = zeros(Int, 2)
+            target_loc_candidates = Vector{Symbol}(undef, 2)
             # Values at time n
             n = 1
             xn = copy(x0)
             tn = copy(t0) 
             next_state!(A, ptr_loc_state, values_state, ptr_time_state, 
-                        x0, t0, nothing, x0, p_sim, edge_candidates; verbose = verbose)
+                        x0, t0, nothing, x0, p_sim, edge_id_candidates, target_loc_candidates; verbose = verbose)
             isabsorbing::Bool = $(isabsorbing)(p_sim,xn)
             isacceptedLHA::Bool = isaccepted(ptr_loc_state[1], A)
             # Alloc of vectors where we stock n+1 values
@@ -297,7 +301,7 @@ function generate_code_synchronized_simulation(model_name::Symbol, lha_name::Sym
             if isabsorbing || isacceptedLHA 
                 if !isacceptedLHA
                     next_state!(A, ptr_loc_state, values_state, ptr_time_state, 
-                                xn, time_bound, nothing, xn, p_sim, edge_candidates; verbose = verbose)
+                                xn, time_bound, nothing, xn, p_sim, edge_id_candidates, target_loc_candidates; verbose = verbose)
                 end
                 setfield!(S, :loc, ptr_loc_state[1])
                 setfield!(S, :time, ptr_time_state[1])
@@ -314,7 +318,7 @@ function generate_code_synchronized_simulation(model_name::Symbol, lha_name::Sym
                     break
                 end
                 next_state!(A, ptr_loc_state, values_state, ptr_time_state, 
-                            vec_x, l_t[1], l_tr[1], xn, p_sim, edge_candidates; verbose = verbose)
+                            vec_x, l_t[1], l_tr[1], xn, p_sim, edge_id_candidates, target_loc_candidates; verbose = verbose)
                 copyto!(xn, vec_x)
                 tn = l_t[1]
                 tr_n = l_tr[1]
@@ -323,7 +327,7 @@ function generate_code_synchronized_simulation(model_name::Symbol, lha_name::Sym
             end
             if isabsorbing && !isacceptedLHA
                 next_state!(A, ptr_loc_state, values_state, ptr_time_state, 
-                            xn, time_bound, nothing, xn, p_sim, edge_candidates; verbose = verbose)
+                            xn, time_bound, nothing, xn, p_sim, edge_id_candidates, target_loc_candidates; verbose = verbose)
             end
             setfield!(S, :loc, ptr_loc_state[1])
             setfield!(S, :time, ptr_time_state[1])
-- 
GitLab