section ‹Underlying FSM Representation›
text ‹This theory contains the underlying datatype for (possibly not well-formed) finite state machines.›
theory FSM_Impl
imports Util Datatype_Order_Generator.Order_Generator "HOL-Library.FSet"
begin
text ‹A finite state machine (FSM) is represented using its classical definition:›
datatype ('state, 'input, 'output) fsm_impl = FSMI (initial : 'state)
(states : "'state set")
(inputs : "'input set")
(outputs : "'output set")
(transitions : "('state × 'input × 'output × 'state) set")
subsection ‹Types for Transitions and Paths›
type_synonym ('a,'b,'c) transition = "('a × 'b × 'c × 'a)"
type_synonym ('a,'b,'c) path = "('a,'b,'c) transition list"
abbreviation "t_source (a :: ('a,'b,'c) transition) ≡ fst a"
abbreviation "t_input (a :: ('a,'b,'c) transition) ≡ fst (snd a)"
abbreviation "t_output (a :: ('a,'b,'c) transition) ≡ fst (snd (snd a))"
abbreviation "t_target (a :: ('a,'b,'c) transition) ≡ snd (snd (snd a))"
subsection ‹Basic Algorithms on FSM›
subsubsection ‹Reading FSMs from Lists›
fun fsm_impl_from_list :: "'a →
('a,'b,'c) transition list →
('a, 'b, 'c) fsm_impl"
where
"fsm_impl_from_list q [] = FSMI q {q} {} {} {}" |
"fsm_impl_from_list q (t#ts) =
(let ts' = set (t#ts)
in FSMI (t_source t)
((image t_source ts') ∪ (image t_target ts'))
(image t_input ts')
(image t_output ts')
(ts'))"
fun fsm_impl_from_list' :: "'a → ('a,'b,'c) transition list → ('a, 'b, 'c) fsm_impl" where
"fsm_impl_from_list' q [] = FSMI q {q} {} {} {}" |
"fsm_impl_from_list' q (t#ts) = (let tsr = (remdups (t#ts))
in FSMI (t_source t)
(set (remdups ((map t_source tsr) @ (map t_target tsr))))
(set (remdups (map t_input tsr)))
(set (remdups (map t_output tsr)))
(set tsr))"
lemma fsm_impl_from_list_code[code] :
"fsm_impl_from_list q ts = fsm_impl_from_list' q ts"
by (cases ts; auto)
subsubsection ‹Changing the initial State›
fun from_FSMI :: "('a,'b,'c) fsm_impl → 'a → ('a,'b,'c) fsm_impl" where
"from_FSMI M q = (if q ∈ states M then FSMI q (states M) (inputs M) (outputs M) (transitions M) else M)"
subsubsection ‹Product Construction›
fun product :: "('a,'b,'c) fsm_impl → ('d,'b,'c) fsm_impl → ('a × 'd,'b,'c) fsm_impl" where
"product A B = FSMI ((initial A, initial B))
((states A) × (states B))
(inputs A ∪ inputs B)
(outputs A ∪ outputs B)
{((qA,qB),x,y,(qA',qB')) | qA qB x y qA' qB' . (qA,x,y,qA') ∈ transitions A ∧ (qB,x,y,qB') ∈ transitions B}"
lemma product_code_naive[code] :
"product A B = FSMI ((initial A, initial B))
((states A) × (states B))
(inputs A ∪ inputs B)
(outputs A ∪ outputs B)
(image (λ((qA,x,y,qA'), (qB,x',y',qB')) . ((qA,qB),x,y,(qA',qB'))) (Set.filter (λ((qA,x,y,qA'), (qB,x',y',qB')) . x = x' ∧ y = y') (∪(image (λ tA . image (λ tB . (tA,tB)) (transitions B)) (transitions A)))))"
(is "?P1 = ?P2")
proof -
have "(∪(image (λ tA . image (λ tB . (tA,tB)) (transitions B)) (transitions A))) = {(tA,tB) | tA tB . tA ∈ transitions A ∧ tB ∈ transitions B}"
by auto
then have "(Set.filter (λ((qA,x,y,qA'), (qB,x',y',qB')) . x = x' ∧ y = y') (∪(image (λ tA . image (λ tB . (tA,tB)) (transitions B)) (transitions A)))) = {((qA,x,y,qA'),(qB,x,y,qB')) | qA qB x y qA' qB' . (qA,x,y,qA') ∈ transitions A ∧ (qB,x,y,qB') ∈ transitions B}"
by auto
then have "image (λ((qA,x,y,qA'), (qB,x',y',qB')) . ((qA,qB),x,y,(qA',qB'))) (Set.filter (λ((qA,x,y,qA'), (qB,x',y',qB')) . x = x' ∧ y = y') (∪(image (λ tA . image (λ tB . (tA,tB)) (transitions B)) (transitions A))))
= image (λ((qA,x,y,qA'), (qB,x',y',qB')) . ((qA,qB),x,y,(qA',qB'))) {((qA,x,y,qA'),(qB,x,y,qB')) | qA qB x y qA' qB' . (qA,x,y,qA') ∈ transitions A ∧ (qB,x,y,qB') ∈ transitions B}"
by auto
moreover have "image (λ((qA,x,y,qA'), (qB,x',y',qB')) . ((qA,qB),x,y,(qA',qB'))) {((qA,x,y,qA'),(qB,x,y,qB')) | qA qB x y qA' qB' . (qA,x,y,qA') ∈ transitions A ∧ (qB,x,y,qB') ∈ transitions B} = {((qA,qB),x,y,(qA',qB')) | qA qB x y qA' qB' . (qA,x,y,qA') ∈ transitions A ∧ (qB,x,y,qB') ∈ transitions B}"
by force
ultimately have "transitions ?P1 = transitions ?P2"
unfolding product.simps by auto
moreover have "initial ?P1 = initial ?P2" by auto
moreover have "states ?P1 = states ?P2" by auto
moreover have "inputs ?P1 = inputs ?P2" by auto
moreover have "outputs ?P1 = outputs ?P2" by auto
ultimately show ?thesis by auto
qed
subsubsection ‹Filtering Transitions›
fun filter_transitions :: "('a,'b,'c) fsm_impl → (('a,'b,'c) transition → bool) → ('a,'b,'c) fsm_impl" where
"filter_transitions M P = FSMI (initial M)
(states M)
(inputs M)
(outputs M)
(Set.filter P (transitions M))"
subsubsection ‹Filtering States›
fun filter_states :: "('a,'b,'c) fsm_impl → ('a → bool) → ('a,'b,'c) fsm_impl" where
"filter_states M P = (if P (initial M) then FSMI (initial M)
(Set.filter P (states M))
(inputs M)
(outputs M)
(Set.filter (λ t . P (t_source t) ∧ P (t_target t)) (transitions M))
else M)"
subsubsection ‹Initial Singleton FSMI (For Trivial Preamble)›
fun initial_singleton :: "('a,'b,'c) fsm_impl → ('a,'b,'c) fsm_impl" where
"initial_singleton M = FSMI (initial M)
{initial M}
(inputs M)
(outputs M)
{}"
subsubsection ‹Canonical Separator›
abbreviation "shift_Inl t ≡ (Inl (t_source t),t_input t, t_output t, Inl (t_target t))"
definition shifted_transitions :: "(('a × 'a) × 'b × 'c × ('a × 'a)) set → ((('a × 'a) + 'd) × 'b × 'c × (('a × 'a) + 'd)) set" where
"shifted_transitions ts = image shift_Inl ts"
definition distinguishing_transitions :: "(('a × 'b) → 'c set) → 'a → 'a → ('a × 'a) set → 'b set → ((('a × 'a) + 'a) × 'b × 'c × (('a × 'a) + 'a)) set" where
"distinguishing_transitions f q1 q2 stateSet inputSet = ∪ (Set.image (λ((q1',q2'),x) .
(image (λy . (Inl (q1',q2'),x,y,Inr q1)) (f (q1',x) - f (q2',x)))
∪ (image (λy . (Inl (q1',q2'),x,y,Inr q2)) (f (q2',x) - f (q1',x))))
(stateSet × inputSet))"
(* Note: parameter P is added to allow usage of different restricted versions of the product machine *)
fun canonical_separator' :: "('a,'b,'c) fsm_impl → (('a × 'a),'b,'c) fsm_impl → 'a → 'a → (('a × 'a) + 'a,'b,'c) fsm_impl" where
"canonical_separator' M P q1 q2 = (if initial P = (q1,q2)
then
(let f' = set_as_map (image (λ(q,x,y,q') . ((q,x),y)) (transitions M));
f = (λqx . (case f' qx of Some yqs → yqs | None → {}));
shifted_transitions' = shifted_transitions (transitions P);
distinguishing_transitions_lr = distinguishing_transitions f q1 q2 (states P) (inputs P);
ts = shifted_transitions' ∪ distinguishing_transitions_lr
in
FSMI (Inl (q1,q2))
((image Inl (states P)) ∪ {Inr q1, Inr q2})
(inputs M ∪ inputs P)
(outputs M ∪ outputs P)
(ts))
else FSMI (Inl (q1,q2)) {Inl (q1,q2)} {} {} {})"
lemma h_out_impl_helper: "(λ (q,x) . {y . ∃ q' . (q,x,y,q') ∈ A}) = (λqx . (case (set_as_map (image (λ(q,x,y,q') . ((q,x),y)) A)) qx of Some yqs → yqs | None → {}))"
proof
fix qx
show "(λ (q,x) . {y . ∃ q' . (q,x,y,q') ∈ A}) qx = (λqx . (case (set_as_map (image (λ(q,x,y,q') . ((q,x),y)) A)) qx of Some yqs → yqs | None → {})) qx"
proof -
obtain q x where "qx = (q,x)" using prod.exhaust by metis
have **: "∧ z . ((q, x), z) ∈ (λ(q, x, y, q'). ((q, x), y)) ` A = (z ∈ {y . ∃ q' . (q,x,y,q') ∈ A})"
by force
show ?thesis unfolding ‹qx = (q,x)› case_prod_conv set_as_map_def
unfolding ** by auto
qed
qed
lemma canonical_separator'_simps :
"initial (canonical_separator' M P q1 q2) = Inl (q1,q2)"
"states (canonical_separator' M P q1 q2) = (if initial P = (q1,q2) then (image Inl (states P)) ∪ {Inr q1, Inr q2} else {Inl (q1,q2)})"
"inputs (canonical_separator' M P q1 q2) = (if initial P = (q1,q2) then inputs M ∪ inputs P else {})"
"outputs (canonical_separator' M P q1 q2) = (if initial P = (q1,q2) then outputs M ∪ outputs P else {})"
"transitions (canonical_separator' M P q1 q2) = (if initial P = (q1,q2) then shifted_transitions (transitions P) ∪ distinguishing_transitions (λ (q,x) . {y . ∃ q' . (q,x,y,q') ∈ transitions M}) q1 q2 (states P) (inputs P) else {})"
unfolding h_out_impl_helper by (simp add: Let_def)+
subsubsection ‹Generalised Canonical Separator›
text ‹A variation on the state separator that uses states @{text "L"} and @{text "R"} instead of
@{text "Inr q1"} and @{text "Inr q2"} to indicate targets of transitions in the
canonical separator that are available only for the left or right component of a state pair›
text ‹Note: this definition of a canonical separator might serve as a way to avoid recalculation
of state separators for different pairs of states, but is currently not fully
implemented›
datatype LR = Left | Right
derive linorder LR
definition distinguishing_transitions_LR :: "(('a × 'b) → 'c set) → ('a × 'a) set → 'b set → ((('a × 'a) + LR) × 'b × 'c × (('a × 'a) + LR)) set" where
"distinguishing_transitions_LR f stateSet inputSet = ∪ (Set.image (λ((q1',q2'),x) .
(image (λy . (Inl (q1',q2'),x,y,Inr Left)) (f (q1',x) - f (q2',x)))
∪ (image (λy . (Inl (q1',q2'),x,y,Inr Right)) (f (q2',x) - f (q1',x))))
(stateSet × inputSet))"
fun canonical_separator_complete' :: "('a,'b,'c) fsm_impl → (('a × 'a) + LR,'b,'c) fsm_impl" where
"canonical_separator_complete' M =
(let P = product M M;
f' = set_as_map (image (λ(q,x,y,q') . ((q,x),y)) (transitions M));
f = (λqx . (case f' qx of Some yqs → yqs | None → {}));
shifted_transitions' = shifted_transitions (transitions P);
distinguishing_transitions_lr = distinguishing_transitions_LR f (states P) (inputs P);
ts = shifted_transitions' ∪ distinguishing_transitions_lr
in
FSMI (Inl (initial P))
((image Inl (states P)) ∪ {Inr Left, Inr Right})
(inputs M ∪ inputs P)
(outputs M ∪ outputs P)
ts )"
subsubsection ‹Adding Transitions›
fun add_transitions :: "('a,'b,'c) fsm_impl → ('a,'b,'c) transition set → ('a,'b,'c) fsm_impl" where
"add_transitions M ts = (if (∀ t ∈ ts . t_source t ∈ states M ∧ t_input t ∈ inputs M ∧ t_output t ∈ outputs M ∧ t_target t ∈ states M)
then FSMI (initial M)
(states M)
(inputs M)
(outputs M)
((transitions M) ∪ ts)
else M)"
subsubsection ‹Creating an FSMI without transitions›
fun create_unconnected_FSMI :: "'a → 'a set → 'b set → 'c set → ('a,'b,'c) fsm_impl" where
"create_unconnected_FSMI q ns ins outs = (if (finite ns ∧ finite ins ∧ finite outs)
then FSMI q (insert q ns) ins outs {}
else FSMI q {q} {} {} {})"
fun create_unconnected_fsm_from_lists :: "'a → 'a list → 'b list → 'c list → ('a,'b,'c) fsm_impl" where
"create_unconnected_fsm_from_lists q ns ins outs = FSMI q (insert q (set ns)) (set ins) (set outs) {}"
fun create_unconnected_fsm_from_fsets :: "'a → 'a fset → 'b fset → 'c fset → ('a,'b,'c) fsm_impl" where
"create_unconnected_fsm_from_fsets q ns ins outs = FSMI q (insert q (fset ns)) (fset ins) (fset outs) {}"
fun create_fsm_from_sets :: "'a → 'a set → 'b set → 'c set → ('a,'b,'c) transition set → ('a,'b,'c) fsm_impl" where
"create_fsm_from_sets q qs ins outs ts = (if q ∈ qs ∧ finite qs ∧ finite ins ∧ finite outs
then add_transitions (FSMI q qs ins outs {}) ts
else FSMI q {q} {} {} {})"
subsection ‹Transition Function h›
text ‹Function @{text "h"} represents the classical view of the transition relation of an FSM @{text "M"} as a
function: given a state @{text "q"} and an input @{text "x"}, @{text "(h M) (q,x)"} returns all
possibly reactions @{text "(y,q')"} of @{text "M"} in state @{text "q"} to @{text "x"}, where
@{text "y"} is the produced output and @{text "q'"} the target state of the reaction transition.›
fun h :: "('state, 'input, 'output) fsm_impl → ('state × 'input) → ('output × 'state) set" where
"h M (q,x) = { (y,q') . (q,x,y,q') ∈ transitions M }"
fun h_obs :: "('a,'b,'c) fsm_impl → 'a → 'b → 'c → 'a option" where
"h_obs M q x y = (let
tgts = snd ` Set.filter (λ (y',q') . y' = y) (h M (q,x))
in if card tgts = 1
then Some (the_elem tgts)
else None)"
lemma h_code[code] :
"h M (q,x) = (let m = set_as_map (image (λ(q,x,y,q') . ((q,x),y,q')) (transitions M))
in (case m (q,x) of Some yqs → yqs | None → {}))"
unfolding set_as_map_def by force
subsection ‹Extending FSMs by single elements›
fun add_transition :: "('a,'b,'c) fsm_impl →
('a,'b,'c) transition →
('a,'b,'c) fsm_impl"
where
"add_transition M t =
(if t_source t ∈ states M ∧ t_input t ∈ inputs M ∧
t_output t ∈ outputs M ∧ t_target t ∈ states M
then FSMI (initial M)
(states M)
(inputs M)
(outputs M)
(insert t (transitions M))
else M)"
fun add_state :: "('a,'b,'c) fsm_impl → 'a → ('a,'b,'c) fsm_impl" where
"add_state M q = FSMI (initial M) (insert q (states M)) (inputs M) (outputs M) (transitions M)"
fun add_input :: "('a,'b,'c) fsm_impl → 'b → ('a,'b,'c) fsm_impl" where
"add_input M x = FSMI (initial M) (states M) (insert x (inputs M)) (outputs M) (transitions M)"
fun add_output :: "('a,'b,'c) fsm_impl → 'c → ('a,'b,'c) fsm_impl" where
"add_output M y = FSMI (initial M) (states M) (inputs M) (insert y (outputs M)) (transitions M)"
fun add_transition_with_components :: "('a,'b,'c) fsm_impl → ('a,'b,'c) transition → ('a,'b,'c) fsm_impl" where
"add_transition_with_components M t = add_transition (add_state (add_state (add_input (add_output M (t_output t)) (t_input t)) (t_source t)) (t_target t)) t"
subsection ‹Renaming elements›
fun rename_states :: "('a,'b,'c) fsm_impl → ('a → 'd) → ('d,'b,'c) fsm_impl" where
"rename_states M f = FSMI (f (initial M))
(f ` states M)
(inputs M)
(outputs M)
((λt . (f (t_source t), t_input t, t_output t, f (t_target t))) ` transitions M)"
end
¤ Dauer der Verarbeitung: 0.7 Sekunden
¤
*© Formatika GbR, Deutschland
|
|