Theory FSM

(*  Title:       Finite state machines
    ID:
    Author:      Peter Lammich <peter.lammich@uni-muenster.de>
    Maintainer:  Peter Lammich <peter.lammich@uni-muenster.de>
*)

section ‹ Finite state machines ›
theory FSM
imports DPN_Setup
begin

text ‹
  This theory models nondeterministic finite state machines with explicit set of states and alphabet. @{text ε}-transitions are not supported.
›

subsection ‹ Definitions ›

record ('s,'a) FSM_rec =
  Q :: "'s set" ― ‹The set of states›
  Σ :: "'a set" ― ‹The alphabet›
  δ :: "('s, 'a) LTS" ― ‹The transition relation›
  s0 :: "'s" ― ‹The initial state›
  F :: "'s set" ― ‹The set of final states›

locale FSM = 
  fixes A
  assumes delta_cons: "(q,l,q')δ A  qQ A  lΣ A  q'Q A" ― ‹The transition relation is consistent with the set of states and the alphabet›
  assumes s0_cons: "s0 A  Q A" ― ‹The initial state is a state›
  assumes F_cons: "F A  Q A" ― ‹The final states are states›
  assumes finite_states: "finite (Q A)" ― ‹The set of states is finite›
  assumes finite_alphabet: "finite (Σ A)" ― ‹The alphabet is finite›

subsection ‹ Basic properties ›
lemma (in FSM) finite_delta_dom: "finite (Q A × Σ A × Q A)" proof -
  from finite_states finite_alphabet finite_cartesian_product[of "Σ A" "Q A"] have "finite (Σ A × Q A)" by fast
  with finite_states finite_cartesian_product[of "Q A" "Σ A × Q A"] show "finite (Q A × Σ A × Q A)" by fast
qed

lemma (in FSM) finite_delta: "finite (δ A)" proof -
  have "δ A  Q A × Σ A × Q A" by (auto simp add: delta_cons)
  with finite_delta_dom show ?thesis by (simp add: finite_subset)
qed

subsection ‹Constructing FSMs›

definition "fsm_empty s0   Q={s0}, Σ={}, δ={}, s0=s0, F={} "
definition "fsm_add_F s fsm  fsm Q:=insert s (Q fsm), F:=insert s (F fsm) "
definition "fsm_add_tr q a q' fsm  fsm Q:={q,q'}  (Q fsm), Σ:=insert a (Σ fsm), δ := insert (q,a,q') (δ fsm) "

lemma fsm_empty_invar[simp]: "FSM (fsm_empty s)"
  apply unfold_locales unfolding fsm_empty_def by auto
  
lemma fsm_add_F_invar[simp]: assumes "FSM fsm" shows "FSM (fsm_add_F s fsm)"  
proof -
  interpret FSM fsm by fact
  show ?thesis
    apply unfold_locales
    unfolding fsm_add_F_def
    using delta_cons s0_cons F_cons finite_states finite_alphabet
    by auto
qed

lemma fsm_add_tr_invar[simp]: assumes "FSM fsm" shows "FSM (fsm_add_tr q a q' fsm)"  
proof -
  interpret FSM fsm by fact
  show ?thesis
    apply unfold_locales
    unfolding fsm_add_tr_def
    using delta_cons s0_cons F_cons finite_states finite_alphabet
    by auto
qed



subsection ‹ Reflexive, transitive closure of transition relation ›

text ‹ Reflexive transitive closure on restricted domain ›

inductive_set trclAD :: "('s,'a,'c) FSM_rec_scheme  ('s,'a) LTS  ('s,'a list) LTS" 
for A D
where
  empty[simp]: "sQ A  (s,[],s)trclAD A D" |
  cons[simp]: "(s,e,s')D; sQ A; eΣ A; (s',w,s'')trclAD A D  (s,e#w,s'')trclAD A D"

abbreviation "trclA A == trclAD A (δ A)"
(*syntax trclA :: "('s,'a,'c) FSM_rec_scheme ⇒ ('s,'a list) LTS"
translations "trclA A" => "trclAD A (δ A)"*)

lemma trclAD_empty_cons[simp]: "(c,[],c')trclAD A D  c=c'" by (auto elim: trclAD.cases)
lemma trclAD_single: "(c,[a],c')  trclAD A D  (c,a,c')  D" by (auto elim: trclAD.cases)
lemma trclAD_elems: "(c,w,c')trclAD A D  cQ A  wlists (Σ A)  c'Q A" by (erule trclAD.induct, auto)
lemma trclAD_one_elem: "cQ A; eΣ A; c'Q A; (c,e,c')D  (c,[e],c')trclAD A D" by auto


lemma trclAD_uncons: "(c,a#w,c')trclAD A D  ch . (c,a,ch)D  (ch,w,c')  trclAD A D  cQ A  aΣ A" 
  by (auto elim: trclAD.cases)

lemma trclAD_concat: "!! c .  (c,w1,c')trclAD A D; (c',w2,c'')trclAD A D   (c,w1@w2,c'')trclAD A D" 
proof (induct w1)
  case Nil thus ?case by (subgoal_tac "c=c'") auto
next
  case (Cons a w) thus ?case by (auto dest: trclAD_uncons)
qed    
 
lemma trclAD_unconcat: "!! c . (c,w1@w2,c')trclAD A D  ch . (c,w1,ch)trclAD A D  (ch,w2,c')trclAD A D" proof (induct w1)
  case Nil hence "(c,[],c)trclAD A D  (c,w2,c')trclAD A D" by (auto dest: trclAD_elems)
  thus ?case by fast
next
  case (Cons a w1) note IHP = this
  hence "(c,a#(w1@w2),c')trclAD A D" by simp (* Auto/fast/blast do not get the point _#(_@_) = (_#_)@_ in next step, so making it explicit *)
  with trclAD_uncons obtain chh where "(c,a,chh)D  (chh,w1@w2,c')trclAD A D  cQ A  aΣ A" by fast
  moreover with IHP obtain ch where "(chh,w1,ch)trclAD A D  (ch,w2,c')trclAD A D" by fast
  ultimately have "(c,a#w1,ch)trclAD A D  (ch,w2,c')trclAD A D" by auto
  thus ?case by fast
qed

lemma trclAD_eq: "Q A = Q A'; Σ A = Σ A'  trclAD A D = trclAD A' D" 
  apply (safe)
  subgoal by (erule trclAD.induct) auto
  subgoal by (erule trclAD.induct) auto
  done

lemma trclAD_mono: "DD'  trclAD A D  trclAD A D'"
  apply (clarsimp)
  apply (erule trclAD.induct)
  apply auto
  done

lemma trclAD_mono_adv: "DD'; Q A = Q A'; Σ A = Σ A'  trclAD A D  trclAD A' D'" by (subgoal_tac "trclAD A D = trclAD A' D") (auto dest: trclAD_eq trclAD_mono)


subsubsection ‹ Relation of @{term trclAD} and @{term LTS.trcl}
lemma trclAD_by_trcl1: "trclAD A D  (trcl (D  (Q A × Σ A × Q A))  (Q A × lists (Σ A) × Q A))"
  by (auto 0 3 dest: trclAD_elems elim: trclAD.induct simp: trclAD_elems intro: trcl.cons)

lemma trclAD_by_trcl2: "(trcl (D  (Q A × Σ A × Q A))  (Q A × lists (Σ A) × Q A))  trclAD A D " proof -
  { fix c
    have "!! s s' . (s, c, s')  trcl (D  Q A × Σ A × Q A); sQ A; s'Q A; clists (Σ A)  (s,c,s')trclAD A D" proof (induct c)
      case Nil thus ?case by (auto dest: trcl_empty_cons)
    next
      case (Cons e w) note IHP=this
      then obtain sh where SPLIT: "(s,e,sh)(D  Q A × Σ A × Q A)  (sh,w,s')trcl (D  Q A × Σ A × Q A)" by (fast dest: trcl_uncons)
      hence "(sh,w,s')trcl (D  Q A × Σ A × Q A)  (Q A × lists (Σ A) × Q A)" by (auto elim!: trcl_structE)
      hence "(sh,w,s')trclAD A D" by (blast intro: IHP)
      with SPLIT show ?case by auto
    qed
  }
  thus ?thesis by (auto)
qed
    
lemma trclAD_by_trcl: "trclAD A D = (trcl (D  (Q A × Σ A × Q A))  (Q A × lists (Σ A) × Q A))" 
  apply (rule equalityI)
  apply (rule trclAD_by_trcl1)
  apply (rule trclAD_by_trcl2)
  done

lemma trclAD_by_trcl': "trclAD A D = (trcl (D  (Q A × Σ A × Q A))  (Q A × UNIV × UNIV))"
  by (auto iff add: trclAD_by_trcl elim!: trcl_structE)

lemma trclAD_by_trcl'': " DQ A × Σ A × Q A   trclAD A D = trcl D  (Q A × UNIV × UNIV)"
  using trclAD_by_trcl'[of A D] by (simp add: Int_absorb2)

lemma trclAD_subset_trcl: "trclAD A D  trcl (D)" proof -
  have "trclAD A D  (trcl (D  (Q A × Σ A × Q A)))" by (auto simp add: trclAD_by_trcl)
  also with trcl_mono[of "D  (Q A × Σ A × Q A)" D] have "  trcl D" by auto
  finally show ?thesis .
qed

subsection ‹ Language of a FSM ›
  

definition "langs A s == { w . ( f(F A) . (s,w,f)  trclA A) }"
definition "lang A == langs A (s0 A)"

lemma langs_alt_def: "(wlangs A s) == (f . fF A & (s,w,f)  trclA A)" by (intro eq_reflection, unfold langs_def, auto)

subsection ‹ Example: Product automaton ›

definition "prod_fsm A1 A2 ==  Q=Q A1 × Q A2, Σ=Σ A1  Σ A2, δ = { ((s,t),a,(s',t')) . (s,a,s')δ A1  (t,a,t')δ A2 }, s0=(s0 A1,s0 A2), F = {(s,t) . sF A1  tF A2} "

lemma prod_inter_1: "!! s s' f f' . ((s,s'),w,(f,f'))  trclA (prod_fsm A A')  (s,w,f)  trclA A  (s',w,f')  trclA A'" proof (induct w) 
  case Nil note P=this 
  moreover hence "s=f  s'=f'" by (fast dest: trclAD_empty_cons)
  moreover from P have "sQ A  s'Q A'" by (unfold prod_fsm_def, auto dest: trclAD_elems)
  ultimately show ?case by (auto)
next
  case (Cons e w)
  note IHP=this
  then obtain m m' where I: "((s,s'),e,(m,m'))  δ (prod_fsm A A')  (s,s')Q (prod_fsm A A')  eΣ (prod_fsm A A')  ((m,m'),w,(f,f'))trclA (prod_fsm A A')" by (fast dest: trclAD_uncons)
  hence "(s,e,m)δ A  (s',e,m')δ A'  sQ A  s'Q A'  eΣ A  eΣ A'" by (unfold prod_fsm_def, simp)
  moreover from I IHP have "(m,w,f)trclA A  (m',w,f')trclA A'" by auto
  ultimately show ?case by auto
qed
  
lemma prod_inter_2: "!! s s' f f' . (s,w,f)  trclA A  (s',w,f')  trclA A'  ((s,s'),w,(f,f'))  trclA (prod_fsm A A')" proof (induct w)
  case Nil note P=this
  moreover hence "s=f  s'=f'" by (fast dest: trclAD_empty_cons)
  moreover from P have "(s,s')Q (prod_fsm A A')" by (unfold prod_fsm_def, auto dest: trclAD_elems)
  ultimately show ?case by simp
next
  case (Cons e w)
  note IHP=this
  then obtain m m' where I: "(s,e,m)δ A  (m,w,f)trclA A  (s',e,m')δ A'  (m',w,f')trclA A'  sQ A  s'Q A'  eΣ A  eΣ A'" by (fast dest: trclAD_uncons)
  hence "((s,s'),e,(m,m'))  δ (prod_fsm A A')  (s,s')Q (prod_fsm A A')  eΣ (prod_fsm A A')" by (unfold prod_fsm_def, simp)
  moreover from I IHP have "((m,m'),w,(f,f'))  trclA (prod_fsm A A')" by auto
  ultimately show ?case by auto
qed
  
lemma prod_F: "(a,b)F (prod_fsm A B) = (aF A  bF B)" by (unfold prod_fsm_def, auto)
lemma prod_FI: "aF A; bF B  (a,b)F (prod_fsm A B)" by (unfold prod_fsm_def, auto)

lemma prod_fsm_langs: "langs (prod_fsm A B) (s,t) = langs A s  langs B t"
  apply (unfold langs_def)
  apply (insert prod_inter_1 prod_F)
  apply (fast intro: prod_inter_2 prod_FI)
done

lemma prod_FSM_intro: "FSM A1  FSM A2  FSM (prod_fsm A1 A2)" by (rule FSM.intro) (auto simp add: FSM_def prod_fsm_def)


end