Theory LexicalVals3

theory LexicalVals3
  imports Lexer3 "HOL-Library.Sublist"
begin

section ‹ Sets of Lexical Values ›

text ‹
  Shows that lexical values are finite for a given regex and string.
›

definition
  LV :: "'a rexp  'a list  ('a val) set"
where  "LV r s  {v.  v : r  flat v = s}"

lemma LV_simps:
  shows "LV Zero s = {}"
  and   "LV One s = (if s = [] then {Void} else {})"
  and   "LV (Atom c) s = (if s = [c] then {Atm c} else {})"
  and   "LV (Plus r1 r2) s = Left ` LV r1 s  Right ` LV r2 s"
  and   "LV (NTimes r 0) s = (if s = [] then {Stars []} else {})"
  and   "LV (Rec l r) s = {Recv l v | v. v  LV r s}"
  and   "LV (Charset cs) s = (if length s = 1  (hd s)  cs then {Atm (hd s)} else {})"
unfolding LV_def
  apply(auto intro: Prf.intros elim: Prf.cases)
  apply(simp add: Prf_NTimes_empty)
  by (metis Suc_length_conv length_0_conv list.sel(1))  

abbreviation
  "Prefixes s  {s'. prefix s' s}"

abbreviation
  "Suffixes s  {s'. suffix s' s}"

abbreviation
  "SSuffixes s  {s'. strict_suffix s' s}"

lemma Suffixes_cons [simp]:
  shows "Suffixes (c # s) = Suffixes s  {c # s}"
by (auto simp add: suffix_def Cons_eq_append_conv)


lemma finite_Suffixes: 
  shows "finite (Suffixes s)"
by (induct s) (simp_all)

lemma finite_SSuffixes: 
  shows "finite (SSuffixes s)"
proof -
  have "SSuffixes s  Suffixes s"
   unfolding strict_suffix_def suffix_def by auto
  then show "finite (SSuffixes s)"
   using finite_Suffixes finite_subset by blast
qed

lemma finite_Prefixes: 
  shows "finite (Prefixes s)"
proof -
  have "finite (Suffixes (rev s))" 
    by (rule finite_Suffixes)
  then have "finite (rev ` Suffixes (rev s))" by simp
  moreover
  have "rev ` (Suffixes (rev s)) = Prefixes s"
  unfolding suffix_def prefix_def image_def
   by (auto)(metis rev_append rev_rev_ident)+
  ultimately show "finite (Prefixes s)" by simp
qed

lemma LV_STAR_finite:
  assumes "s. finite (LV r s)"
  shows "finite (LV (Star r) s)"
proof(induct s rule: length_induct)
  fix s::"'a list"
  assume "s'. length s' < length s  finite (LV (Star r) s')"
  then have IH: "s'  SSuffixes s. finite (LV (Star r) s')"
    by (force simp add: strict_suffix_def suffix_def) 
  define f where "f  λ(v::'a val, vs). Stars (v # vs)"
  define S1 where "S1  s'  Prefixes s. LV r s'"
  define S2 where "S2  s2  SSuffixes s. Stars -` (LV (Star r) s2)"
  have "finite S1" using assms
    unfolding S1_def by (simp_all add: finite_Prefixes)
  moreover 
  with IH have "finite S2" unfolding S2_def
    by (auto simp add: finite_SSuffixes inj_on_def finite_vimageI)
  ultimately 
  have "finite ({Stars []}  f ` (S1 × S2))" by simp
  moreover 
  have "LV (Star r) s  {Stars []}  f ` (S1 × S2)" 
  unfolding S1_def S2_def f_def
  unfolding LV_def image_def prefix_def strict_suffix_def 
  apply(auto)
  apply(case_tac x)
  apply(auto elim: Prf_elims)
  apply(erule Prf_elims)
  apply(auto)
  apply(case_tac vs)
  apply(auto intro: Prf.intros)  
  apply(rule exI)
  apply(rule conjI)
  apply(rule_tac x="flat a" in exI)
  apply(rule conjI)
  apply(rule_tac x="flats list" in exI)
  apply(simp)
  apply(blast)
  apply(simp add: suffix_def)
  using Prf.intros(6) by blast  
  ultimately
  show "finite (LV (Star r) s)" by (simp add: finite_subset)
qed  

definition
  "Stars_Cons V Vs  {Stars (v # vs) | v vs. v  V  Stars vs  Vs}"

definition
  "Stars_Append Vs1 Vs2  {Stars (vs1 @ vs2) | vs1 vs2. Stars vs1  Vs1  Stars vs2  Vs2}"

fun Stars_Pow :: "('a val) set  nat  ('a val) set"
where  
  "Stars_Pow Vs 0 = {Stars []}"
| "Stars_Pow Vs (Suc n) = Stars_Cons Vs (Stars_Pow Vs n)"
  
lemma finite_Stars_Cons:
  assumes "finite V" "finite Vs"
  shows "finite (Stars_Cons V Vs)"
  using assms  
proof -
  from assms(2) have "finite (Stars -` Vs)"
    by(simp add: finite_vimageI inj_on_def) 
  with assms(1) have "finite (V × (Stars -` Vs))"
    by(simp)
  then have "finite ((λ(v, vs). Stars (v # vs)) ` (V × (Stars -` Vs)))"
    by simp
  moreover have "Stars_Cons V Vs = (λ(v, vs). Stars (v # vs)) ` (V × (Stars -` Vs))"
    unfolding Stars_Cons_def by auto    
  ultimately show "finite (Stars_Cons V Vs)"   
    by simp
qed

lemma finite_Stars_Append:
  assumes "finite Vs1" "finite Vs2"
  shows "finite (Stars_Append Vs1 Vs2)"
  using assms  
proof -
  define UVs1 where "UVs1  Stars -` Vs1"
  define UVs2 where "UVs2  Stars -` Vs2"  
  from assms have "finite UVs1" "finite UVs2"
    unfolding UVs1_def UVs2_def
    by(simp_all add: finite_vimageI inj_on_def) 
  then have "finite ((λ(vs1, vs2). Stars (vs1 @ vs2)) ` (UVs1 × UVs2))"
    by simp
  moreover 
    have "Stars_Append Vs1 Vs2 = (λ(vs1, vs2). Stars (vs1 @ vs2)) ` (UVs1 × UVs2)"
    unfolding Stars_Append_def UVs1_def UVs2_def by auto    
  ultimately show "finite (Stars_Append Vs1 Vs2)"   
    by simp
qed 
 
lemma finite_Stars_Pow:
  assumes "finite Vs"
  shows "finite (Stars_Pow Vs n)"    
by (induct n) (simp_all add: finite_Stars_Cons assms)

lemma LV_NTimes_5:
  "LV (NTimes r n) s  Stars_Append (LV (Star r) s) (in. LV (NTimes r i) [])"
apply(auto simp add: LV_def)
apply(auto elim!: Prf_elims)
  apply(auto simp add: Stars_Append_def)
  apply(rule_tac x="vs1" in exI)
  apply(rule_tac x="vs2" in exI)  
  apply(auto)
    using Prf.intros(6) apply(auto)
      apply(rule_tac x="length vs2" in bexI)
    thm Prf.intros
      apply(subst append.simps(1)[symmetric])
    apply(rule Prf.intros)
      apply(auto)[1]
      apply(auto)[1]
     apply(simp)
    apply(simp)
      done

lemma LV_NTIMES_3:
  shows "LV (NTimes r (Suc n)) [] = 
     (λ(v, vs). Stars (v#vs)) ` (LV r [] × (Stars -` (LV (NTimes r n) [])))"
unfolding LV_def
apply(auto elim!: Prf_elims simp add: image_def)
apply(case_tac vs1)
apply(auto)
apply(case_tac vs2)
apply(auto)
apply(subst append.simps(1)[symmetric])
apply(rule Prf.intros)
apply(auto)
apply(subst append.simps(1)[symmetric])
apply(rule Prf.intros)
apply(auto)
  done 

lemma finite_NTimes_empty:
  assumes "s. finite (LV r s)" 
  shows "finite (LV (NTimes r n) [])"
  using assms
  apply(induct n)
   apply(auto simp add: LV_simps)
  apply(subst LV_NTIMES_3)
  apply(rule finite_imageI)
  apply(rule finite_cartesian_product)
  using assms apply simp 
  apply(rule finite_vimageI)
  apply(simp)
  apply(simp add: inj_on_def)
  done

lemma LV_From_5:
  shows "LV (From r n) s  Stars_Append (LV (Star r) s) (in. LV (From r i) [])"
apply(auto simp add: LV_def)
apply(auto elim!: Prf_elims)
apply(auto simp add: Stars_Append_def)
apply(rule_tac x="vs1" in exI)
apply(rule_tac x="vs2" in exI)  
apply(auto)
    using Prf.intros(6) apply(auto)
      apply(rule_tac x="length vs2" in bexI)
    thm Prf.intros
      apply(subst append.simps(1)[symmetric])
    apply(rule Prf.intros)
      apply(auto)[1]
      apply(auto)[1]
     apply(simp)
     apply(simp)
      apply(rule_tac x="vs" in exI)
    apply(rule_tac x="[]" in exI) 
    apply(auto)
    by (metis Prf.intros(9) append_Nil atMost_iff empty_iff le_imp_less_Suc less_antisym list.set(1) nth_mem zero_le)

lemma LV_FROMNTIMES_3:
  shows "LV (From r (Suc n)) [] = 
    (λ(v,vs). Stars (v#vs)) ` (LV r [] × (Stars -` (LV (From r n) [])))"
unfolding LV_def
apply(auto elim!: Prf_elims simp add: image_def)
apply(case_tac vs1)
apply(auto)
apply(case_tac vs2)
apply(auto)
apply(subst append.simps(1)[symmetric])
apply(rule Prf.intros)
     apply(auto)
  apply (metis le_imp_less_Suc length_greater_0_conv less_antisym list.exhaust list.set_intros(1) not_less_eq zero_le)
  prefer 2
  using nth_mem apply blast
  apply(case_tac vs1)
  apply (smt Groups.add_ac(2) Prf.intros(9) add.right_neutral add_Suc_right append.simps(1) insert_iff length_append list.set(2) list.size(3) list.size(4))
    apply(auto)
done   

lemma LV_From_empty:
 "LV (From r n) [] = Stars_Pow (LV r []) n" 
  apply(induct n)
   apply(simp add: LV_def)    
   apply(auto elim: Prf_elims simp add: image_def)[1]
   prefer 2
    apply(subst append.simps[symmetric])
    apply(rule Prf.intros)
      apply(simp_all)
   apply(erule Prf_elims) 
    apply(case_tac vs1)
     apply(simp)
    apply(simp)
   apply(case_tac x)
    apply(simp_all)
    apply(simp add: LV_FROMNTIMES_3 image_def Stars_Cons_def)
  apply blast
 done   

lemma finite_From_empty:
  assumes "s. finite (LV r s)"
  shows "finite (LV (From r n) s)"
  apply(rule finite_subset)
   apply(rule LV_From_5)
  apply(rule finite_Stars_Append)
    apply(rule LV_STAR_finite)
   apply(rule assms)
  apply(rule finite_UN_I)
   apply(auto)
  by (simp add: assms finite_Stars_Pow LV_From_empty)
    

lemma subseteq_Upto_Star:
  shows "LV (Upto r n) s  LV (Star r) s"
  apply(auto simp add: LV_def)
  by (metis Prf.intros(6) Prf_elims(8))


lemma LV_finite:
  shows "finite (LV r s)"
proof(induct r arbitrary: s)
  case (Zero s) 
  show "finite (LV Zero s)" by (simp add: LV_simps)
next
  case (One s)
  show "finite (LV One s)" by (simp add: LV_simps)
next
  case (Atom c s)
  show "finite (LV (Atom c) s)" by (simp add: LV_simps)
next 
  case (Plus r1 r2 s)
  then show "finite (LV (Plus r1 r2) s)" by (simp add: LV_simps)
next 
  case (Times r1 r2 s)
  define f where "f  λ(v1::'a val, v2). Seq v1 v2"
  define S1 where "S1  s'  Prefixes s. LV r1 s'"
  define S2 where "S2  s'  Suffixes s. LV r2 s'"
  have IHs: "s. finite (LV r1 s)" "s. finite (LV r2 s)" by fact+
  then have "finite S1" "finite S2" unfolding S1_def S2_def
    by (simp_all add: finite_Prefixes finite_Suffixes)
  moreover
  have "LV (Times r1 r2) s  f ` (S1 × S2)"
    unfolding f_def S1_def S2_def 
    unfolding LV_def image_def prefix_def suffix_def
    apply (auto elim!: Prf_elims)
    by (metis (mono_tags, lifting) mem_Collect_eq)  
  ultimately 
  show "finite (LV (Times r1 r2) s)"
    by (simp add: finite_subset)
next
  case (Star r s)
  then show "finite (LV (Star r) s)" by (simp add: LV_STAR_finite)
next
  case (NTimes r n s)
  have "s. finite (LV r s)" by fact
  then have "finite (Stars_Append (LV (Star r) s) (in. LV (NTimes r i) []))" 
    apply(rule_tac finite_Stars_Append)
     apply (simp add: LV_STAR_finite)
    using finite_NTimes_empty by blast
  then show "finite (LV (NTimes r n) s)"
    by (metis LV_NTimes_5 finite_subset)
next
  case (Upto r n s)
  then have "finite (LV (Star r) s)" by (simp add: LV_STAR_finite)
  moreover
  have "LV (Upto r n) s  LV (Star r) s"
    by (meson subseteq_Upto_Star) 
  ultimately show "finite (LV (Upto r n) s)"
    using rev_finite_subset by blast 
next 
  case (From r n)
  then show "finite (LV (From r n) s)"
    by (simp add: finite_From_empty)
next 
  case (Rec l r)
  have "s. finite (LV r s)" by fact
  then show "finite (LV (Rec l r) s)"
    by(simp add: LV_simps)
next
  case (Charset cs s)
  show "finite (LV (Charset cs) s)" by (simp add: LV_simps)
qed



text ‹
  Our POSIX values are lexical values.
›


lemma Posix_LV:
  assumes "s  r  v"
  shows "v  LV r s"
  using assms unfolding LV_def
  apply(induct rule: Posix.induct)
  using Prf.intros(4) flat.simps(1) apply blast
  apply (simp add: Prf.intros(5))
  apply (simp add: Prf.intros(2))
  apply (simp add: Prf.intros(3))
  apply (simp add: Prf.intros(1))
  apply (smt (verit, best) CollectI Posix1(2) Posix1a Posix_Star1)
  apply (simp add: Prf.intros(6))
  apply (smt (verit, best) Posix1(2) Posix1a Posix_NTimes1 mem_Collect_eq)
  using Posix1a Posix_NTimes2 apply fastforce
  apply (smt (verit, ccfv_threshold) Posix1(2) Posix1a Posix_Upto1 mem_Collect_eq)
  using Posix1a Posix_Upto2 apply fastforce
  using Posix1a Posix_From2 apply fastforce
  apply (smt (verit, best) Posix1(2) Posix1a Posix_From1 mem_Collect_eq)
  apply (smt (verit, best) Posix1a Posix_From3 flat.simps(7) mem_Collect_eq)
  apply(simp add: Prf.intros(11))
  by (simp add: Prf.intros(12))
  

lemma Posix_Prf:
  assumes "s  r  v"
  shows " v : r"
  using assms Posix_LV LV_def
  by blast

end