Theory LTS_Automata
section‹LTS-based Automata›
theory LTS_Automata
imports Labeled_Transition_System
begin
text‹An automaton ‹M› is a triple ‹(T, S, F)›, where ‹T› is the transition system,
‹S› is the start state and ‹F› are the final states.
This is just a thin layer on top of ‹lts›.
NB: ‹T› may be infinite (but we require to finiteness in crucial places).›
record ('s, 't) auto =
lts :: "('s, 't) lts"
start :: 's
finals :: "'s set"
text‹
The language ‹L(M)› of an automaton ‹M› is defined as the set of words that
reach at least one final state from the start state:
›
abbreviation accepts_auto :: "('s, 't) auto ⇒ 't list ⇒ bool" where
"accepts_auto M ≡ accepts_lts (lts M) (start M) (finals M)"
abbreviation Lang_auto :: "('s, 't) auto ⇒ 't list set" where
"Lang_auto M ≡ Lang_lts (lts M) (start M) (finals M)"
subsection ‹Sequential Composition of Automata›
text ‹We will later provide concrete example of automata accepting specific languages.
While proving that an automaton accepts a certain language often is straightforward,
proving that the automaton only accepts that language is a much more difficult task.
The lemma below provides a powerful tool to make these proofs manageable. It shows that
if two automata over disjoint state sets are connected via a single uni-directional bridge,
every word that reaches from the first set of states to a state within the second set of state must,
at some point, pass this bridge, and have a prefix within the first set of states
and a suffix within the second set.›
lemma auto_merge:
assumes "s⇩A ∈ A" and "f⇩A ∈ A" and "s⇩B ∈ B" and "f⇩B ∈ B" and "A ∩ B = {}"
and sideA: "∀(q,c,q') ∈ T⇩A. q ∈ A ∧ q' ∈ A"
and sideB: "∀(q,c,q') ∈ T⇩B. q ∈ B ∧ q' ∈ B"
and "f⇩B ∈ steps_lts (T⇩A ∪ {(f⇩A, c, s⇩B)} ∪ T⇩B) w s⇩A"
shows "∃w⇩A w⇩B. w = w⇩A@[c]@w⇩B ∧ f⇩A ∈ steps_lts T⇩A w⇩A s⇩A ∧ f⇩B ∈ steps_lts T⇩B w⇩B s⇩B"
using assms(1,8) proof (induction w arbitrary: s⇩A)
case Nil
then have "steps_lts (T⇩A ∪ {(f⇩A, c, s⇩B)} ∪ T⇩B) [] s⇩A = {s⇩A}"
by (simp add: Steps_lts_def)
then show ?case
using Nil.prems assms(4,5) by fast
next
case (Cons a w)
define T where "T ≡ T⇩A ∪ {(f⇩A, c, s⇩B)} ∪ T⇩B"
note ‹f⇩B ∈ steps_lts (T⇩A ∪ {(f⇩A, c, s⇩B)} ∪ T⇩B) (a#w) s⇩A›
then obtain q where a_step: "q ∈ steps_lts T [a] s⇩A"
and w_step: "f⇩B ∈ steps_lts T w q"
unfolding T_def using Steps_lts_split by force
then show ?case
proof (cases "(s⇩A, a, q) ∉ T⇩A")
case True
moreover have "(s⇩A, a, q) ∉ T⇩B"
using Cons.prems(1) assms(5,7) by fast
moreover have "(s⇩A, a, q) ∈ T"
using a_step by (auto simp: steps_lts_defs)
ultimately have "s⇩A = f⇩A" and "a = c" and "q = s⇩B"
unfolding T_def by simp+
have inB: "s⇩B ∈ B ⟹ f⇩B ∈ steps_lts T w s⇩B ⟹ f⇩B ∈ steps_lts T⇩B w s⇩B"
proof (induction w arbitrary: s⇩B)
case Nil
then show ?case
by (simp add: Steps_lts_def)
next
case (Cons x xs)
then obtain q where "f⇩B ∈ steps_lts T xs q" and "q ∈ steps_lts T [x] s⇩B"
using Steps_lts_split by force
then have "(s⇩B, x, q) ∈ T"
by (auto simp: steps_lts_defs)
moreover have "s⇩B ∈ B"
using Cons by simp
ultimately have "(s⇩B, x, q) ∈ T⇩B" and "q ∈ B"
unfolding T_def using assms(2,5,6,7) by blast+
then have "q ∈ steps_lts T⇩B [x] s⇩B"
by (auto simp: steps_lts_defs) force
moreover have "f⇩B ∈ steps_lts T⇩B xs q"
using ‹f⇩B ∈ steps_lts T xs q› ‹q ∈ B› Cons by simp
ultimately show ?case
using Steps_lts_join by force
qed
have "a#w = []@[c]@w"
by (simp add: ‹a = c›)
moreover have "f⇩A ∈ steps_lts T⇩A [] s⇩A"
by (simp add: ‹s⇩A = f⇩A› Steps_lts_def)
moreover have "f⇩B ∈ steps_lts T⇩B w s⇩B"
using w_step assms(3) inB by (simp add: ‹q = s⇩B›)
ultimately show ?thesis
by blast
next
case False
then have a_step': "q ∈ steps_lts T⇩A [a] s⇩A"
by (auto simp: steps_lts_defs) (force)
then have "q ∈ A"
using False Cons.prems(1) assms(6) by fast
then have "∃w⇩A w⇩B. w = w⇩A @[c]@w⇩B ∧ f⇩A ∈ steps_lts T⇩A w⇩A q ∧ f⇩B ∈ steps_lts T⇩B w⇩B s⇩B"
by (rule Cons.IH; use Cons.prems w_step[unfolded T_def] in simp)
then obtain w⇩A w⇩B where "w = w⇩A @[c]@w⇩B" and "f⇩A ∈ steps_lts T⇩A w⇩A q" and "f⇩B ∈ steps_lts T⇩B w⇩B s⇩B"
by blast
moreover then have "f⇩A ∈ steps_lts T⇩A (a#w⇩A) s⇩A"
using a_step' Steps_lts_join by force
ultimately have "a#w = a#w⇩A@[c]@w⇩B ∧ f⇩A ∈ steps_lts T⇩A (a#w⇩A) s⇩A ∧ f⇩B ∈ steps_lts T⇩B w⇩B s⇩B"
by simp
then show ?thesis
by (intro exI) auto
qed
qed
subsection‹Concrete Automata›
text ‹We now present three concrete automata that accept certain languages.›
subsubsection ‹Universe over specific Alphabet›
text‹This automaton accepts exactly the words that only contains letters from a given alphabet ‹Σ›.›
definition loop_lts :: "'s ⇒ 'a set ⇒ ('s × 'a × 's) set" where
"loop_lts q Σ ≡ {q} × Σ × {q}"
lemma loop_lts_fin: "finite Σ ⟹ finite (loop_lts q Σ)"
by (simp add: loop_lts_def)
lemma loop_lts_correct1: "set w ⊆ Σ ⟹ steps_lts (loop_lts q Σ) w q = {q}"
proof (induction w)
case Nil
then show ?case
by (simp add: Steps_lts_def)
next
case (Cons w ws)
then have "steps_lts (loop_lts q Σ) [w] q = {q}"
unfolding loop_lts_def steps_lts_defs by fastforce
moreover have "steps_lts (loop_lts q Σ) ws q = {q}"
using Cons by simp
ultimately show ?case
by (simp add: Steps_lts_def)
qed
lemma loop_lts_correct2: "¬ set w ⊆ Σ ⟹ steps_lts (loop_lts q Σ) w q = {}"
proof (induction w)
case Nil
then show ?case
by simp
next
case (Cons w ws)
then consider "w ∉ Σ" | "¬ set ws ⊆ Σ"
by auto
then show ?case
proof (cases)
case 1
then have "steps_lts (loop_lts q Σ) [w] q = {}"
by (auto simp: loop_lts_def steps_lts_defs)
moreover have "Steps_lts (loop_lts q Σ) ws {} = {}"
by (meson Steps_lts_path ex_in_conv)
ultimately show ?thesis
by (metis Steps_lts_split all_not_in_conv append_Cons append_Nil)
next
case 2
then have "steps_lts (loop_lts q Σ) ws q = {}"
using Cons by simp
moreover have "steps_lts (loop_lts q Σ) [w] q ⊆ {q}"
by (auto simp: loop_lts_def steps_lts_defs)
ultimately show ?thesis
by (metis Steps_lts_def Steps_lts_mono Un_insert_right ex_in_conv fold_simps(1,2) insert_absorb insert_not_empty sup.absorb_iff1)
qed
qed
lemmas loop_lts_correct = loop_lts_correct1 loop_lts_correct2
definition auto_univ :: "'a set ⇒ (unit, 'a) auto" where
"auto_univ Σ ≡ ⦇
lts = loop_lts () Σ,
start = (),
finals = {()}
⦈"
lemma auto_univ_lang[simp]: "Lang_auto (auto_univ Σ) = {w. set w ⊆ Σ}"
proof -
define T where "T ≡ loop_lts () Σ"
have "⋀w. set w ⊆ Σ ⟷ () ∈ steps_lts T w ()"
unfolding T_def using loop_lts_correct by fast
then show ?thesis
by (auto simp: T_def auto_univ_def)
qed
subsubsection‹Fixed Character with Arbitrary Prefix/Suffix›
text‹
This automaton accepts exactly those words that contain a specific letter ‹c› at some point,
and whose prefix and suffix are contained within the alphabets ‹Σp› and ‹Σs›.
›
definition pcs_lts :: "'a set ⇒ 'a ⇒ 'a set ⇒ (nat × 'a × nat) set" where
"pcs_lts Σp c Σs ≡ loop_lts 0 Σp ∪ {(0, c, 1)} ∪ loop_lts 1 Σs"
lemma pcs_lts_fin: "finite Σp ⟹ finite Σs ⟹ finite (pcs_lts Σp c Σs)"
by (auto intro: loop_lts_fin simp: pcs_lts_def)
lemma pcs_lts_correct1:
"(∃p s. w = p@[c]@s ∧ set p ⊆ Σp ∧ set s ⊆ Σs) ⟹ 1 ∈ steps_lts (pcs_lts Σp c Σs) w 0"
proof -
assume "∃p s. w = p@[c]@s ∧ set p ⊆ Σp ∧ set s ⊆ Σs"
then obtain p s where "w = p@[c]@s" and "set p ⊆ Σp" and "set s ⊆ Σs"
by blast
moreover hence "0 ∈ steps_lts (pcs_lts Σp c Σs) p 0"
by (metis pcs_lts_def steps_lts_union loop_lts_correct1 singletonI)
moreover have "1 ∈ steps_lts (pcs_lts Σp c Σs) [c] 0"
unfolding pcs_lts_def steps_lts_defs by force
moreover have "1 ∈ steps_lts (pcs_lts Σp c Σs) s 1"
by (metis calculation(3) inf_sup_ord(3) insertI1 pcs_lts_def steps_lts_mono' loop_lts_correct1 sup_commute)
ultimately show "1 ∈ steps_lts (pcs_lts Σp c Σs) w 0"
using Steps_lts_join by meson
qed
lemma pcs_lts_correct2:
assumes "1 ∈ steps_lts (pcs_lts Σp c Σs) w 0"
shows "∃p s. w = p@[c]@s ∧ set p ⊆ Σp ∧ set s ⊆ Σs"
proof -
define T⇩A where [simp]: "T⇩A ≡ loop_lts (0::nat) Σp"
define T⇩B where [simp]: "T⇩B ≡ loop_lts (1::nat) Σs"
have "1 ∈ steps_lts (T⇩A ∪ {(0, c, 1)} ∪ T⇩B) w 0"
using assms by (simp add: pcs_lts_def)
then have "∃w⇩A w⇩B. w = w⇩A@[c]@w⇩B ∧ 0 ∈ steps_lts T⇩A w⇩A 0 ∧ 1 ∈ steps_lts T⇩B w⇩B 1"
by (intro auto_merge[where A="{0}" and B="{1}"]) (simp add: loop_lts_def)+
then obtain w⇩A w⇩B where w_split: "w = w⇩A@[c]@w⇩B" and "0 ∈ steps_lts T⇩A w⇩A 0" and "1 ∈ steps_lts T⇩B w⇩B 1"
by blast
then have "set w⇩A ⊆ Σp" and "set w⇩B ⊆ Σs"
using loop_lts_correct2 by fastforce+
then show ?thesis
using w_split by blast
qed
lemmas pcs_lts_correct = pcs_lts_correct1 pcs_lts_correct2
definition cps_auto :: "'a ⇒ 'a set ⇒ (nat, 'a) auto" where
"cps_auto c Σ ≡ ⦇
lts = pcs_lts Σ c Σ,
start = 0,
finals = {1}
⦈"
lemma cps_auto_lang: "Lang_auto (cps_auto c U) = { α@[c]@β | α β. set α ⊆ U ∧ set β ⊆ U }"
using pcs_lts_correct unfolding cps_auto_def
by (metis (lifting) disjoint_insert(2) inf_bot_right select_convs(1,2,3))
subsubsection‹Singleton Language›
text‹
Last but not least, the automaton accepting exactly a single word can be inductively defined.
›
lemma steps_lts_empty_lts: "w ≠ [] ⟹ steps_lts {} w q⇩0 = {}"
proof (induction w)
case Nil
then show ?case
by simp
next
case (Cons w ws)
moreover have "Steps_lts {} [w] {q⇩0} = {}"
by (simp add: steps_lts_defs)
moreover have "Steps_lts {} ws {} = {}"
using Steps_lts_noState by fast
ultimately show ?case
by (simp add: Steps_lts_def)
qed
fun word_lts :: "'a list ⇒ (nat × 'a × nat) set" where
"word_lts (w#ws) = word_lts ws ∪ {(Suc (length ws), w, length ws)}" |
"word_lts [] = {}"
lemma word_lts_domain:
"(q, c, q') ∈ word_lts ws ⟹ q ≤ length ws ∧ q' ≤ length ws"
by (induction ws) auto
definition word_auto :: "'a list ⇒ (nat, 'a) auto" where
"word_auto ws ≡ ⦇ lts = word_lts ws, start = length ws, finals = {0} ⦈"
lemma word_lts_correct1:
"0 ∈ steps_lts (word_lts ws) ws (length ws)"
proof (induction ws)
case Nil
then show ?case
by (simp add: Steps_lts_def)
next
case (Cons w ws)
have "0 ∈ steps_lts (word_lts ws) ws (length ws)"
using Cons.IH(1) by blast
then have "0 ∈ steps_lts (word_lts (w#ws)) ws (length ws)"
using steps_lts_mono' by (metis word_lts.simps(1) sup_ge1)
moreover have "length ws ∈ steps_lts (word_lts (w#ws)) [w] (Suc (length ws))"
proof -
have "(Suc (length ws), w, length ws) ∈ word_lts (w#ws)"
by simp
then show ?thesis
unfolding steps_lts_defs by force
qed
ultimately show ?case
using Steps_lts_join by force
qed
lemma word_lts_correct2:
"0 ∈ steps_lts (word_lts ws) ws' (length ws) ⟹ ws = ws'"
proof (induction ws arbitrary: ws')
case Nil
then show ?case
by (simp, metis equals0D steps_lts_empty_lts)
next
case (Cons w ws)
define T⇩B where [simp]: "T⇩B ≡ word_lts ws"
define B where [simp]: "B ≡ {n. n ≤ length ws}"
define T where [simp]: "T ≡ {} ∪ {(Suc (length ws), w, length ws)} ∪ T⇩B"
have "0 ∈ steps_lts T ws' (length (w#ws))"
using Cons.prems by simp
moreover have "∀(q, c, q')∈T⇩B. q ∈ B ∧ q' ∈ B"
using word_lts_domain by force
ultimately have "∃w⇩A w⇩B. ws' = w⇩A@[w]@w⇩B ∧ (Suc (length ws)) ∈ steps_lts {} w⇩A (Suc (length ws)) ∧ 0 ∈ steps_lts T⇩B w⇩B (length ws)"
by (intro auto_merge[where A="{Suc (length ws)}" and B=B]) simp+
then obtain w⇩A w⇩B where ws'_split: "ws' = w⇩A@[w]@w⇩B"
and w⇩A_step: "(length (w#ws)) ∈ steps_lts {} w⇩A (length (w#ws))"
and w⇩B_step: "0 ∈ steps_lts T⇩B w⇩B (length ws)"
by force
have "w⇩A = []"
using w⇩A_step steps_lts_empty_lts by fast
have "ws = w⇩B"
by (intro Cons.IH, use w⇩B_step in simp)
then show ?case
using ws'_split by (simp add: ‹w⇩A = []› ‹ws = w⇩B›)
qed
lemmas word_lts_correct = word_lts_correct1 word_lts_correct2
lemma word_auto_lang[simp]: "Lang_auto (word_auto w) = {w}"
unfolding word_auto_def using word_lts_correct[of w] by auto
lemma word_auto_finite_lts: "finite (lts (word_auto w))"
proof -
have "finite (word_lts w)"
by (induction w) simp+
then show ?thesis
by (simp add: word_auto_def)
qed
hide_const (open) lts start finals
term auto.start
end