theory FSMInClass imports Main begin text{* We model deterministic finite automata (DFA) and prove the Pumping Lemma. We define a \textit{DFA} in Isabelle to be a record consisting of the set of states, the starting state, the set of final states, and the transition function $\delta$. The transition function says which state the DFA goes to given an input character (we're using natural numbers for characters here) and the current state. *} types state = nat record DFA = DFA_states :: "state set" ("Q") DFA_start :: state ("q\<^sub>0") DFA_finals :: "state set" ("F") DFA_delta :: "nat \ state \ state" ("\") text{* A DFA can be used to define a regular language: if the DFA accepts a string, then it is in the language, otherwise the string is not in the language. A DFA accepts a string if feeding the string into the DFA causes the DFA to transition to a final (i.e. accepting) state. *} types string = "nat list" lang = "string set" text{* The set consisting of the natural numbers up to n, called \textit{iota}, will be used in several places in the definitions and proofs. We collect some useful properties of \textit{iota} here. *} definition iota :: "nat \ nat set" where "iota n \ { i. i \ n }" definition good_DFA :: "DFA \ bool" where "good_DFA M \ finite (Q M) \ (Q M) = iota (card (Q M) - 1) \ (q\<^sub>0 M \ Q M) \ (F M \ Q M) \ (\ a. \ q \ Q M. \ M a q \ Q M)" text{* The $\Delta$ function is the extension of the transition function $\delta$ to strings. This define what it means to feed a string into a DFA. *} primrec ext_delta :: "DFA \ string \ state \ state" ("\") where "\ M [] = id" | "\ M (a#w) = (\ M w) \ (\ M a)" text{* We can now formally define the language of a DFA as the set of strings that take the DFA to a final state via the extended transition function. *} definition lang_of :: "DFA \ lang" where "lang_of M \ { w. \ M w (q\<^sub>0 M) \ F M }" primrec strpow :: "string \ nat \ string" ("_\<^bsup>_\<^esup>" [80,80] 80) where "w\<^bsup>0\<^esup> = w" | (* should be the empty string *) "w\<^bsup>Suc n\<^esup> = w @ w\<^bsup>n\<^esup>" text{* The Pigeon Hole Principle states that if you have have more pigeons than holes, then at least two pigeons will need to share the same hole. The following lemma formally states the principle. The set A represents the pigeons and B the holes. The function f places pigeons into holes. The cardinality (size) of set A is larger than the cardinality of set B. Another way to state the Pigeon Hole Principle is to say that if A is larger than B, then there is no injective function from A to B. The \texttt{Finite\_Set} theory in Isabelle's standard library includes many properties of finite sets and injective functions, including the property that if a function is injective, then it's domain and image are the same size. The Pigeon Hole Principle is a straightforward corollary. *} lemma pigeonhole: assumes fA: "finite A" and fB: "finite B" and cB: "card B < card A" and dr: "(\ x \ A. f x \ B)" shows "\ x y. x \ y \ x \ A \ y \ A \ f x = f y" proof - from dr have iAB: "fA \ B" by auto from fB iAB have "card (fA) \ card B" by (rule card_mono) from this cB have "card (f`A) \ card A" by arith from this fA have "\ inj_on f A" using inj_on_iff_eq_card by blast from this show ?thesis unfolding inj_on_def by blast qed text{* To apply the Pigeonhole Principle to the Pumping Lemma, we need to figure out what our sets A and B are, and the function f. Conceptually, we're going to take A to be the set of all prefixes of w that have length less-than or equal to n. The cardinality of this set is n + 1. The function f will then be the extended delta function. The set B will be the number of states, which is n. Thus, card(B) < card(A), as required for the Pigeonhole Principle. However, instead of working on the set of all prefixes of w, it is somewhat simpler to take A to be the set of the lengths of the prefixes of w. This is just the set $\{0,1,\ldots,n\}$. Then for the f function, we instead use the following function named steps, which maps from an integer k (length of prefix of w) to the state reached via the prefix of length k of w. *} definition steps :: "DFA \ string \ nat \ state" where "steps M w k = \ M (take k w) (q\<^sub>0 M)" section "Lemmas about iota" lemma iota_z: "iota 0 = {0}" by (simp add: iota_def) lemma iota_s: "iota (Suc n) = insert (Suc n) (iota n)" apply (simp add: iota_def) by auto lemma not_in_iota: "Suc n \ iota n" apply (induct n) by (auto simp add: iota_def) lemma iota_finite: "finite (iota n)" apply (induct n) by (auto simp add: iota_z iota_s) lemma card_iota: "card (iota n) = n + 1" apply (induct n) using not_in_iota iota_finite by (auto simp add: iota_z iota_s) subsection "Properties of the extended transition function" lemma ext_delta_append: "\ M (x@y) = (\ M y) \ (\ M x)" by (induct x, auto) lemma ext_delta_idempotent: "\ M p. good_DFA M \ p \ Q M \ p = \ M y p \ p = \ M (y\<^bsup>k\<^esup>) p" apply (induct k) using ext_delta_append by auto lemma ext_delta_good: "\ M q. good_DFA M \ q \ Q M \ \ M w q \ Q M" apply (induct w) by (auto simp add: good_DFA_def) subsection "Some properties of the take and drop string functions" lemma take_eq_take_app_drop_take: assumes ilj: "i < j" shows "take j w = (take i w) @ (drop i (take j w))" proof - from ilj have B: "take i (take j w) = take i w" by (simp add: min_def) have C: "(take i (take j w)) @ (drop i (take j w)) = take j w" by (simp only: append_take_drop_id) from B C show "take j w = take i w @ drop i (take j w)" by simp qed lemma w_equals_xyz: assumes ij: "i < j" and jw: "j \ length w" shows "w = (take i w) @ (drop i (take j w)) @ (drop j w)" proof - have A: "(take j w) @ (drop j w) = w" by simp obtain t where T: "t = take j w" by simp from A T have X: "t @ drop j w = w" by simp from ij have D: "take j w = take i w @ drop i (take j w)" by (rule take_eq_take_app_drop_take) from D T have D2: "t = take i w @ drop i (take j w)" by simp from X D2 show ?thesis by simp qed subsection "The Pumping Lemma" theorem pumping_regular: assumes g: "good_DFA M" shows "\ n. \ w. w \ lang_of M \ n \ length w \ (\ x y z. w = x @ y @ z \ y \ [] \ length (x @ y) \ n \ (\ k. x @ y\<^bsup>k\<^esup> @ z \ lang_of M))" proof - let ?n = "card (Q M)" { fix w assume wl: "w \ lang_of M" and nw: "?n \ length w" let ?A = "iota ?n" and ?B = "iota (?n - 1)" have fA: "finite ?A" using iota_finite by blast have fB: "finite ?B" using iota_finite by blast from g have C: "card ?B < card ?A" using card_iota good_DFA_def by auto from g have F: "\ x \ ?A. (steps M w) x \ ?B" using steps_def ext_delta_good good_DFA_def by auto from fA fB C F obtain i j where ij: "i \ j" and iA: "i \ ?A" and jA: "j \ ?A" and sij: "steps M w i = steps M w j" using pigeonhole by blast { fix i j assume ilj: "i < j" and iA: "i \ ?A" and jA: "j \ ?A" and sij: "steps M w i = steps M w j" obtain x y z where x: "x = take i w" and y: "y = drop i (take j w)" and z: "z = drop j w" by simp from jA nw have jlw: "j \ length w" by (simp add: iota_def) from ilj jlw x y z have w: "w = x@y@z" using w_equals_xyz by blast from jlw y ilj have ynil: "y \ []" by auto from jA nw x ilj y have lxyn: "length (x @ y) \ ?n" by (simp add: iota_def min_def) have "\ k. x @ y\<^bsup>k\<^esup> @ z \ lang_of M" proof (rule allI) fix k let ?p = "steps M w i" have pyp: "?p = \ M y ?p" proof - from sij have "?p = steps M w j" by simp also have "\ = \ M (take j w) (q\<^sub>0 M)" unfolding steps_def by fast also from x y ilj have "\ = \ M (x @ y) (q\<^sub>0 M)" using take_eq_take_app_drop_take[of i j w] by simp also have "\ = (\ M y \ \ M x) (q\<^sub>0 M)" using ext_delta_append by simp also from x have "\ = \ M y ?p" by (simp add: steps_def) finally show "?p = \ M y ?p" by blast qed from g have pq: "?p \ Q M" using ext_delta_good steps_def good_DFA_def by simp thm ext_delta_idempotent from g pq pyp have pykp: "?p = \ M (y\<^bsup>k\<^esup>) ?p" using ext_delta_idempotent by blast from x have xp: "?p = \ M x (q\<^sub>0 M)" by (simp add: steps_def) from w xp pyp pykp have "\ M w (q\<^sub>0 M) = \ M (x@y\<^bsup>k\<^esup>@z) (q\<^sub>0 M)" by (simp add: ext_delta_append o_assoc) from this wl show "x @ y\<^bsup>k\<^esup> @ z \ lang_of M" by (simp add: lang_of_def) qed from this w ynil lxyn have "(\ x y z. w = x @ y @ z \ y \ [] \ length (x @ y) \ ?n \ (\ k. x @ y\<^bsup>k\<^esup> @ z \ lang_of M))" by blast } from this ij iA jA sij have "(\ x y z. w = x @ y @ z \ y \ [] \ length (x @ y) \ ?n \ (\ k. x @ y\<^bsup>k\<^esup> @ z \ lang_of M))" apply (case_tac "i < j") apply force apply (case_tac "j < i") by auto } thus ?thesis by blast qed end