# Theory Position_Autos

```(*  Author: Tobias Nipkow, Dmitriy Traytel *)

section ‹Framework Instantiations using Marked Regular Expressions›

(*<*)
theory Position_Autos
imports
Automaton
begin
(*>*)

subsection ‹Marked Regular Expressions›

type_synonym 'a mrexp = "(bool * 'a) rexp"

abbreviation "strip ≡ map_rexp snd"

primrec mrexps :: "'a rexp ⇒ ('a mrexp) set" where
"mrexps Zero = {Zero}"
| "mrexps One = {One}"
| "mrexps (Atom a) = {Atom (True, a), Atom (False, a)}"
| "mrexps (Plus r s) = case_prod Plus ` (mrexps r × mrexps s)"
| "mrexps (Times r s) = case_prod Times ` (mrexps r × mrexps s)"
| "mrexps (Star r) = Star ` mrexps r"

lemma finite_mrexps[simp]: "finite (mrexps r)"
by (induction r) auto

lemma strip_mrexps: "strip ` mrexps r = {r}"
by (induction r) (auto simp: set_eq_subset subset_iff image_iff)

fun Lm :: "'a mrexp ⇒ 'a lang" where
"Lm Zero = {}" |
"Lm One = {}" |
"Lm (Atom(m,a)) = (if m then {[a]} else {})" |
"Lm (Plus r s) = Lm r ∪ Lm s" |
"Lm (Times r s) = Lm r @@ lang(strip s) ∪ Lm s" |
"Lm (Star r) = Lm r @@ star(lang(strip r))"

fun final :: "'a mrexp ⇒ bool" where
"final Zero = False" |
"final One = False" |
"final (Atom(m,a)) = m" |
"final (Plus r s) = (final r ∨ final s)" |
"final (Times r s) = (final s ∨ nullable s ∧ final r)" |
"final (Star r) = final r"

abbreviation read :: "'a ⇒ 'a mrexp ⇒ 'a mrexp" where
"read a ≡ map_rexp (λ(m,x). (m ∧ a=x, x))"

lemma read_mrexps[simp]: "r ∈ mrexps s ⟹ read a r ∈ mrexps s"
by (induction s arbitrary: a r) (auto simp: image_iff)

fun follow :: "bool ⇒ 'a mrexp ⇒ 'a mrexp" where
"follow m Zero = Zero" |
"follow m One = One" |
"follow m (Atom(_,a)) = Atom(m,a)" |
"follow m (Times r s) =
Times (follow m r) (follow (final r ∨ m ∧ nullable r) s)" |

lemma follow_mrexps[simp]: "r ∈ mrexps s ⟹ follow b r ∈ mrexps s"
by (induction s arbitrary: b r) (auto simp: image_iff)

lemma Nil_notin_Lm[simp]: "[] ∉ Lm r"
by (induction r) (auto split: if_splits)

lemma Nil_in_lang_strip[simp]: "[] ∈ lang(r) ⟷ [] ∈ lang(strip r)"
by (induction r) auto

lemma strip_follow[simp]: "strip(follow m r) = strip r"
by (induction r arbitrary: m) (auto split: if_splits)

lemma conc_lemma: "[] ∉ A ⟹ {w : A @@ B. w ≠ [] ∧ P(hd w)} = {w : A. w ≠ [] ∧ P(hd w)} @@ B"
unfolding conc_def by auto (metis hd_append2)+

lemma Lm_read: "Lm (read a r) = {w : Lm r. w ≠ [] ∧ hd w = a}"
proof (induction r)
case (Times r1 r2) thus ?case
using conc_lemma[OF Nil_notin_Lm, where P = "λx. x=a" and r1 = r1] by auto
next
case Star thus ?case using conc_lemma[OF Nil_notin_Lm, where P = "λx. x=a"] by simp
qed (auto split: if_splits)

lemma tl_conc[simp]: "[] ∉ A ⟹tl ` (A @@ B) = tl ` A @@ B"
by (fastforce simp: image_def Bex_def tl_append split: list.split)

lemma Nil_in_tl_Lm_if_final[simp]: "final r ⟹ [] : tl ` Lm r"
by (induction r) (auto simp: nullable_iff image_Un)

lemma Nil_notin_tl_if_not_final: "¬ final r ⟹ [] ∉ tl ` Lm r"
by (induction r) (auto simp: nullable_iff Nil_tl singleton_in_conc intro!: image_eqI[rotated])

lemma Lm_follow: "Lm (follow m r) = tl ` Lm r ∪ (if m then lang(strip r) else {}) - {[]}"
proof (induction r arbitrary: m)
case (Atom mb) thus ?case by (cases mb) auto
next
case (Times r s) thus ?case
by (simp add: Un_Diff image_Un conc_Un_distrib nullable_iff
conc_Diff_if_Nil1 Nil_notin_tl_if_not_final Un_ac)
next
case (Star r) thus ?case
conc_Diff_if_Nil1 Nil_notin_tl_if_not_final star_Diff_Nil_fold)
qed auto

subsection ‹Mark Before Atom›

text‹Position automaton where mark is placed before atoms.›

abbreviation "empty_mrexp ≡ map_rexp (λa. (False,a))"

lemma empty_mrexp_mrexps[simp]: "empty_mrexp r ∈ mrexps r"
by (induction r) auto

lemma nullable_empty_mrexp[simp]: "nullable (empty_mrexp r) = nullable r"
by (induct r) auto

definition "init_b r = (follow True (empty_mrexp r), nullable r)"

lemma init_b_mrexps[simp]: "init_b r ∈ mrexps r × UNIV"
unfolding init_b_def by auto

fun delta_b where
"delta_b a (r,b) = (let r' = read a r in (follow False r', final r'))"

lemma delta_b_mrexps[simp]: "rb ∈ mrexps r × UNIV ⟹ delta_b a rb ∈ mrexps r × UNIV"
by (auto simp: Let_def)

lemma fold_delta_b_init_b_mrexps[simp]: "fold delta_b w (init_b s) ∈ mrexps s × UNIV"
by (induction w arbitrary: s rule: rev_induct) auto

fun L_b where
"L_b (r,b) = Lm r ∪ (if b then {[]} else {})"

abbreviation "final_b ≡ snd"

lemma Lm_empty: "Lm (empty_mrexp r) = {}"
by (induction r) auto

by (induction r) (auto simp: nullable_iff concI_if_Nil2 singleton_in_conc split: if_splits)

global_interpretation before: rexp_DFA init_b delta_b final_b L_b
defines before_closure = before.closure
and check_eqv_b = before.check_eqv
and reachable_b = before.reachable
and automaton_b = before.automaton
and match_b = before.match
proof (standard, goal_cases)
case (1 r) show "L_b (init_b r) = lang r"
next
case (2 a rb) show "L_b (delta_b a rb) = Deriv a (L_b rb)"
next
case (3 rb) show  "final_b rb ⟷ [] ∈ L_b rb" by (cases rb) simp
next
case (4 s)
have "{fold delta_b w (init_b s) |w. True} ⊆ mrexps s × UNIV"
by (intro subsetI, elim CollectE exE) (simp only: fold_delta_b_init_b_mrexps)
then show "finite {fold delta_b w (init_b s) |w. True}" by (rule finite_subset) simp
qed

subsection ‹Mark After Atom›

text‹Position automaton where mark is placed after atoms. This is the

definition "init_a r = (True, empty_mrexp r)"

lemma init_a_mrexps[simp]: "init_a r ∈ UNIV × mrexps r"
unfolding init_a_def by auto

fun delta_a where

lemma delta_a_mrexps[simp]: "br ∈ UNIV × mrexps r ⟹ delta_a a br ∈ UNIV × mrexps r"
by auto

lemma fold_delta_a_init_a_mrexps[simp]: "fold delta_a w (init_a s) ∈ UNIV × mrexps s"
by (induction w arbitrary: s rule: rev_induct) auto

fun final_a where
"final_a (b,r) ⟷ final r ∨ b ∧ nullable r"

fun L_a where
"L_a (b,r) = Lm (follow b r) ∪ (if final_a(b,r)  then {[]} else {})"

lemma nonfinal_empty_mrexp: "¬ final (empty_mrexp r)"
by (induction r) auto

lemma Cons_eq_tl_iff[simp]: "x # xs = tl ys ⟷ (∃y. ys = y # x # xs)"
by (cases ys) auto

lemma tl_eq_Cons_iff[simp]: "tl ys = x # xs ⟷ (∃y. ys = y # x # xs)"
by (cases ys) auto

global_interpretation after: rexp_DFA init_a delta_a final_a L_a
defines after_closure = after.closure
and check_eqv_a = after.check_eqv
and reachable_a = after.reachable
and automaton_a = after.automaton
and match_a = after.match
proof (standard, goal_cases)
case (1 r) show "L_a (init_a r) = lang r"
by (auto simp: init_a_def nonfinal_empty_mrexp Lm_follow Lm_empty map_map_rexp nullable_iff)
next
case (2 a br) show "L_a (delta_a a br) = Deriv a (L_a br)"
fastforce simp: image_def neq_Nil_conv)
next
case (3 br) show  "final_a br ⟷ [] ∈ L_a br" by (cases br) simp
next
case (4 s)
have "{fold delta_a w (init_a s) |w. True} ⊆ UNIV × mrexps s"
by (intro subsetI, elim CollectE exE) (simp only: fold_delta_a_init_a_mrexps)
then show "finite {fold delta_a w (init_a s) |w. True}" by (rule finite_subset) simp
qed

text ‹
The ``before'' atomaton is a quotient of the ``after'' automaton.

The proof below follows an informal proof given by Helmut Seidl in personal communication.
›

fun hom_ab where
"hom_ab (b, r) = (follow b r, final_a (b, r))"

lemma hom_delta: "hom_ab (delta_a x br) = delta_b x (hom_ab br)"
by(cases br) (auto simp add: Let_def)

lemma hom_deltas: "hom_ab (fold delta_a w br) = fold delta_b w (hom_ab br)"
by (induct w arbitrary: br) (auto simp add: hom_delta)

lemma hom_init: "hom_ab (init_a r) = init_b r"
unfolding init_a_def init_b_def hom_ab.simps by (simp add: nonfinal_empty_mrexp)

lemma reachable_ab: "reachable_b as r = hom_ab ` reachable_a as r"
unfolding after.reachable before.reachable by (force simp: hom_init hom_deltas)

theorem card_reachable_ab: "card (reachable_b as r) ≤ card (reachable_a as r)"
unfolding reachable_ab using after.finite_reachable by (rule card_image_le)

text‹The implementation by Fischer et al.:›

(* better: shift b m r and move m b r *)
fun shift :: "bool ⇒ 'a mrexp ⇒ 'a ⇒ 'a mrexp" where
"shift _ One _ = One" |
"shift _ Zero _ = Zero" |
"shift m (Atom (_,x)) c = Atom (m ∧ (x=c),x)" |
"shift m (Plus r s) c = Plus (shift m r c) (shift m s c)" |
"shift m (Times r s) c =
Times (shift m r c) (shift (final r ∨ m ∧ nullable r) s c)" |
"shift m (Star r) c = Star (shift (final r ∨ m) r c)"

by (induction m r x rule: shift.induct) auto

text‹In the spirit of Asperti, and similarly quadratic because of need
to call final1 in move.›

fun final1 :: "'a mrexp ⇒ 'a ⇒ bool" where
"final1 Zero _ = False" |
"final1 One _ = False" |
"final1 (Atom(m,a)) x = (m ∧ a=x)" |
"final1 (Plus r s) x = (final1 r x ∨ final1 s x)" |
"final1 (Times r s) x = (final1 s x ∨ nullable s ∧ final1 r x)" |
"final1 (Star r) x = final1 r x"

fun move :: "'a ⇒ 'a mrexp ⇒ bool ⇒ 'a mrexp" where
"move _ One _ = One" |
"move _ Zero _ = Zero" |
"move c (Atom (_,a)) m = Atom (m, a)" |
"move c (Plus r s) m = Plus (move c r m) (move c s m)" |
"move c (Times r s) m =
Times (move c r m) (move c s (final1 r c ∨ m ∧ nullable r))" |
"move c (Star r) m = Star (move c r (final1 r c ∨ m))"