Theory Finite_Automata

chapter ‹An Application: Finite Automata›

theory Finite_Automata imports Ordinal
begin

text ‹The point of this example is that the HF sets are closed under disjoint sums and Cartesian products,
 allowing the theory of finite state machines to be developed without issues of polymorphism
 or any tricky encodings of states.›

record 'a fsm = states :: hf
                init :: hf
                final :: hf
                "next" :: "hf  'a  hf  bool"

inductive reaches :: "['a fsm, hf, 'a list, hf]  bool"
where
    Nil:  "st  states fsm  reaches fsm st [] st"
  | Cons: "next fsm st x st''; reaches fsm st'' xs st'; st  states fsm  reaches fsm st (x#xs) st'"

declare reaches.intros [intro]
inductive_simps reaches_Nil [simp]:  "reaches fsm st [] st'"
inductive_simps reaches_Cons [simp]: "reaches fsm st (x#xs) st'"

lemma reaches_imp_states: "reaches fsm st xs st'  st  states fsm  st'  states fsm"
  by (induct xs arbitrary: st st', auto)

lemma reaches_append_iff:
     "reaches fsm st (xs@ys) st'  (st''. reaches fsm st xs st''  reaches fsm st'' ys st')"
  by (induct xs arbitrary: ys st st') (auto simp: reaches_imp_states)

definition accepts :: "'a fsm  'a list  bool"  where
  "accepts fsm xs  st st'. reaches fsm st xs st'  st  init fsm  st'  final fsm"

definition regular :: "'a list set  bool" where
  "regular S  fsm. S = {xs. accepts fsm xs}"

definition Null where
  "Null = states = 0, init = 0, final = 0, next = λst x st'. False"

theorem regular_empty:  "regular {}"
  by (auto simp: regular_def accepts_def) (metis hempty_iff simps(2))

abbreviation NullStr where
  "NullStr  states = 1, init = 1, final = 1, next = λst x st'. False"

theorem regular_emptystr:  "regular {[]}"
proof -
  have "x::'a list. reaches NullStr 0 x 0  x = []"
    using reaches.simps by fastforce
  then show ?thesis
    unfolding regular_def accepts_def
    by (rule_tac x = NullStr in exI) auto
qed

abbreviation SingStr where
  "SingStr a  states = 0, 1, init = 0, final = 1, next = λst x st'. st=0  x=a  st'=1"

theorem regular_singstr: "regular {[a]}"
proof -
  have "x::'a list. reaches (SingStr a) 0 x 1  x = [a]"
    by (smt (verit, best) one_neq_zero reaches.simps select_convs(4))
  then show ?thesis
    unfolding regular_def accepts_def
    by (rule_tac x = "SingStr a" in exI) auto
qed

definition Reverse where
  "Reverse fsm = states = states fsm, init = final fsm, final = init fsm,
                  next = λst x st'. next fsm st' x st"

lemma Reverse_Reverse_ident [simp]: "Reverse (Reverse fsm) = fsm"
  by (simp add: Reverse_def)

lemma reaches_Reverse_iff [simp]:
     "reaches (Reverse fsm) st (rev xs) st'  reaches fsm st' xs st"
  by (induct xs arbitrary: st st') (auto simp add: Reverse_def reaches_append_iff reaches_imp_states)

lemma reaches_Reverse_iff2 [simp]:
     "reaches (Reverse fsm) st' xs st  reaches fsm st (rev xs) st'"
  by (metis reaches_Reverse_iff rev_rev_ident)

lemma [simp]: "init (Reverse fsm) = final fsm"
  by (simp add: Reverse_def)

lemma [simp]: "final (Reverse fsm) = init fsm"
  by (simp add: Reverse_def)

lemma accepts_Reverse: "rev ` {xs. accepts fsm xs} = {xs. accepts (Reverse fsm) xs}"
  by (fastforce simp: accepts_def image_iff)

theorem regular_rev: "regular S  regular (rev ` S)"
  by (metis accepts_Reverse regular_def)

definition Times where
  "Times fsm1 fsm2 = states = states fsm1 * states fsm2,
                      init = init fsm1 * init fsm2,
                      final = final fsm1 * final fsm2,
                      next = λst x st'. (st1 st2 st1' st2'. st = st1,st2  st' = st1',st2' 
                                      next fsm1 st1 x st1'  next fsm2 st2 x st2')"

lemma states_Times [simp]: "states (Times fsm1 fsm2) = states fsm1 * states fsm2"
  by (simp add: Times_def)

lemma init_Times [simp]: "init (Times fsm1 fsm2) = init fsm1 * init fsm2"
  by (simp add: Times_def)

lemma final_Times [simp]: "final (Times fsm1 fsm2) = final fsm1 * final fsm2"
  by (simp add: Times_def)

lemma next_Times: "next (Times fsm1 fsm2) st1,st2 x st' 
    (st1' st2'. st' = st1',st2'  next fsm1 st1 x st1'  next fsm2 st2 x st2')"
  by (simp add: Times_def)

lemma reaches_Times_iff [simp]:
     "reaches (Times fsm1 fsm2) st1,st2 xs st1',st2' 
      reaches fsm1 st1 xs st1'  reaches fsm2 st2 xs st2'"
proof (induction xs arbitrary: st1 st2 st1' st2')
  case Nil
  then show ?case by auto
next
  case (Cons a xs)
  then show ?case
    by (force simp add: next_Times Times_def reaches.Cons)
qed

lemma accepts_Times_iff [simp]:
     "accepts (Times fsm1 fsm2) xs  accepts fsm1 xs  accepts fsm2 xs"
  by (force simp add: accepts_def)

theorem regular_Int:
  assumes S: "regular S" and T: "regular T" shows "regular (S  T)"
proof -
  obtain fsmS fsmT where "S = {xs. accepts fsmS xs}" "T = {xs. accepts fsmT xs}" using S T
    by (auto simp: regular_def)
  hence "S  T = {xs. accepts (Times fsmS fsmT) xs}"
    by (auto simp: accepts_Times_iff [of fsmS fsmT])
  thus ?thesis
    by (metis regular_def)
qed

definition Plus where
  "Plus fsm1 fsm2 = states = states fsm1 + states fsm2,
                      init = init fsm1 + init fsm2,
                      final = final fsm1 + final fsm2,
                      next = λst x st'. (st1 st1'. st = Inl st1  st' = Inl st1'  next fsm1 st1 x st1') 
                                       (st2 st2'. st = Inr st2  st' = Inr st2'  next fsm2 st2 x st2')"

lemma states_Plus [simp]: "states (Plus fsm1 fsm2) = states fsm1 + states fsm2"
  by (simp add: Plus_def)

lemma init_Plus [simp]: "init (Plus fsm1 fsm2) = init fsm1 + init fsm2"
  by (simp add: Plus_def)

lemma final_Plus [simp]: "final (Plus fsm1 fsm2) = final fsm1 + final fsm2"
  by (simp add: Plus_def)

lemma next_Plus1: "next (Plus fsm1 fsm2) (Inl st1) x st'  (st1'. st' = Inl st1'  next fsm1 st1 x st1')"
  by (simp add: Plus_def)

lemma next_Plus2: "next (Plus fsm1 fsm2) (Inr st2) x st'  (st2'. st' = Inr st2'  next fsm2 st2 x st2')"
  by (simp add: Plus_def)

lemma reaches_Plus_iff1 [simp]:
     "reaches (Plus fsm1 fsm2) (Inl st1) xs st' 
      (st1'. st' = Inl st1'  reaches fsm1 st1 xs st1')"
proof (induction xs arbitrary: st1)
  case Nil
  then show ?case by auto
next
  case (Cons a xs)
  then show ?case 
    by (force simp add: next_Plus1 reaches.Cons)
qed

lemma reaches_Plus_iff2 [simp]:
     "reaches (Plus fsm1 fsm2) (Inr st2) xs st' 
      (st2'. st' = Inr st2'  reaches fsm2 st2 xs st2')"
proof (induction xs arbitrary: st2)
  case Nil
  then show ?case by auto
next
  case (Cons a xs)
  then show ?case by (force simp add: next_Plus2 reaches.Cons)
qed

lemma reaches_Plus_iff [simp]:
     "reaches (Plus fsm1 fsm2) st xs st' 
      (st1 st1'. st = Inl st1  st' = Inl st1'  reaches fsm1 st1 xs st1') 
      (st2 st2'. st = Inr st2  st' = Inr st2'  reaches fsm2 st2 xs st2')"
proof (induction xs arbitrary: st st')
  case Nil
  then show ?case by auto
next
  case (Cons a xs)
  then show ?case
    by (smt (verit) Plus_def list.simps(3) reaches.simps reaches_Plus_iff1 reaches_Plus_iff2 select_convs(4))
qed

lemma accepts_Plus_iff [simp]:
     "accepts (Plus fsm1 fsm2) xs  accepts fsm1 xs  accepts fsm2 xs"
  by (auto simp: accepts_def) (metis sum_iff)

lemma regular_Un:
  assumes S: "regular S" and T: "regular T" shows "regular (S  T)"
proof -
  obtain fsmS fsmT where "S = {xs. accepts fsmS xs}" "T = {xs. accepts fsmT xs}" using S T
    by (auto simp: regular_def)
  hence "S  T = {xs. accepts (Plus fsmS fsmT) xs}"
    by (auto simp: accepts_Plus_iff [of fsmS fsmT])
  thus ?thesis
    by (metis regular_def)
qed

end