Theory Regex_Proof_System

(*<*)
theory Regex_Proof_System
imports Regex
begin
(*>*)

context begin

qualified inductive
  SAT :: "(nat  'a  bool)  nat  nat  'a Regex.regex  bool"
  for sat where
  STest: "i = j  sat i x  SAT sat i j (Regex.Test x)"
| SSkip: "j = i + n  SAT sat i j (Regex.Skip n)"
| SPlusL: "SAT sat i j r  SAT sat i j (Regex.Plus r s)"
| SPlusR: "SAT sat i j s  SAT sat i j (Regex.Plus r s)"
| STimes: "SAT sat i k r  SAT sat k j s  SAT sat i j (Regex.Times r s)"
| SStar_eps: "i = j  SAT sat i j (Regex.Star r)"
| SStar: "i < j  (zs. xs = i # zs @ [j]) 
    k  {0 ..< length xs - 1}. xs ! k < xs ! (Suc k) 
    k  {0 ..< length xs - 1}. SAT sat (xs ! k) (xs ! (Suc k)) r 
    SAT sat i j (Regex.Star r)"

lemma SAT_mono[mono]:
  assumes "X  Y"
  shows "SAT X  SAT Y"
  unfolding le_fun_def le_bool_def
proof safe
  fix i j r
  assume "SAT X i j r"
  then show "SAT Y i j r"
    by (induct i j r rule: SAT.induct) (use assms in auto 0 3 intro: SAT.intros)
qed

abbreviation "rm S  {(i, j)  S. i < j}"

qualified inductive
  VIO :: "(nat  'a  bool)  nat  nat  'a Regex.regex  bool"
  for vio where
  VSkip: "j  i + n  VIO vio i j (Regex.Skip n)"
| VTest: "i = j  vio i x  VIO vio i j (Regex.Test x)"
| VTest_neq: "i  j  VIO vio i j (Regex.Test x)"
| VPlus: "VIO vio i j r  VIO vio i j s  VIO vio i j (Regex.Plus r s)"
| VTimes: "k  {i .. j}. VIO vio i k r  VIO vio k j s  VIO vio i j (Regex.Times r s)"
| VStar: "i < j  i  S  j  T  S  T = {i .. j}  S  T = {} 
    (s, t)  rm (S × T). VIO vio s t r  VIO vio i j (Regex.Star r)"
| VStar_gt: "i > j  VIO vio i j (Regex.Star r)"

lemma VIO_mono[mono]:
  assumes "X  Y"
  shows "VIO X  VIO Y"
  unfolding le_fun_def le_bool_def
proof safe
  fix i j r
  assume "VIO X i j r"
  then show "VIO Y i j r"
    by (induct i j r rule: VIO.induct) (use assms in auto 5 3 intro: VIO.intros)
qed

inductive chain :: "('a  'a  bool)  'a list  bool" for R :: "'a  'a  bool" where
	chain_singleton: "chain R [x]"
| chain_cons: "chain R (y # xs)  R x y  chain R (x # y # xs)"

lemma
  chain_Nil[simp]: "¬ chain R []" and
  chain_not_Nil: "chain R xs  xs  []"
  by (auto elim: chain.cases)

lemma chain_rtranclp: "chain R xs  R** (hd xs) (last xs)"
  by (induct xs rule: chain.induct) auto

lemma chain_append:
  assumes "chain R xs" "chain R ys" "R (last xs) (hd ys)"
  shows "chain R (xs @ ys)"
  using assms
proof (induct xs arbitrary: ys rule: chain.induct)
  case (chain_singleton x)
  then show ?case by (cases ys) (auto intro: chain.intros)
qed (auto intro: chain.intros)

lemma tranclp_imp_exists_finite_chain_list:
  "R++ x y  xs. chain R (x # xs @ [y])"
proof (induct rule: tranclp.induct)
  case (r_into_trancl x y)
  then have "chain R (x # [] @ [y])"
    by (auto intro: chain.intros)
  then show ?case
    by blast
next
  case (trancl_into_trancl x y z)
  note rstar_xy = this(1) and ih = this(2) and r_yz = this(3)
  obtain xs where xs: "chain R (x # xs @ [y])" using ih by blast
  define ys where "ys = xs @ [y]"
  have "chain R (x # ys @ [z])"
    unfolding ys_def using r_yz chain_append[OF xs chain_singleton, of z] by auto
  then show ?case by blast
qed

lemma chain_pairwise:
  "chain R xs  Suc i < length xs  R (xs ! i) (xs ! Suc i)"
  by (induct xs arbitrary: i rule: chain.induct)
    (force simp: nth_Cons' not_le Suc_less_eq2 elim: chain.cases)+

lemma chain_sorted_remdups:
  "chain R xs  (x y. R x y  x  y)  sorted xs  chain R (remdups xs)"
proof (induct xs rule: chain.induct)
  case (chain_cons y xs x)
  then show ?case
    using sorted_remdups[of xs] set_remdups[of xs] eq_iff[of y "hd (remdups xs)"]
    by (cases "remdups xs"; cases "y = hd (remdups xs)")
      (auto intro!: chain.intros intro: order_trans elim: chain.cases)
qed (auto intro: chain.intros)

lemma sorted_remdups: "sorted xs  sorted_wrt (<) (remdups xs)"
  by (induct xs) (auto dest: le_neq_trans)

lemma remdups_sorted_start_end:
  "sorted (i # xs @ [j])  i  j 
  remdups (i # xs @ [j]) = i # remdups (removeAll j (removeAll i xs)) @ [j]"
  by (induct xs) auto

lemma tranclp_to_list:
  fixes R :: "'a :: linorder  'a  bool"
  assumes "R++ i j" "i  j" "x y. R x y  x  y"
  obtains xs zs where "xs = i # zs @ [j]"
    "k  {0 ..< length xs - 1}. xs ! k < xs ! (Suc k)  R (xs ! k) (xs ! (Suc k))"
proof atomize_elim
  from R++ i j obtain zs where "chain R (i # zs @ [j])"
    using tranclp_imp_exists_finite_chain_list by fast
  then have zs: "sorted (i # zs @ [j])" "chain R (remdups (i # zs @ [j]))"
    using chain_sorted_remdups assms(3) by blast+
  then have sorted_wrt: "sorted_wrt (<) (remdups (i # zs @ [j]))"
    using sorted_remdups by blast
  let ?zs = "remdups (removeAll j (removeAll i zs))"
  from zs sorted_wrt have "chain R (i # ?zs @ [j])" "sorted_wrt (<) (i # ?zs @ [j])"
    using remdups_sorted_start_end[of i zs j] assms(2) by auto
  then show "xs zs. xs = i # zs @ [j] 
    (k{0..<length xs - 1}. xs ! k < xs ! Suc k  R (xs ! k) (xs ! Suc k))"
    by (subst ex_comm, unfold simp_thms, intro exI[of _ ?zs])
      (auto 0 3 dest: chain_pairwise simp del: remdups.simps
      simp: sorted_wrt_iff_nth_less)
qed


abbreviation match_rel where
  "match_rel test r xs k  (xs ! k < xs ! (Suc k)  Regex.match test r (xs ! k) (xs ! (Suc k)))"

lemma list_to_chain:
  "xs  []  k  {0 ..< length xs - 1}. R (xs ! k) (xs ! Suc k)  chain R xs"
proof (induct xs)
  case (Cons a xs)
  then show ?case
  proof (cases xs)
    case tail: (Cons b ys)
    with Cons(2,3) show ?thesis
      by (force intro!: chain.intros Cons(1)[unfolded tail])
  qed (auto intro: chain.intros)
qed simp

lemma match_rel_list_to_tranclp:
  "xs zs. xs = i # zs @ [j]  (k  {0 ..< length xs - 1}. match_rel test r xs k)  i  j 
  (Regex.match test r)++ i j"
  using chain_rtranclp[OF list_to_chain, THEN rtranclpD, of "i # _ @ [j]" "Regex.match test r"]
  by fastforce

lemma completeness_SAT: 
  "x  Regex.atms r. i. test i x  sat i x  Regex.match test r i j  SAT sat i j r"
proof (induct r arbitrary: i j)
  case (Skip x)
  then show ?case
    by (auto intro: SAT.SSkip)
next
  case (Test x)
  then show ?case
    by (auto intro: SAT.STest)
next
  case (Plus r1 r2)
  then show ?case
    by (auto intro: SAT.SPlusL SPlusR)
next
  case (Times r1 r2)
  then obtain k where k_def: "k  {i .. j}  SAT sat i k r1  SAT sat k j r2"
    using match_le by fastforce
  then show ?case by (auto intro: SAT.STimes)
next
  case (Star r)
  then have "i = j  (i  j  (Regex.match test r)++ i j)"
    using rtranclpD[of "Regex.match test r" i j] tranclpD[of "Regex.match test r" i j]
    by auto
  moreover
  {
    assume i_eq_j: "i = j"
    then have "SAT sat i j (Regex.Star r)" by (auto intro: SAT.SStar_eps)
  }
  moreover
  {
    assume i_neq_j: "i  j" and tranclp_ij: "(Regex.match test r)++ i j"
    then have i_less: "i < j" using Star
      by (auto simp add: le_neq_implies_less match_rtranclp_le)
    then obtain xs and zs where xs_def: "xs = i # zs @ [j]  (k  {0 ..< length xs - 1}. xs ! k < xs ! (Suc k)  Regex.match test r (xs ! k) (xs ! (Suc k)))"
      using tranclp_to_list[OF tranclp_ij i_neq_j match_le[of test r]] by auto
    then have "SAT sat i j (Regex.Star r)" using i_less Star
      by (auto intro: SAT.SStar)
  }
  ultimately show ?case by auto
qed

lemma completeness_VIO: 
  "x  Regex.atms r. i. ¬ test i x  vio i x  i  j  ¬ Regex.match test r i j  VIO vio i j r"
proof (induct r arbitrary: i j)
  case (Skip x)
  then show ?case
    by (auto intro: VIO.VSkip)
next
  case (Test x)
  then show ?case
    by (auto intro: VIO.VTest VIO.VTest_neq)
next
  case (Plus r1 r2)
  then show ?case
    by (auto intro: VIO.VPlus)
next
  case (Times r1 r2)
  then have "k  {i .. j}. VIO vio i k r1  VIO vio k j r2"
    by fastforce
  then show ?case
    by (auto intro: VIO.VTimes)
next
  case (Star r)
  define V where V_def: "V = {i .. j}"
  define S where S_def: "S = {k  V. (Regex.match test r)** i k}  {i}"
  define T where T_def: "T = V - S"
  from S_def V_def have j_notin_S: "j  S" using Star
    by auto
  from S_def have i_in_S: "i  S"
    by auto
  then have j_in_T: "j  T" using j_notin_S V_def T_def Star(3)
    by auto    
  from Star have nmatch_ij: "¬ (Regex.match test r)** i j"
    by auto
  from S_def T_def V_def Star(3) have union_ST: "S  T = {i .. j}"
    by auto
  from S_def T_def V_def Star(4) have inter_ST: "S  T = {}"
    by auto
  with i_in_S j_in_T Star(3) have i_less_j: "i < j"
    using le_eq_less_or_eq by blast
  {
    assume not_viost: "¬ ((s,t)  rm (S × T). VIO vio s t r)"
    then obtain s and t where st_def: "(s, t)  rm (S × T)  ¬ VIO vio s t r"
      by auto
    then have "Regex.match test r s t" using Star
      by auto
    then have "(Regex.match test r)** i t" using st_def S_def
      by auto
    then have False using T_def st_def S_def
      by auto
  }
  then have no_path: "(s,t)  rm (S × T). VIO vio s t r"
    by auto
  then show ?case
    by (auto intro: VIO.VStar[OF i_less_j i_in_S j_in_T union_ST inter_ST no_path])
qed

lemma soundness_SAT:
  "x  Regex.atms r. i. sat i x  test i x  SAT sat i j r  Regex.match test r i j"
proof(induct r arbitrary: i j)
  case (Skip x)
  then show ?case using SAT.simps[of sat i j "Regex.Skip x"]
    by auto
next
  case (Test x)
  then show ?case using SAT.simps[of sat i j "Regex.Test x"]
    by auto
next
  case (Plus r1 r2)
  then show ?case using SAT.simps[of sat i j "Regex.Plus r1 r2"]
    by auto
next
  case (Times r1 r2)
  then show ?case using SAT.simps[of sat i j "Regex.Times r1 r2"]
    by fastforce
next
  case (Star r)
  then show ?case
  proof(cases "i = j")
    case True
    then show ?thesis
      by auto
  next
    case False
    then obtain xs and zs where xs_form: "xs = i # zs @ [j]" and
      xs_props: "k  {0 ..< length xs - 1}. xs ! k < xs ! (Suc k)  SAT sat (xs ! k) (xs ! (Suc k)) r"
      using Star(3) SAT.simps[of sat i j "Regex.Star r"]
      by blast
    then have kmatch: "k  {0 ..< length xs - 1}. Regex.match test r (xs ! k) (xs ! Suc k)"
      using Star
      by auto
    then have ex_lists: "xs zs. xs = i # zs @ [j] 
      (k  {0 ..< length xs - 1}. xs ! k < xs ! (Suc k)  Regex.match test r (xs ! k) (xs ! (Suc k)))"
      using xs_form xs_props by auto
    then have "(Regex.match test r)++ i j"
      using match_rel_list_to_tranclp[OF ex_lists False] by auto
    then show ?thesis
      by auto
  qed
qed

lemma soundness_VIO:
"x  Regex.atms r. i. vio i x  ¬ test i x  i  j  VIO vio i j r  ¬ Regex.match test r i j"
proof(induct r arbitrary: i j)
  case (Skip x)
  then show ?case using VIO.simps[of vio i j "Regex.Skip x"]
    by auto
next
  case (Test x)
  then show ?case using VIO.simps[of vio i j "Regex.Test x"]
    by auto
next
  case (Plus r1 r2)
  then show ?case using VIO.simps[of vio i j "Regex.Plus r1 r2"]
    by auto
next
  case (Times r1 r2)
  then have kvio: "k  {i .. j}. VIO vio i k r1  VIO vio k j r2"
    using VIO.simps[of vio i j "Regex.Times r1 r2"]
    by auto
  have "k. Regex.match test r i k  Regex.match test r k j  k  {i .. j}"
    using match_le
    by auto
  then show ?case using Times kvio match_le[of test]
    unfolding Ball_def atLeastAtMost_iff match.simps regex.simps relcompp_apply
    by (metis Un_iff)
next
  case (Star r)
  then obtain S and T where S_def: "i  S" and T_def: "j  T" and
    ST_props: "S  T = {i .. j}  S  T = {}" and
    st_vio: "(s,t)  rm (S × T). VIO vio s t r"
    using Star(4) VIO.simps[of vio i j "Regex.Star r"]
    by auto
  then have nmatch_st: "(s,t)  rm (S × T). ¬ Regex.match test r s t"
    using Star
    by auto
  from S_def T_def ST_props have i_neq_j: "i  j"
    by auto
  {
    assume rtranclp_ij: "(Regex.match test r)** i j"
    then have tranclp_ij: "(Regex.match test r)++ i j"
      using rtranclpD[of "Regex.match test r" i j] i_neq_j
      by auto

    obtain xs and zs where xs_def: "xs = i # zs @ [j]" and
      xs_prop: "k  {0 ..< length xs - 1}.  match_rel test r xs k"
      using tranclp_to_list[OF tranclp_ij i_neq_j match_le[of test r]]
      by auto

    with S_def T_def ST_props have "k  {0 ..< length xs - 1}. (xs ! k)  S  (xs ! (Suc k))  T"
    proof (induction zs arbitrary: S T i j xs)
      case Nil
      then show ?case using S_def T_def xs_def
        by auto
    next
      case (Cons a zs')
      from Cons(2-6) have match: "Regex.match test r i a"
        by force
      show ?case
      proof (cases "a  T")
        case True
        then have "xs ! 0  S  xs ! Suc 0  T" using S_def Cons
          by (auto simp: xs_def)
        then show ?thesis using S_def Cons(1)[of _ _ _ _ xs] Cons(2-5)
          by force
      next
        case False
        from Cons(5,6) have "chain (<) (i # (a # zs') @ [j])"
          by (intro list_to_chain) auto
        then have "sorted (i # (a # zs') @ [j])"
          using chain_sorted_remdups[of "(<)" "i # (a # zs') @ [j]"]
          by auto
        then have "a  {i .. j}"
          by auto
        with Cons(2-6) False have "k{0..<length (tl xs) - 1}. tl xs ! k  {i  S. a  i}  tl xs ! Suc k  {i  T. a  i}"
          by (intro Cons(1)[of a _ j]) (auto dest: bspec[of _ _ "Suc _"])
        with Cons show ?thesis
          by (auto intro: bexI[of _ "Suc _"])
      qed
    qed
    then have False using nmatch_st xs_prop
      by auto
  }
  then show ?case
    by auto
qed

end

(*<*)
end
(*>*)