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: "f`A \ B" by auto
from fB iAB have "card (f`A) \ 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