progs/Matcher2.thy
author Christian Urban <christian.urban@kcl.ac.uk>
Fri, 29 Nov 2024 18:59:32 +0000
changeset 976 e9eac62928f5
parent 972 ebb4a40d9bae
permissions -rw-r--r--
updated

theory Matcher2
  imports "Main" 
begin

lemma Suc_Union:
  "(\<Union> x\<le>Suc m. B x) = (B (Suc m) \<union> (\<Union> x\<le>m. B x))"
by (metis UN_insert atMost_Suc)

lemma Suc_reduce_Union:
  "(\<Union>x\<in>{Suc n..Suc m}. B x) = (\<Union>x\<in>{n..m}. B (Suc x))"
by (metis UN_extend_simps(10) image_Suc_atLeastAtMost)


section \<open>Regular Expressions\<close>

datatype rexp =
  NULL
| EMPTY
| CH char
| SEQ rexp rexp
| ALT rexp rexp
| STAR rexp
| NOT rexp
| PLUS rexp
| OPT rexp
| NTIMES rexp nat
| NMTIMES rexp nat nat
| UPNTIMES rexp nat


section \<open>Sequential Composition of Sets\<close>

definition
  Seq :: "string set \<Rightarrow> string set \<Rightarrow> string set" ("_ ;; _" [100,100] 100)
where 
  "A ;; B = {s1 @ s2 | s1 s2. s1 \<in> A \<and> s2 \<in> B}"

text \<open>Two Simple Properties about Sequential Composition\<close>

lemma seq_empty [simp]:
  shows "A ;; {[]} = A"
  and   "{[]} ;; A = A"
by (simp_all add: Seq_def)

lemma seq_null [simp]:
  shows "A ;; {} = {}"
  and   "{} ;; A = {}"
by (simp_all add: Seq_def)

lemma seq_union:
  shows "A ;; (B \<union> C) = A ;; B \<union> A ;; C"
  and   "(B \<union> C) ;; A = B ;; A \<union> C ;; A"
by (auto simp add: Seq_def)

lemma seq_Union:
  shows "A ;; (\<Union>x\<in>B. C x) = (\<Union>x\<in>B. A ;; C x)"
by (auto simp add: Seq_def)

lemma seq_empty_in [simp]:
  "[] \<in> A ;; B \<longleftrightarrow> ([] \<in> A \<and> [] \<in> B)"
by (simp add: Seq_def)

lemma seq_assoc: 
  shows "A ;; (B ;; C) = (A ;; B) ;; C" 
apply(auto simp add: Seq_def)
apply(metis append_assoc)
apply(metis)
done


section \<open>Power for Sets\<close>

fun 
  pow :: "string set \<Rightarrow> nat \<Rightarrow> string set" ("_ \<up> _" [101, 102] 101)
where
   "A \<up> 0 = {[]}"
|  "A \<up> (Suc n) = A ;; (A \<up> n)"

lemma pow_empty [simp]:
  shows "[] \<in> A \<up> n \<longleftrightarrow> (n = 0 \<or> [] \<in> A)"
by (induct n) (auto)

lemma pow_plus:
  "A \<up> (n + m) = A \<up> n ;; A \<up> m"
by (induct n) (simp_all add: seq_assoc)

section \<open>Kleene Star for Sets\<close>

inductive_set
  Star :: "string set \<Rightarrow> string set" ("_\<star>" [101] 102)
  for A :: "string set"
where
  start[intro]: "[] \<in> A\<star>"
| step[intro]:  "\<lbrakk>s1 \<in> A; s2 \<in> A\<star>\<rbrakk> \<Longrightarrow> s1 @ s2 \<in> A\<star>"

text \<open>A Standard Property of Star\<close>

lemma star_decomp: 
  assumes a: "c # x \<in> A\<star>" 
  shows "\<exists>a b. x = a @ b \<and> c # a \<in> A \<and> b \<in> A\<star>"
using a 
using a
by (induct x\<equiv>"c # x" rule: Star.induct) 
   (auto simp add: append_eq_Cons_conv)

lemma star_cases:
  shows "A\<star> = {[]} \<union> A ;; A\<star>"
unfolding Seq_def 
by (auto) (metis Star.simps)

lemma Star_in_Pow:
  assumes a: "s \<in> A\<star>"
  shows "\<exists>n. s \<in> A \<up> n"
using a
apply(induct)
apply(auto)
apply(rule_tac x="Suc n" in exI)
apply(auto simp add: Seq_def)
done

lemma Pow_in_Star:
  assumes a: "s \<in> A \<up> n"
  shows "s \<in> A\<star>"
using a
by (induct n arbitrary: s) (auto simp add: Seq_def)


lemma Star_def2: 
  shows "A\<star> = (\<Union>n. A \<up> n)"
using Star_in_Pow Pow_in_Star
by (auto)


section \<open>Semantics of Regular Expressions\<close>
 
fun
  L :: "rexp \<Rightarrow> string set"
where
  "L (NULL) = {}"
| "L (EMPTY) = {[]}"
| "L (CH c) = {[c]}"
| "L (SEQ r1 r2) = (L r1) ;; (L r2)"
| "L (ALT r1 r2) = (L r1) \<union> (L r2)"
| "L (STAR r) = (L r)\<star>"
| "L (NOT r) = UNIV - (L r)"
| "L (PLUS r) = (L r) ;; ((L r)\<star>)"
| "L (OPT r) = (L r) \<union> {[]}"
| "L (NTIMES r n) = (L r) \<up> n"
| "L (NMTIMES r n m) = (\<Union>i\<in> {n..m} . ((L r) \<up> i))" 
| "L (UPNTIMES r n) = (\<Union>i\<in> {..n} . ((L r) \<up> i))"

lemma "L (NOT NULL) = UNIV"
apply(simp)
done

section \<open>The Matcher\<close>

fun
 nullable :: "rexp \<Rightarrow> bool"
where
  "nullable (NULL) = False"
| "nullable (EMPTY) = True"
| "nullable (CH c) = False"
| "nullable (ALT r1 r2) = (nullable r1 \<or> nullable r2)"
| "nullable (SEQ r1 r2) = (nullable r1 \<and> nullable r2)"
| "nullable (STAR r) = True"
| "nullable (NOT r) = (\<not>(nullable r))"
| "nullable (PLUS r) = (nullable r)"
| "nullable (OPT r) = True"
| "nullable (NTIMES r n) = (if n = 0 then True else nullable r)"
| "nullable (NMTIMES r n m) = (if m < n then False else (if n = 0 then True else nullable r))"
| "nullable (UPNTIMES r n) = True"

fun M :: "rexp \<Rightarrow> nat"
where
  "M (NULL) = 0"
| "M (EMPTY) = 0"
| "M (CH char) = 0"
| "M (SEQ r1 r2) = Suc ((M r1) + (M r2))"
| "M (ALT r1 r2) = Suc ((M r1) + (M r2))"
| "M (STAR r) = Suc (M r)"
| "M (NOT r) = Suc (M r)"
| "M (PLUS r) = Suc (M r)"
| "M (OPT r) = Suc (M r)"
| "M (NTIMES r n) = Suc (M r) * 2 * (Suc n)"
| "M (NMTIMES r n m) = Suc (Suc (M r)) * 2 * (Suc m) * (Suc (Suc m) - Suc n)"
| "M (UPNTIMES r n) = Suc (M r) * 2 * (Suc n)"

function der :: "char \<Rightarrow> rexp \<Rightarrow> rexp"
where
  "der c (NULL) = NULL"
| "der c (EMPTY) = NULL"
| "der c (CH d) = (if c = d then EMPTY else NULL)"
| "der c (ALT r1 r2) = ALT (der c r1) (der c r2)"
| "der c (SEQ r1 r2) = ALT (SEQ (der c r1) r2) (if nullable r1 then der c r2 else NULL)"
| "der c (STAR r) = SEQ (der c r) (STAR r)"
| "der c (NOT r) = NOT(der c r)"
| "der c (PLUS r) = SEQ (der c r) (STAR r)"
| "der c (OPT r) = der c r"
| "der c (NTIMES r 0) = NULL"
| "der c (NTIMES r (Suc n)) = der c (SEQ r (NTIMES r n))"
| "der c (NMTIMES r n m) = 
        (if m < n then NULL else 
        (if n = m then der c (NTIMES r n) else
                       ALT (der c (NTIMES r n)) (der c (NMTIMES r (Suc n) m))))"
| "der c (UPNTIMES r 0) = NULL"
| "der c (UPNTIMES r (Suc n)) = der c (ALT (NTIMES r (Suc n)) (UPNTIMES r n))"
by pat_completeness auto

lemma bigger1:
  "\<lbrakk>c < (d::nat); a < b; 0 < a; 0 < c\<rbrakk> \<Longrightarrow> c * a < d * b"
by (metis le0 mult_strict_mono')

termination der 
apply(relation "measure (\<lambda>(c, r). M r)") 
apply(simp)
apply(simp)
apply(simp)
apply(simp)
apply(simp)
apply(simp)
apply(simp)
apply(simp)
apply(simp)
apply(simp)
apply(simp)
apply(simp_all del: M.simps)
apply(simp_all only: M.simps)
defer
defer
defer
apply(subgoal_tac "Suc (Suc m) - Suc (Suc n) < Suc (Suc m) - Suc n")
prefer 2
     apply(auto)[1]

(*
apply (metis Suc_mult_less_cancel1 mult.assoc numeral_eq_Suc)
apply(subgoal_tac "0 < (Suc (Suc m) - Suc n)")
prefer 2
apply(auto)[1]
apply(subgoal_tac "Suc n < Suc m")
prefer 2
apply(auto)[1]
apply(subgoal_tac "Suc (M r) * 2 * Suc n < Suc (Suc (M r)) * 2 * Suc m")
prefer 2
apply(subgoal_tac "Suc (M r) * 2 < Suc (Suc (M r)) * 2")
prefer 2
apply(auto)[1]
apply(rule bigger1)
apply(assumption)
apply(simp)
apply (metis zero_less_Suc)
apply (metis mult_is_0 neq0_conv old.nat.distinct(2))
apply(rotate_tac 4)
apply(drule_tac a="1" and b="(Suc (Suc m) - Suc n)" in bigger1)
prefer 4
apply(simp)
apply(simp)
apply (metis zero_less_one)
apply(simp)
done
*)
sorry

fun 
 ders :: "string \<Rightarrow> rexp \<Rightarrow> rexp"
where
  "ders [] r = r"
| "ders (c # s) r = ders s (der c r)"

fun
  matcher :: "rexp \<Rightarrow> string \<Rightarrow> bool"
where
  "matcher r s = nullable (ders s r)"


section \<open>Correctness Proof of the Matcher\<close>

lemma nullable_correctness:
  shows "nullable r  \<longleftrightarrow> [] \<in> (L r)"
apply(induct r) 
apply(auto simp add: Seq_def) 
done

section \<open>Left-Quotient of a Set\<close>

definition
  Der :: "char \<Rightarrow> string set \<Rightarrow> string set"
where
  "Der c A \<equiv> {s. [c] @ s \<in> A}"

lemma Der_null [simp]:
  shows "Der c {} = {}"
unfolding Der_def
by auto

lemma Der_empty [simp]:
  shows "Der c {[]} = {}"
unfolding Der_def
by auto

lemma Der_char [simp]:
  shows "Der c {[d]} = (if c = d then {[]} else {})"
unfolding Der_def
by auto

lemma Der_union [simp]:
  shows "Der c (A \<union> B) = Der c A \<union> Der c B"
unfolding Der_def
by auto

lemma Der_insert_nil [simp]:
  shows "Der c (insert [] A) = Der c A"
unfolding Der_def 
by auto 

lemma Der_seq [simp]:
  shows "Der c (A ;; B) = (Der c A) ;; B \<union> (if [] \<in> A then Der c B else {})"
unfolding Der_def Seq_def
by (auto simp add: Cons_eq_append_conv)

lemma Der_star [simp]:
  shows "Der c (A\<star>) = (Der c A) ;; A\<star>"
proof -    
  have "Der c (A\<star>) = Der c ({[]} \<union> A ;; A\<star>)"
    by (simp only: star_cases[symmetric])
  also have "... = Der c (A ;; A\<star>)"
    by (simp only: Der_union Der_empty) (simp)
  also have "... = (Der c A) ;; A\<star> \<union> (if [] \<in> A then Der c (A\<star>) else {})"
    by simp
  also have "... =  (Der c A) ;; A\<star>"
    unfolding Seq_def Der_def
    by (auto dest: star_decomp)
  finally show "Der c (A\<star>) = (Der c A) ;; A\<star>" .
qed

lemma test:
  assumes "[] \<in> A"
  shows "Der c (A \<up> n) \<subseteq> (Der c A) ;; (A \<up> n)"
  using assms
  apply(induct n)
   apply(simp)
  apply(simp)
  apply(auto simp add: Der_def Seq_def)
  apply blast
  by force

lemma Der_ntimes [simp]:
  shows "Der c (A  \<up> (Suc n)) = (Der c A) ;; (A \<up> n)"
proof -    
  have "Der c (A  \<up> (Suc n)) = Der c (A ;; A \<up> n)"
    by(simp)
  also have "... = (Der c A) ;; (A \<up> n) \<union> (if [] \<in> A then Der c (A \<up> n) else {})"
    by simp
  also have "... =  (Der c A) ;; (A \<up> n)"
    using test by force
  finally show "Der c (A  \<up> (Suc n)) = (Der c A) ;; (A \<up> n)" .
qed



lemma Der_UNIV [simp]:
  "Der c (UNIV - A) = UNIV - Der c A"
unfolding Der_def
by (auto)

lemma Der_pow [simp]:
  shows "Der c (A \<up> (Suc n)) = (Der c A) ;; (A \<up> n) \<union> (if [] \<in> A then Der c (A \<up> n) else {})"
unfolding Der_def 
by(auto simp add: Cons_eq_append_conv Seq_def)

lemma Der_UNION [simp]: 
  shows "Der c (\<Union>x\<in>A. B x) = (\<Union>x\<in>A. Der c (B x))"
  by (auto simp add: Der_def)

lemma if_f:
  shows "f(if B then C else D) = (if B then f(C) else f(D))"
  by simp


lemma der_correctness:
  shows "L (der c r) = Der c (L r)"
proof(induct r)
  case NULL
  then show ?case by simp
next
  case EMPTY
  then show ?case by simp
next
  case (CH x)
  then show ?case by simp
next
  case (SEQ r1 r2)
  then show ?case
    by (simp add: nullable_correctness) 
next
  case (ALT r1 r2)
  then show ?case by simp
next
  case (STAR r)
  then show ?case
    by simp 
next
  case (NOT r)
  then show ?case by simp
next
  case (PLUS r)
  then show ?case by simp
next
  case (OPT r)
  then show ?case by simp
next
  case (NTIMES r n)
  then show ?case
    apply(induct n)
     apply(simp)
    apply(simp only: L.simps)
    apply(simp only: Der_pow)
    apply(simp only: der.simps L.simps)
    apply(simp only: nullable_correctness)
    apply(simp only: if_f)
    by simp
next
  case (NMTIMES r n m)
  then show ?case 
    apply(case_tac n)
    sorry
next
  case (UPNTIMES r x2)
  then show ?case sorry
qed




lemma der_correctness:
  shows "L (der c r) = Der c (L r)"
apply(induct rule: der.induct) 
apply(simp_all add: nullable_correctness 
    Suc_Union Suc_reduce_Union seq_Union atLeast0AtMost)
apply(rule impI)+
apply(subgoal_tac "{n..m} = {n} \<union> {Suc n..m}")
apply(auto simp add: Seq_def)
done

lemma L_der_NTIMES:
  shows "L(der c (NTIMES r n)) = L (if n = 0 then NULL else if nullable r then 
         SEQ (der c r) (UPNTIMES r (n - 1)) else SEQ (der c r) (NTIMES r (n - 1)))"
apply(induct n)
apply(simp)
apply(simp)
apply(auto)
apply(auto simp add: Seq_def)
apply(rule_tac x="s1" in exI)
apply(simp)
apply(rule_tac x="xa" in bexI)
apply(simp)
apply(simp)
apply(rule_tac x="s1" in exI)
apply(simp)
by (metis Suc_pred atMost_iff le_Suc_eq)

lemma "L(der c (UPNTIMES r 0)) = {}"
by simp

lemma "L(der c (UPNTIMES r (Suc n))) = L(SEQ (der c r) (UPNTIMES r n))"
proof(induct n)
  case 0 show ?case by simp
next
  case (Suc n)
  have IH: "L (der c (UPNTIMES r (Suc n))) = L (SEQ (der c r) (UPNTIMES r n))" by fact
  { assume a: "nullable r"
    have "L (der c (UPNTIMES r (Suc (Suc n)))) = Der c (L (UPNTIMES r (Suc (Suc n))))"
    by (simp only: der_correctness)
    also have "... = Der c (L (ALT (NTIMES r (Suc (Suc n))) (UPNTIMES r (Suc n))))"
    by(simp only: L.simps Suc_Union)
    also have "... = L (der c (ALT (NTIMES r (Suc (Suc n))) (UPNTIMES r (Suc n))))"
    by (simp only: der_correctness)
    also have "... = L (der c (NTIMES r (Suc (Suc n)))) \<union> L (der c (UPNTIMES r (Suc n)))"
    by(auto simp add: Seq_def)
    also have "... = L (der c (NTIMES r (Suc (Suc n)))) \<union> L (SEQ (der c r) (UPNTIMES r n))"
    using IH by simp
    also have "... = L (SEQ (der c r) (UPNTIMES r (Suc n))) \<union> L (SEQ (der c r) (UPNTIMES r n))"
    using a unfolding L_der_NTIMES by simp
    also have "... =  L (SEQ (der c r) (UPNTIMES r (Suc n)))"
    by (auto, metis Suc_Union Un_iff seq_Union)
    finally have "L (der c (UPNTIMES r (Suc (Suc n)))) = L (SEQ (der c r) (UPNTIMES r (Suc n)))" .
    } 
  moreover
  { assume a: "\<not>nullable r"
    have "L (der c (UPNTIMES r (Suc (Suc n)))) = Der c (L (UPNTIMES r (Suc (Suc n))))"
    by (simp only: der_correctness)
    also have "... = Der c (L (ALT (NTIMES r (Suc (Suc n))) (UPNTIMES r (Suc n))))"
    by(simp only: L.simps Suc_Union)
    also have "... = L (der c (ALT (NTIMES r (Suc (Suc n))) (UPNTIMES r (Suc n))))"
    by (simp only: der_correctness)
    also have "... = L (der c (NTIMES r (Suc (Suc n)))) \<union> L (der c (UPNTIMES r (Suc n)))"
    by(auto simp add: Seq_def)
    also have "... = L (der c (NTIMES r (Suc (Suc n)))) \<union> L (SEQ (der c r) (UPNTIMES r n))"
    using IH by simp
    also have "... = L (SEQ (der c r) (NTIMES r (Suc n))) \<union> L (SEQ (der c r) (UPNTIMES r n))"
    using a unfolding L_der_NTIMES by simp
    also have "... =  L (SEQ (der c r) (UPNTIMES r (Suc n)))"
    by (simp add: Suc_Union seq_union(1))
    finally have "L (der c (UPNTIMES r (Suc (Suc n)))) = L (SEQ (der c r) (UPNTIMES r (Suc n)))" .
  }
  ultimately  
  show "L (der c (UPNTIMES r (Suc (Suc n)))) = L (SEQ (der c r) (UPNTIMES r (Suc n)))"
  by blast
qed

lemma matcher_correctness:
  shows "matcher r s \<longleftrightarrow> s \<in> L r"
by (induct s arbitrary: r)
   (simp_all add: nullable_correctness der_correctness Der_def)

end